void Sprite::remapImages(FrameNumber frameFrom, FrameNumber frameTo, const std::vector<uint8_t>& mapping) { ASSERT(m_format == IMAGE_INDEXED); ASSERT(mapping.size() == 256); CelList cels; getCels(cels); for (CelIterator it = cels.begin(); it != cels.end(); ++it) { Cel* cel = *it; // Remap this Cel because is inside the specified range if (cel->getFrame() >= frameFrom && cel->getFrame() <= frameTo) { Image* image = getStock()->getImage(cel->getImage()); LockImageBits<IndexedTraits> bits(image); LockImageBits<IndexedTraits>::iterator it = bits.begin(), end = bits.end(); for (; it != end; ++it) *it = mapping[*it]; } } }
void UndoTransaction::removeCel(LayerImage* layer, Cel* cel) { ASSERT(layer); ASSERT(cel); // find if the image that use the cel to remove, is used by // another cels bool used = false; for (int frame=0; frame<m_sprite->getTotalFrames(); ++frame) { Cel* it = layer->getCel(frame); if (it && it != cel && it->getImage() == cel->getImage()) { used = true; break; } } // if the image is only used by this cel, // we can remove the image from the stock if (!used) removeImageFromStock(cel->getImage()); if (isEnabled()) m_undoHistory->pushUndoer(new undoers::RemoveCel(m_undoHistory->getObjects(), layer, cel)); // remove the cel from the layer layer->removeCel(cel); // and here we destroy the cel delete cel; }
void UndoTransaction::pasteImage(const Image* src_image, int x, int y, int opacity) { const Layer* layer = m_sprite->getCurrentLayer(); ASSERT(layer); ASSERT(layer->is_image()); ASSERT(layer->is_readable()); ASSERT(layer->is_writable()); Cel* cel = ((LayerImage*)layer)->getCel(m_sprite->getCurrentFrame()); ASSERT(cel); Image* cel_image = m_sprite->getStock()->getImage(cel->getImage()); Image* cel_image2 = Image::createCopy(cel_image); image_merge(cel_image2, src_image, x-cel->getX(), y-cel->getY(), opacity, BLEND_MODE_NORMAL); replaceStockImage(cel->getImage(), cel_image2); // TODO fix this, improve, avoid replacing the whole image }
void write_layer(std::ostream& os, LayerSubObjectsSerializer* subObjects, Layer* layer) { std::string name = layer->getName(); write16(os, name.size()); // Name length if (!name.empty()) os.write(name.c_str(), name.size()); // Name write32(os, layer->getFlags()); // Flags write16(os, layer->getType()); // Type switch (layer->getType()) { case GFXOBJ_LAYER_IMAGE: { // 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 = layer->getSprite()->getStock()->getImage(cel->getImage()); ASSERT(image != NULL); subObjects->write_image(os, image); } break; } case GFXOBJ_LAYER_FOLDER: { LayerIterator it = static_cast<LayerFolder*>(layer)->get_layer_begin(); LayerIterator end = static_cast<LayerFolder*>(layer)->get_layer_end(); // Number of sub-layers write16(os, static_cast<LayerFolder*>(layer)->get_layers_count()); 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 = getSprite()->getStock()->getImage(cel->getImage()); ASSERT(image != NULL); getSprite()->getStock()->removeImage(image); delete image; delete cel; } m_cels.clear(); }
static void remove_cel(Sprite* sprite, UndoTransaction& undo, LayerImage *layer, Cel *cel) { Image *image; Cel *it; bool used; if (sprite != NULL && layer->isImage() && cel != NULL) { /* find if the image that use the cel to remove, is used by another cels */ used = false; for (FrameNumber frame(0); frame<sprite->getTotalFrames(); ++frame) { it = layer->getCel(frame); if (it != NULL && it != cel && it->getImage() == cel->getImage()) { used = true; break; } } if (!used) { // If the image is only used by this cel, we can remove the // image from the stock. image = sprite->getStock()->getImage(cel->getImage()); if (undo.isEnabled()) undo.pushUndoer(new undoers::RemoveImage(undo.getObjects(), sprite->getStock(), cel->getImage())); sprite->getStock()->removeImage(image); image_free(image); } if (undo.isEnabled()) { undo.pushUndoer(new undoers::RemoveCel(undo.getObjects(), layer, cel)); } // Remove the cel layer->removeCel(cel); delete cel; } }
void DocumentApi::removeCel(LayerImage* layer, Cel* cel) { ASSERT(layer); ASSERT(cel); Sprite* sprite = layer->getSprite(); DocumentEvent ev(m_document); ev.sprite(sprite); ev.layer(layer); ev.cel(cel); m_document->notifyObservers<DocumentEvent&>(&DocumentObserver::onRemoveCel, ev); // find if the image that use the cel to remove, is used by // another cels bool used = false; for (FrameNumber frame(0); frame<sprite->getTotalFrames(); ++frame) { Cel* it = layer->getCel(frame); if (it && it != cel && it->getImage() == cel->getImage()) { used = true; break; } } // if the image is only used by this cel, // we can remove the image from the stock if (!used) removeImageFromStock(sprite, cel->getImage()); DocumentUndo* undo = m_document->getUndo(); if (undo->isEnabled()) m_undoers->pushUndoer(new undoers::RemoveCel(getObjects(), layer, cel)); // remove the cel from the layer layer->removeCel(cel); // and here we destroy the cel delete cel; }
void Sprite::remapImages(FrameNumber frameFrom, FrameNumber frameTo, const std::vector<uint8_t>& mapping) { ASSERT(m_format == IMAGE_INDEXED); ASSERT(mapping.size() == 256); CelList cels; getCels(cels); for (CelIterator it = cels.begin(); it != cels.end(); ++it) { Cel* cel = *it; // Remap this Cel because is inside the specified range if (cel->getFrame() >= frameFrom && cel->getFrame() <= frameTo) { Image* image = getStock()->getImage(cel->getImage()); for (int y=0; y<image->h; ++y) { IndexedTraits::address_t ptr = image_address_fast<IndexedTraits>(image, 0, y); for (int x=0; x<image->w; ++x, ++ptr) *ptr = mapping[*ptr]; } } } }
/** * [working thread] */ virtual void onJob() { UndoTransaction undoTransaction(m_writer.context(), "Rotate Canvas"); DocumentApi api = m_document->getApi(); // get all sprite cels CelList cels; m_sprite->getCels(cels); // for each cel... for (CelIterator it = cels.begin(); it != cels.end(); ++it) { Cel* cel = *it; Image* image = m_sprite->getStock()->getImage(cel->getImage()); // change it location switch (m_angle) { case 180: api.setCelPosition(m_sprite, cel, m_sprite->getWidth() - cel->getX() - image->getWidth(), m_sprite->getHeight() - cel->getY() - image->getHeight()); break; case 90: api.setCelPosition(m_sprite, cel, m_sprite->getHeight() - cel->getY() - image->getHeight(), cel->getX()); break; case -90: api.setCelPosition(m_sprite, cel, cel->getY(), m_sprite->getWidth() - cel->getX() - image->getWidth()); break; } } // for each stock's image for (int i=0; i<m_sprite->getStock()->size(); ++i) { Image* image = m_sprite->getStock()->getImage(i); if (!image) continue; // rotate the image Image* new_image = Image::create(image->getPixelFormat(), m_angle == 180 ? image->getWidth(): image->getHeight(), m_angle == 180 ? image->getHeight(): image->getWidth()); raster::rotate_image(image, new_image, m_angle); api.replaceStockImage(m_sprite, i, new_image); jobProgress((float)i / m_sprite->getStock()->size()); // cancel all the operation? if (isCanceled()) return; // UndoTransaction destructor will undo all operations } // rotate mask if (m_document->isMaskVisible()) { Mask* origMask = m_document->getMask(); base::UniquePtr<Mask> new_mask(new Mask()); const gfx::Rect& origBounds = origMask->getBounds(); int x = 0, y = 0; switch (m_angle) { case 180: x = m_sprite->getWidth() - origBounds.x - origBounds.w; y = m_sprite->getHeight() - origBounds.y - origBounds.h; break; case 90: x = m_sprite->getHeight() - origBounds.y - origBounds.h; y = origBounds.x; break; case -90: x = origBounds.y; y = m_sprite->getWidth() - origBounds.x - origBounds.w; break; } // create the new rotated mask new_mask->replace(x, y, m_angle == 180 ? origBounds.w: origBounds.h, m_angle == 180 ? origBounds.h: origBounds.w); raster::rotate_image(origMask->getBitmap(), new_mask->getBitmap(), m_angle); // Copy new mask api.copyToCurrentMask(new_mask); // Regenerate mask m_document->resetTransformation(); m_document->generateMaskBoundaries(); } // change the sprite's size if (m_angle != 180) api.setSpriteSize(m_sprite, m_sprite->getHeight(), m_sprite->getWidth()); // commit changes undoTransaction.commit(); }
/** * [working thread] */ virtual void onJob() { UndoTransaction undoTransaction(m_document, "Rotate Canvas"); // get all sprite cels CelList cels; m_sprite->getCels(cels); // for each cel... for (CelIterator it = cels.begin(); it != cels.end(); ++it) { Cel* cel = *it; Image* image = m_sprite->getStock()->getImage(cel->getImage()); // change it location switch (m_angle) { case 180: undoTransaction.setCelPosition(cel, m_sprite->getWidth() - cel->getX() - image->w, m_sprite->getHeight() - cel->getY() - image->h); break; case 90: undoTransaction.setCelPosition(cel, m_sprite->getHeight() - cel->getY() - image->h, cel->getX()); break; case -90: undoTransaction.setCelPosition(cel, cel->getY(), m_sprite->getWidth() - cel->getX() - image->w); break; } } // for each stock's image for (int i=0; i<m_sprite->getStock()->size(); ++i) { Image* image = m_sprite->getStock()->getImage(i); if (!image) continue; // rotate the image Image* new_image = image_new(image->imgtype, m_angle == 180 ? image->w: image->h, m_angle == 180 ? image->h: image->w); image_rotate(image, new_image, m_angle); undoTransaction.replaceStockImage(i, new_image); jobProgress((float)i / m_sprite->getStock()->size()); // cancel all the operation? if (isCanceled()) return; // UndoTransaction destructor will undo all operations } // rotate mask if (m_document->isMaskVisible()) { Mask* origMask = m_document->getMask(); Mask* new_mask = mask_new(); int x = 0, y = 0; switch (m_angle) { case 180: x = m_sprite->getWidth() - origMask->x - origMask->w; y = m_sprite->getHeight() - origMask->y - origMask->h; break; case 90: x = m_sprite->getHeight() - origMask->y - origMask->h; y = origMask->x; break; case -90: x = origMask->y; y = m_sprite->getWidth() - origMask->x - origMask->w; break; } // create the new rotated mask mask_replace(new_mask, x, y, m_angle == 180 ? origMask->w: origMask->h, m_angle == 180 ? origMask->h: origMask->w); image_rotate(origMask->bitmap, new_mask->bitmap, m_angle); // copy new mask undoTransaction.copyToCurrentMask(new_mask); mask_free(new_mask); // regenerate mask m_document->generateMaskBoundaries(); } // change the sprite's size if (m_angle != 180) undoTransaction.setSpriteSize(m_sprite->getHeight(), m_sprite->getWidth()); // commit changes undoTransaction.commit(); }
Layer* read_layer(std::istream& is, LayerSubObjectsSerializer* subObjects, Sprite* sprite) { uint16_t name_length = read16(is); // Name length std::vector<char> name(name_length+1); if (name_length > 0) { is.read(&name[0], name_length); // Name name[name_length] = 0; } else name[0] = 0; uint32_t flags = read32(is); // Flags uint16_t layer_type = read16(is); // Type UniquePtr<Layer> layer; switch (layer_type) { case GFXOBJ_LAYER_IMAGE: { // Create layer layer.reset(new LayerImage(sprite)); // Read cels int cels = read16(is); // Number of cels for (int c=0; c<cels; ++c) { // Read the cel Cel* cel = subObjects->read_cel(is); // Add the cel in the layer static_cast<LayerImage*>(layer.get())->addCel(cel); // Read the cel's image Image* image = subObjects->read_image(is); sprite->getStock()->replaceImage(cel->getImage(), image); } break; } case GFXOBJ_LAYER_FOLDER: { // Create the layer set layer.reset(new LayerFolder(sprite)); // Number of sub-layers int layers = read16(is); for (int c=0; c<layers; c++) { Layer* child = subObjects->read_layer(is); if (child) static_cast<LayerFolder*>(layer.get())->addLayer(child); else break; } break; } default: throw InvalidLayerType("Invalid layer type found in stream"); } if (layer != NULL) { layer->setName(&name[0]); layer->setFlags(flags); } return layer.release(); }
void FlipCommand::onExecute(Context* context) { ContextWriter writer(context); Document* document = writer.document(); Sprite* sprite = writer.sprite(); DocumentApi api = document->getApi(); { UndoTransaction undoTransaction(writer.context(), m_flipMask ? (m_flipType == raster::algorithm::FlipHorizontal ? "Flip Horizontal": "Flip Vertical"): (m_flipType == raster::algorithm::FlipHorizontal ? "Flip Canvas Horizontal": "Flip Canvas Vertical")); if (m_flipMask) { int x, y; Image* image = writer.image(&x, &y); if (!image) return; Mask* mask = NULL; bool alreadyFlipped = false; // This variable will be the area to be flipped inside the image. gfx::Rect bounds(image->getBounds()); // If there is some portion of sprite selected, we flip the // selected region only. If the mask isn't visible, we flip the // whole image. if (document->isMaskVisible()) { mask = document->getMask(); // Intersect the full area of the image with the mask's // bounds, so we don't request to flip an area outside the // image's bounds. bounds = bounds.createIntersect(gfx::Rect(mask->getBounds()).offset(-x, -y)); // If the mask isn't a rectangular area, we've to flip the mask too. if (mask->getBitmap() != NULL && !mask->isRectangular()) { int bgcolor = app_get_color_to_clear_layer(writer.layer()); // Flip the portion of image specified by the mask. mask->offsetOrigin(-x, -y); api.flipImageWithMask(image, mask, m_flipType, bgcolor); mask->offsetOrigin(x, y); alreadyFlipped = true; // Flip the mask. Image* maskBitmap = mask->getBitmap(); if (maskBitmap != NULL) { // Create a flipped copy of the current mask. base::UniquePtr<Mask> newMask(new Mask(*mask)); newMask->freeze(); raster::algorithm::flip_image(newMask->getBitmap(), maskBitmap->getBounds(), m_flipType); newMask->unfreeze(); // Change the current mask and generate the new boundaries. api.copyToCurrentMask(newMask); document->generateMaskBoundaries(); } } } // Flip the portion of image specified by "bounds" variable. if (!alreadyFlipped) { api.flipImage(image, bounds, m_flipType); } } else { // get all sprite cels CelList cels; sprite->getCels(cels); // for each cel... for (CelIterator it = cels.begin(); it != cels.end(); ++it) { Cel* cel = *it; Image* image = sprite->getStock()->getImage(cel->getImage()); api.setCelPosition (sprite, cel, (m_flipType == raster::algorithm::FlipHorizontal ? sprite->getWidth() - image->getWidth() - cel->getX(): cel->getX()), (m_flipType == raster::algorithm::FlipVertical ? sprite->getHeight() - image->getHeight() - cel->getY(): cel->getY())); api.flipImage(image, image->getBounds(), m_flipType); } } undoTransaction.commit(); } update_screen_for_document(document); }
static Cel *ase_file_read_cel_chunk(FILE *f, Sprite *sprite, int frame, PixelFormat pixelFormat, FileOp *fop, ASE_Header *header, size_t chunk_end) { /* read chunk data */ int layer_index = fgetw(f); int x = ((short)fgetw(f)); int y = ((short)fgetw(f)); int opacity = fgetc(f); int cel_type = fgetw(f); Layer* layer; ase_file_read_padding(f, 7); layer = sprite->indexToLayer(layer_index); if (!layer) { fop_error(fop, "Frame %d didn't found layer with index %d\n", frame, layer_index); return NULL; } if (!layer->is_image()) { fop_error(fop, "Invalid .ase file (frame %d in layer %d which does not contain images\n", frame, layer_index); return NULL; } // Create the new frame. UniquePtr<Cel> cel(new Cel(frame, 0)); cel->setPosition(x, y); cel->setOpacity(opacity); switch (cel_type) { case ASE_FILE_RAW_CEL: { // Read width and height int w = fgetw(f); int h = fgetw(f); if (w > 0 && h > 0) { Image* image = Image::create(pixelFormat, w, h); // Read pixel data switch (image->getPixelFormat()) { case IMAGE_RGB: read_raw_image<RgbTraits>(f, image, fop, header); break; case IMAGE_GRAYSCALE: read_raw_image<GrayscaleTraits>(f, image, fop, header); break; case IMAGE_INDEXED: read_raw_image<IndexedTraits>(f, image, fop, header); break; } cel->setImage(sprite->getStock()->addImage(image)); } break; } case ASE_FILE_LINK_CEL: { // Read link position int link_frame = fgetw(f); Cel* link = static_cast<LayerImage*>(layer)->getCel(link_frame); if (link) { // Create a copy of the linked cel (avoid using links cel) Image* image = Image::createCopy(sprite->getStock()->getImage(link->getImage())); cel->setImage(sprite->getStock()->addImage(image)); } else { // Linked cel doesn't found return NULL; } break; } case ASE_FILE_COMPRESSED_CEL: { // Read width and height int w = fgetw(f); int h = fgetw(f); if (w > 0 && h > 0) { Image* image = Image::create(pixelFormat, w, h); // Try to read pixel data try { switch (image->getPixelFormat()) { case IMAGE_RGB: read_compressed_image<RgbTraits>(f, image, chunk_end, fop, header); break; case IMAGE_GRAYSCALE: read_compressed_image<GrayscaleTraits>(f, image, chunk_end, fop, header); break; case IMAGE_INDEXED: read_compressed_image<IndexedTraits>(f, image, chunk_end, fop, header); break; } } // OK, in case of error we can show the problem, but continue // loading more cels. catch (const std::exception& e) { fop_error(fop, e.what()); } cel->setImage(sprite->getStock()->addImage(image)); } break; } } Cel* newCel = cel.release(); static_cast<LayerImage*>(layer)->addCel(newCel); return newCel; }
void UndoTransaction::flattenLayers(int bgcolor) { Image* cel_image; Cel* cel; int frame; // create a temporary image UniquePtr<Image> image_wrap(Image::create(m_sprite->getPixelFormat(), m_sprite->getWidth(), m_sprite->getHeight())); Image* image = image_wrap.get(); /* get the background layer from the sprite */ LayerImage* background = m_sprite->getBackgroundLayer(); if (!background) { /* if there aren't a background layer we must to create the background */ background = new LayerImage(m_sprite); if (isEnabled()) m_undoHistory->pushUndoer(new undoers::AddLayer(m_undoHistory->getObjects(), m_sprite->getFolder(), background)); m_sprite->getFolder()->add_layer(background); if (isEnabled()) m_undoHistory->pushUndoer(new undoers::MoveLayer(m_undoHistory->getObjects(), background)); background->configureAsBackground(); } /* copy all frames to the background */ for (frame=0; frame<m_sprite->getTotalFrames(); frame++) { /* clear the image and render this frame */ image_clear(image, bgcolor); layer_render(m_sprite->getFolder(), image, 0, 0, frame); cel = background->getCel(frame); if (cel) { cel_image = m_sprite->getStock()->getImage(cel->getImage()); ASSERT(cel_image != NULL); /* we have to save the current state of `cel_image' in the undo */ if (isEnabled()) { Dirty* dirty = new Dirty(cel_image, image); dirty->saveImagePixels(cel_image); m_undoHistory->pushUndoer(new undoers::DirtyArea( m_undoHistory->getObjects(), cel_image, dirty)); delete dirty; } } else { /* if there aren't a cel in this frame in the background, we have to create a copy of the image for the new cel */ cel_image = Image::createCopy(image); /* TODO error handling: if (!cel_image) { ... } */ /* here we create the new cel (with the new image `cel_image') */ cel = new Cel(frame, m_sprite->getStock()->addImage(cel_image)); /* TODO error handling: if (!cel) { ... } */ /* and finally we add the cel in the background */ background->addCel(cel); } image_copy(cel_image, image, 0, 0); } /* select the background */ if (m_sprite->getCurrentLayer() != background) { if (isEnabled()) m_undoHistory->pushUndoer(new undoers::SetCurrentLayer( m_undoHistory->getObjects(), m_sprite)); m_sprite->setCurrentLayer(background); } // Remove old layers. LayerList layers = m_sprite->getFolder()->get_layers_list(); LayerIterator it = layers.begin(); LayerIterator end = layers.end(); for (; it != end; ++it) { if (*it != background) { Layer* old_layer = *it; // Remove the layer if (isEnabled()) m_undoHistory->pushUndoer(new undoers::RemoveLayer(m_undoHistory->getObjects(), old_layer)); m_sprite->getFolder()->remove_layer(old_layer); // Destroy the layer delete old_layer; } } }
void UndoTransaction::backgroundFromLayer(LayerImage* layer, int bgcolor) { ASSERT(layer); ASSERT(layer->is_image()); ASSERT(layer->is_readable()); ASSERT(layer->is_writable()); ASSERT(layer->getSprite() == m_sprite); ASSERT(m_sprite->getBackgroundLayer() == NULL); // create a temporary image to draw each frame of the new // `Background' layer UniquePtr<Image> bg_image_wrap(Image::create(m_sprite->getPixelFormat(), m_sprite->getWidth(), m_sprite->getHeight())); Image* bg_image = bg_image_wrap.get(); CelIterator it = layer->getCelBegin(); CelIterator end = layer->getCelEnd(); for (; it != end; ++it) { Cel* cel = *it; ASSERT((cel->getImage() > 0) && (cel->getImage() < m_sprite->getStock()->size())); // get the image from the sprite's stock of images Image* cel_image = m_sprite->getStock()->getImage(cel->getImage()); ASSERT(cel_image); image_clear(bg_image, bgcolor); image_merge(bg_image, cel_image, cel->getX(), cel->getY(), MID(0, cel->getOpacity(), 255), layer->getBlendMode()); // now we have to copy the new image (bg_image) to the cel... setCelPosition(cel, 0, 0); // same size of cel-image and bg-image if (bg_image->w == cel_image->w && bg_image->h == cel_image->h) { if (isEnabled()) m_undoHistory->pushUndoer(new undoers::ImageArea(m_undoHistory->getObjects(), cel_image, 0, 0, cel_image->w, cel_image->h)); image_copy(cel_image, bg_image, 0, 0); } else { replaceStockImage(cel->getImage(), Image::createCopy(bg_image)); } } // Fill all empty cels with a flat-image filled with bgcolor for (int frame=0; frame<m_sprite->getTotalFrames(); frame++) { Cel* cel = layer->getCel(frame); if (!cel) { Image* cel_image = Image::create(m_sprite->getPixelFormat(), m_sprite->getWidth(), m_sprite->getHeight()); image_clear(cel_image, bgcolor); // Add the new image in the stock int image_index = addImageInStock(cel_image); // Create the new cel and add it to the new background layer cel = new Cel(frame, image_index); addCel(layer, cel); } } configureLayerAsBackground(layer); }
void DocumentApi::flattenLayers(Sprite* sprite, int bgcolor) { Image* cel_image; Cel* cel; DocumentUndo* undo = m_document->getUndo(); // Create a temporary image. UniquePtr<Image> image_wrap(Image::create(sprite->getPixelFormat(), sprite->getWidth(), sprite->getHeight())); Image* image = image_wrap.get(); // Get the background layer from the sprite. LayerImage* background = sprite->getBackgroundLayer(); if (!background) { // If there aren't a background layer we must to create the background. background = new LayerImage(sprite); addLayer(sprite->getFolder(), background, NULL); configureLayerAsBackground(background); } // Copy all frames to the background. for (FrameNumber frame(0); frame<sprite->getTotalFrames(); ++frame) { // Clear the image and render this frame. image_clear(image, bgcolor); layer_render(sprite->getFolder(), image, 0, 0, frame); cel = background->getCel(frame); if (cel) { cel_image = sprite->getStock()->getImage(cel->getImage()); ASSERT(cel_image != NULL); // We have to save the current state of `cel_image' in the undo. if (undo->isEnabled()) { Dirty* dirty = new Dirty(cel_image, image); dirty->saveImagePixels(cel_image); m_undoers->pushUndoer(new undoers::DirtyArea( getObjects(), cel_image, dirty)); delete dirty; } } else { // If there aren't a cel in this frame in the background, we // have to create a copy of the image for the new cel. cel_image = Image::createCopy(image); // TODO error handling: if createCopy throws // Here we create the new cel (with the new image `cel_image'). cel = new Cel(frame, sprite->getStock()->addImage(cel_image)); // TODO error handling: if new Cel throws // And finally we add the cel in the background. background->addCel(cel); } image_copy(cel_image, image, 0, 0); } // Delete old layers. LayerList layers = sprite->getFolder()->getLayersList(); LayerIterator it = layers.begin(); LayerIterator end = layers.end(); for (; it != end; ++it) if (*it != background) removeLayer(*it); }