static Mask *ase_file_read_mask_chunk(FILE *f) { int c, u, v, byte; Mask *mask; // Read chunk data int x = fgetw(f); int y = fgetw(f); int w = fgetw(f); int h = fgetw(f); ase_file_read_padding(f, 8); std::string name = ase_file_read_string(f); mask = new Mask(); mask->setName(name.c_str()); mask->replace(x, y, w, h); // Read image data for (v=0; v<h; v++) for (u=0; u<(w+7)/8; u++) { byte = fgetc(f); for (c=0; c<8; c++) image_putpixel(mask->getBitmap(), u*8+c, v, byte & (1<<(7-c))); } return mask; }
// Loads a MSK file (Animator and Animator Pro format) Mask* load_msk_file(const char* filename) { #if (MAKE_VERSION(4, 2, 1) >= MAKE_VERSION(ALLEGRO_VERSION, \ ALLEGRO_SUB_VERSION, \ ALLEGRO_WIP_VERSION)) int orig_size = file_size(filename); #else int orig_size = file_size_ex(filename); #endif int i, c, u, v, byte, magic, size; Mask *mask = NULL; PACKFILE *f; f = pack_fopen(filename, F_READ); if (!f) return NULL; size = pack_igetl(f); magic = pack_igetw(f); // Animator Pro MSK format if ((size == orig_size) && (magic == 0x9500)) { int x, y; pack_fclose(f); // Just load an Animator Pro PIC file base::UniquePtr<Image> image(load_pic_file(filename, &x, &y, NULL)); if (image != NULL && (image->getPixelFormat() == IMAGE_BITMAP)) { mask = new Mask(x, y, image.release()); } } // Animator MSK format else if (orig_size == 8000) { mask = new Mask(); mask->replace(0, 0, 320, 200); u = v = 0; for (i=0; i<8000; i++) { byte = pack_getc (f); for (c=0; c<8; c++) { mask->getBitmap()->putpixel(u, v, byte & (1<<(7-c))); u++; if (u == 320) { u = 0; v++; } } } pack_fclose(f); } else { pack_fclose(f); } return mask; }
/** * [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(); }
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); }
// clears the mask region in the current sprite with the specified background color void UndoTransaction::clearMask(int bgcolor) { Cel* cel = getCurrentCel(); if (!cel) return; Image* image = getCelImage(cel); if (!image) return; Mask* mask = m_document->getMask(); // If the mask is empty or is not visible then we have to clear the // entire image in the cel. if (!m_document->isMaskVisible()) { // If the layer is the background then we clear the image. if (m_sprite->getCurrentLayer()->is_background()) { if (isEnabled()) m_undoHistory->pushUndoer(new undoers::ImageArea(m_undoHistory->getObjects(), image, 0, 0, image->w, image->h)); // clear all image_clear(image, bgcolor); } // If the layer is transparent we can remove the cel (and its // associated image). else { removeCel(static_cast<LayerImage*>(m_sprite->getCurrentLayer()), cel); } } else { int offset_x = mask->getBounds().x-cel->getX(); int offset_y = mask->getBounds().y-cel->getY(); int u, v, putx, puty; int x1 = MAX(0, offset_x); int y1 = MAX(0, offset_y); int x2 = MIN(image->w-1, offset_x+mask->getBounds().w-1); int y2 = MIN(image->h-1, offset_y+mask->getBounds().h-1); // do nothing if (x1 > x2 || y1 > y2) return; if (isEnabled()) m_undoHistory->pushUndoer(new undoers::ImageArea(m_undoHistory->getObjects(), image, x1, y1, x2-x1+1, y2-y1+1)); // clear the masked zones for (v=0; v<mask->getBounds().h; v++) { div_t d = div(0, 8); uint8_t* address = ((uint8_t**)mask->getBitmap()->line)[v]+d.quot; for (u=0; u<mask->getBounds().w; u++) { if ((*address & (1<<d.rem))) { putx = u + offset_x; puty = v + offset_y; image_putpixel(image, putx, puty, bgcolor); } _image_bitmap_next_bit(d, address); } } } }