void MaskContentCommand::onExecute(Context* context) { Document* document; { ContextWriter writer(context); document = writer.document(); Cel* cel = writer.cel(); // Get current cel (can be NULL) if (!cel) return; gfx::Color color; if (writer.layer()->isBackground()) { ColorPicker picker; picker.pickColor(*writer.site(), gfx::PointF(0.0, 0.0), current_editor->projection(), ColorPicker::FromComposition); color = color_utils::color_for_layer(picker.color(), writer.layer()); } else color = cel->image()->maskColor(); Mask newMask; gfx::Rect imgBounds = cel->image()->bounds(); if (algorithm::shrink_bounds(cel->image(), imgBounds, color)) { newMask.replace(imgBounds.offset(cel->bounds().origin())); } else { newMask.replace(cel->bounds()); } Transaction transaction(writer.context(), "Select Content", DoesntModifyDocument); transaction.execute(new cmd::SetMask(document, &newMask)); transaction.commit(); document->resetTransformation(); document->generateMaskBoundaries(); } // Select marquee tool if (tools::Tool* tool = App::instance()->toolBox() ->getToolById(tools::WellKnownTools::RectangularMarquee)) { ToolBar::instance()->selectTool(tool); } update_screen_for_document(document); }
void ContextFlags::update(Context* context) { Site site = context->activeSite(); Document* document = static_cast<Document*>(site.document()); m_flags = 0; if (document) { m_flags |= HasActiveDocument; if (document->lock(Document::ReadLock, 0)) { m_flags |= ActiveDocumentIsReadable; if (document->isMaskVisible()) m_flags |= HasVisibleMask; Sprite* sprite = site.sprite(); if (sprite) { m_flags |= HasActiveSprite; if (sprite->backgroundLayer()) m_flags |= HasBackgroundLayer; Layer* layer = site.layer(); if (layer) { m_flags |= HasActiveLayer; if (layer->isBackground()) m_flags |= ActiveLayerIsBackground; if (layer->isVisible()) m_flags |= ActiveLayerIsVisible; if (layer->isEditable()) m_flags |= ActiveLayerIsEditable; if (layer->isImage()) { m_flags |= ActiveLayerIsImage; Cel* cel = layer->cel(site.frame()); if (cel) { m_flags |= HasActiveCel; if (cel->image()) m_flags |= HasActiveImage; } } } } if (document->lockToWrite(0)) m_flags |= ActiveDocumentIsWritable; document->unlock(); } } }
bool expect_cel(int expected_layer, int expected_frame, int layer, frame_t frame) { color_t expected_color = white; Cel* cel = sprite->indexToLayer(LayerIndex(layer))->cel(frame); if (!cel) return false; color_t color = get_pixel( cel->image(), expected_layer, expected_frame); EXPECT_EQ(expected_color, color); return (expected_color == color); }
void write_layer(std::ostream& os, LayerSubObjectsSerializer* subObjects, Layer* layer) { std::string name = layer->name(); write16(os, name.size()); // Name length if (!name.empty()) os.write(name.c_str(), name.size()); // Name write32(os, layer->getFlags()); // Flags write16(os, static_cast<int>(layer->type())); // Type switch (layer->type()) { case ObjectType::LayerImage: { // Number of cels write16(os, static_cast<LayerImage*>(layer)->getCelsCount()); CelIterator it = static_cast<LayerImage*>(layer)->getCelBegin(); CelIterator end = static_cast<LayerImage*>(layer)->getCelEnd(); for (; it != end; ++it) { Cel* cel = *it; subObjects->write_cel(os, cel); Image* image = cel->image(); ASSERT(image != NULL); subObjects->write_image(os, image); } break; } case ObjectType::LayerFolder: { LayerIterator it = static_cast<LayerFolder*>(layer)->getLayerBegin(); LayerIterator end = static_cast<LayerFolder*>(layer)->getLayerEnd(); // Number of sub-layers write16(os, static_cast<LayerFolder*>(layer)->getLayersCount()); for (; it != end; ++it) subObjects->write_layer(os, *it); break; } } }
void LayerImage::destroyAllCels() { CelIterator it = getCelBegin(); CelIterator end = getCelEnd(); for (; it != end; ++it) { Cel* cel = *it; Image* image = cel->image(); ASSERT(image != NULL); sprite()->stock()->removeImage(image); delete image; delete cel; } m_cels.clear(); }
void Sprite::pickCels(int x, int y, frame_t frame, int opacityThreshold, CelList& cels) const { std::vector<Layer*> layers; getLayersList(layers); for (int i=(int)layers.size()-1; i>=0; --i) { Layer* layer = layers[i]; if (!layer->isImage() || !layer->isVisible()) continue; Cel* cel = layer->cel(frame); if (!cel) continue; Image* image = cel->image(); if (!image) continue; if (!cel->bounds().contains(gfx::Point(x, y))) continue; color_t color = get_pixel(image, x - cel->x(), y - cel->y()); bool isOpaque = true; switch (image->pixelFormat()) { case IMAGE_RGB: isOpaque = (rgba_geta(color) >= opacityThreshold); break; case IMAGE_INDEXED: isOpaque = (color != image->maskColor()); break; case IMAGE_GRAYSCALE: isOpaque = (graya_geta(color) >= opacityThreshold); break; } if (!isOpaque) continue; cels.push_back(cel); } fflush(stdout); }
void ShiftMaskedCel::shift(int dx, int dy) { Cel* cel = this->cel(); Image* image = cel->image(); Mask* mask = static_cast<app::Document*>(cel->document())->mask(); ASSERT(mask->bitmap()); if (!mask->bitmap()) return; int x = cel->x(); int y = cel->y(); mask->offsetOrigin(-x, -y); doc::algorithm::shift_image_with_mask(image, mask, dx, dy); mask->offsetOrigin(x, y); image->incrementVersion(); }
void PatchCel::onExecute() { Cel* cel = this->cel(); const gfx::Rect newBounds = cel->bounds() | gfx::Rect(m_region.bounds()).offset(m_pos); if (cel->bounds() != newBounds) { executeAndAdd(new CropCel(cel, newBounds)); } executeAndAdd( new CopyRegion(cel->image(), m_patch, m_region, m_pos - cel->position())); executeAndAdd(new TrimCel(cel)); m_patch = nullptr; }
void CopyCel::onExecute() { LayerImage* srcLayer = static_cast<LayerImage*>(m_srcLayer.layer()); LayerImage* dstLayer = static_cast<LayerImage*>(m_dstLayer.layer()); ASSERT(srcLayer); ASSERT(dstLayer); Sprite* srcSprite = srcLayer->sprite(); Sprite* dstSprite = dstLayer->sprite(); ASSERT(srcSprite); ASSERT(dstSprite); ASSERT(m_srcFrame >= 0 && m_srcFrame < srcSprite->totalFrames()); ASSERT(m_dstFrame >= 0); (void)srcSprite; // To avoid unused variable warning on Release mode Cel* srcCel = srcLayer->cel(m_srcFrame); Cel* dstCel = dstLayer->cel(m_dstFrame); // Clear destination cel if it does exist. It'll be overriden by the // copy of srcCel. if (dstCel) { if (dstCel->links()) executeAndAdd(new cmd::UnlinkCel(dstCel)); executeAndAdd(new cmd::ClearCel(dstCel)); } // Add empty frames until newFrame while (dstSprite->totalFrames() <= m_dstFrame) executeAndAdd(new cmd::AddFrame(dstSprite, dstSprite->totalFrames())); Image* srcImage = (srcCel ? srcCel->image(): NULL); ImageRef dstImage; dstCel = dstLayer->cel(m_dstFrame); if (dstCel) dstImage = dstCel->imageRef(); bool createLink = (srcLayer == dstLayer && dstLayer->isContinuous()); // For background layer if (dstLayer->isBackground()) { ASSERT(dstCel); ASSERT(dstImage); if (!dstCel || !dstImage || !srcCel || !srcImage) return; if (createLink) { executeAndAdd(new cmd::SetCelData(dstCel, srcCel->dataRef())); } else { BlendMode blend = (srcLayer->isBackground() ? BlendMode::SRC: BlendMode::NORMAL); ImageRef tmp(Image::createCopy(dstImage.get())); render::composite_image(tmp.get(), srcImage, srcCel->x(), srcCel->y(), 255, blend); executeAndAdd(new cmd::CopyRect(dstImage.get(), tmp.get(), gfx::Clip(tmp->bounds()))); } } // For transparent layers else { if (dstCel) executeAndAdd(new cmd::RemoveCel(dstCel)); if (srcCel) { if (createLink) dstCel = Cel::createLink(srcCel); else dstCel = Cel::createCopy(srcCel); dstCel->setFrame(m_dstFrame); executeAndAdd(new cmd::AddCel(dstLayer, dstCel)); } } }
/** * [working thread] */ virtual void onJob() { UndoTransaction undoTransaction(m_writer.context(), "Sprite Size"); DocumentApi api = m_writer.document()->getApi(); // Get all sprite cels CelList cels; m_sprite->getCels(cels); // For each cel... int progress = 0; for (CelIterator it = cels.begin(); it != cels.end(); ++it, ++progress) { Cel* cel = *it; // Change its location api.setCelPosition(m_sprite, cel, scale_x(cel->x()), scale_y(cel->y())); // Get cel's image Image* image = cel->image(); if (!image) continue; // Resize the image int w = scale_x(image->width()); int h = scale_y(image->height()); Image* new_image = Image::create(image->pixelFormat(), MAX(1, w), MAX(1, h)); doc::algorithm::fixup_image_transparent_colors(image); doc::algorithm::resize_image(image, new_image, m_resize_method, m_sprite->getPalette(cel->frame()), m_sprite->getRgbMap(cel->frame())); api.replaceStockImage(m_sprite, cel->imageIndex(), new_image); jobProgress((float)progress / cels.size()); // cancel all the operation? if (isCanceled()) return; // UndoTransaction destructor will undo all operations } // Resize mask if (m_document->isMaskVisible()) { base::UniquePtr<Image> old_bitmap (crop_image(m_document->mask()->bitmap(), -1, -1, m_document->mask()->bitmap()->width()+2, m_document->mask()->bitmap()->height()+2, 0)); int w = scale_x(old_bitmap->width()); int h = scale_y(old_bitmap->height()); base::UniquePtr<Mask> new_mask(new Mask); new_mask->replace(scale_x(m_document->mask()->bounds().x-1), scale_y(m_document->mask()->bounds().y-1), MAX(1, w), MAX(1, h)); algorithm::resize_image(old_bitmap, new_mask->bitmap(), m_resize_method, m_sprite->getPalette(FrameNumber(0)), // Ignored m_sprite->getRgbMap(FrameNumber(0))); // Ignored // Reshrink new_mask->intersect(new_mask->bounds()); // Copy new mask api.copyToCurrentMask(new_mask); // Regenerate mask m_document->resetTransformation(); m_document->generateMaskBoundaries(); } // resize sprite api.setSpriteSize(m_sprite, m_new_width, m_new_height); // commit changes undoTransaction.commit(); }
void write_layer(std::ostream& os, const Layer* layer) { write32(os, layer->id()); write_string(os, layer->name()); write32(os, static_cast<int>(layer->flags())); // Flags write16(os, static_cast<int>(layer->type())); // Type switch (layer->type()) { case ObjectType::LayerImage: { CelConstIterator it, begin = static_cast<const LayerImage*>(layer)->getCelBegin(); CelConstIterator end = static_cast<const LayerImage*>(layer)->getCelEnd(); // Images int images = 0; int celdatas = 0; for (it=begin; it != end; ++it) { Cel* cel = *it; if (!cel->link()) { ++images; ++celdatas; } } write16(os, images); for (it=begin; it != end; ++it) { Cel* cel = *it; if (!cel->link()) write_image(os, cel->image()); } write16(os, celdatas); for (it=begin; it != end; ++it) { Cel* cel = *it; if (!cel->link()) write_celdata(os, cel->dataRef().get()); } // Cels write16(os, static_cast<const LayerImage*>(layer)->getCelsCount()); for (it=begin; it != end; ++it) { const Cel* cel = *it; write_cel(os, cel); } break; } case ObjectType::LayerFolder: { LayerConstIterator it = static_cast<const LayerFolder*>(layer)->getLayerBegin(); LayerConstIterator end = static_cast<const LayerFolder*>(layer)->getLayerEnd(); // Number of sub-layers write16(os, static_cast<const LayerFolder*>(layer)->getLayersCount()); for (; it != end; ++it) write_layer(os, *it); break; } } }
bool FliFormat::onLoad(FileOp* fop) { // Open the file to read in binary mode FileHandle handle(open_file_with_exception(fop->filename, "rb")); FILE* f = handle.get(); flic::StdioFileInterface finterface(f); flic::Decoder decoder(&finterface); flic::Header header; if (!decoder.readHeader(header)) { fop_error(fop, "The file doesn't have a FLIC header\n"); return false; } // Size by frame int w = header.width; int h = header.height; // Create a temporal bitmap ImageRef bmp(Image::create(IMAGE_INDEXED, w, h)); Palette pal(0, 1); Cel* prevCel = nullptr; // Create the sprite Sprite* sprite = new Sprite(IMAGE_INDEXED, w, h, 256); LayerImage* layer = new LayerImage(sprite); sprite->folder()->addLayer(layer); layer->configureAsBackground(); // Set frames and speed sprite->setTotalFrames(frame_t(header.frames)); sprite->setDurationForAllFrames(header.speed); flic::Frame fliFrame; flic::Colormap oldFliColormap; fliFrame.pixels = bmp->getPixelAddress(0, 0); fliFrame.rowstride = IndexedTraits::getRowStrideBytes(bmp->width()); frame_t frame_out = 0; for (frame_t frame_in=0; frame_in<sprite->totalFrames(); ++frame_in) { // Read the frame if (!decoder.readFrame(fliFrame)) { fop_error(fop, "Error reading frame %d\n", frame_in); continue; } // Palette change bool palChange = false; if (frame_out == 0 || oldFliColormap != fliFrame.colormap) { oldFliColormap = fliFrame.colormap; pal.resize(fliFrame.colormap.size()); for (int c=0; c<int(fliFrame.colormap.size()); c++) { pal.setEntry(c, rgba(fliFrame.colormap[c].r, fliFrame.colormap[c].g, fliFrame.colormap[c].b, 255)); } pal.setFrame(frame_out); sprite->setPalette(&pal, true); palChange = true; } // First frame, or the frame changes if (!prevCel || (count_diff_between_images(prevCel->image(), bmp.get()))) { // Add the new frame ImageRef image(Image::createCopy(bmp.get())); Cel* cel = new Cel(frame_out, image); layer->addCel(cel); prevCel = cel; ++frame_out; } else if (palChange) { Cel* cel = Cel::createLink(prevCel); cel->setFrame(frame_out); layer->addCel(cel); ++frame_out; } // The palette and the image don't change: add duration to the last added frame else { sprite->setFrameDuration( frame_out-1, sprite->frameDuration(frame_out-1) + header.speed); } if (header.frames > 0) fop_progress(fop, (float)(frame_in+1) / (float)(header.frames)); if (fop_is_stop(fop)) break; if (fop->oneframe) break; } if (frame_out > 0) sprite->setTotalFrames(frame_out); fop->createDocument(sprite); return true; }