void PixelsMovement::redrawExtraImage() { int t, opacity = static_cast<LayerImage*>(m_layer)->opacity(); Cel* cel = m_site.cel(); if (cel) opacity = MUL_UN8(opacity, cel->opacity(), t); gfx::Rect bounds = m_currentData.transformedBounds(); m_extraCel.reset(new ExtraCel); m_extraCel->create(m_document->sprite(), bounds, m_site.frame(), opacity); m_extraCel->setType(render::ExtraType::PATCH); m_extraCel->setBlendMode(static_cast<LayerImage*>(m_layer)->blendMode()); m_document->setExtraCel(m_extraCel); // Draw the transformed pixels in the extra-cel which is the chunk // of pixels that the user is moving. drawImage(m_extraCel->image(), bounds.origin(), true); }
void MergeDownLayerCommand::onExecute(Context* context) { ContextWriter writer(context); Document* document(writer.document()); Sprite* sprite(writer.sprite()); Transaction transaction(writer.context(), "Merge Down Layer", ModifyDocument); LayerImage* src_layer = static_cast<LayerImage*>(writer.layer()); Layer* dst_layer = src_layer->getPrevious(); for (frame_t frpos = 0; frpos<sprite->totalFrames(); ++frpos) { // Get frames Cel* src_cel = src_layer->cel(frpos); Cel* dst_cel = dst_layer->cel(frpos); // Get images Image* src_image; if (src_cel != NULL) src_image = src_cel->image(); else src_image = NULL; ImageRef dst_image; if (dst_cel) dst_image = dst_cel->imageRef(); // With source image? if (src_image) { int t; int opacity; opacity = MUL_UN8(src_cel->opacity(), src_layer->opacity(), t); // No destination image if (!dst_image) { // Only a transparent layer can have a null cel // Copy this cel to the destination layer... // Creating a copy of the image dst_image.reset(Image::createCopy(src_image)); // Creating a copy of the cell dst_cel = new Cel(frpos, dst_image); dst_cel->setPosition(src_cel->x(), src_cel->y()); dst_cel->setOpacity(opacity); transaction.execute(new cmd::AddCel(dst_layer, dst_cel)); } // With destination else { gfx::Rect bounds; // Merge down in the background layer if (dst_layer->isBackground()) { bounds = sprite->bounds(); } // Merge down in a transparent layer else { bounds = src_cel->bounds().createUnion(dst_cel->bounds()); } doc::color_t bgcolor = app_get_color_to_clear_layer(dst_layer); ImageRef new_image(doc::crop_image( dst_image.get(), bounds.x-dst_cel->x(), bounds.y-dst_cel->y(), bounds.w, bounds.h, bgcolor)); // Merge src_image in new_image render::composite_image( new_image.get(), src_image, sprite->palette(src_cel->frame()), src_cel->x()-bounds.x, src_cel->y()-bounds.y, opacity, src_layer->blendMode()); transaction.execute(new cmd::SetCelPosition(dst_cel, bounds.x, bounds.y)); if (dst_cel->links()) transaction.execute(new cmd::UnlinkCel(dst_cel)); transaction.execute(new cmd::ReplaceImage(sprite, dst_cel->imageRef(), new_image)); } } } document->notifyLayerMergedDown(src_layer, dst_layer); document->getApi(transaction).removeLayer(src_layer); // src_layer is deleted inside removeLayer() transaction.commit(); update_screen_for_document(document); }
doc::Image* render_text(const std::string& fontfile, int fontsize, const std::string& text, doc::color_t color, bool antialias) { base::UniquePtr<doc::Image> image(nullptr); ft::Lib ft; ft::Face face(ft.open(fontfile)); if (face.isValid()) { // Set font size face.setSize(fontsize); face.setAntialias(antialias); // Calculate text size gfx::Rect bounds = ft::calc_text_bounds(face, text); // Render the image and copy it to the clipboard if (!bounds.isEmpty()) { image.reset(doc::Image::create(doc::IMAGE_RGB, bounds.w, bounds.h)); doc::clear_image(image, 0); ft::ForEachGlyph<ft::Face> feg(face); if (feg.initialize(base::utf8_const_iterator(text.begin()), base::utf8_const_iterator(text.end()))) { do { auto glyph = feg.glyph(); if (!glyph) continue; int t, yimg = - bounds.y + int(glyph->y); for (int v=0; v<int(glyph->bitmap->rows); ++v, ++yimg) { const uint8_t* p = glyph->bitmap->buffer + v*glyph->bitmap->pitch; int ximg = - bounds.x + int(glyph->x); int bit = 0; for (int u=0; u<int(glyph->bitmap->width); ++u, ++ximg) { int alpha; if (antialias) { alpha = *(p++); } else { alpha = ((*p) & (1 << (7 - (bit++))) ? 255: 0); if (bit == 8) { bit = 0; ++p; } } int output_alpha = MUL_UN8(doc::rgba_geta(color), alpha, t); if (output_alpha) { doc::color_t output_color = doc::rgba(doc::rgba_getr(color), doc::rgba_getg(color), doc::rgba_getb(color), output_alpha); doc::put_pixel( image, ximg, yimg, doc::rgba_blender_normal( doc::get_pixel(image, ximg, yimg), output_color)); } } } } while (feg.nextChar()); } } else { throw std::runtime_error("There is no text"); } } else { throw std::runtime_error("Error loading font face"); } return (image ? image.release(): nullptr); }