// [working thread] virtual void onJob() { Transaction transaction(m_writer.context(), "Rotate Canvas"); DocumentApi api = m_document->getApi(transaction); // 1) Rotate cel positions for (Cel* cel : m_cels) { Image* image = cel->image(); if (!image) continue; switch (m_angle) { case 180: api.setCelPosition(m_sprite, cel, m_sprite->width() - cel->x() - image->width(), m_sprite->height() - cel->y() - image->height()); break; case 90: api.setCelPosition(m_sprite, cel, m_sprite->height() - cel->y() - image->height(), cel->x()); break; case -90: api.setCelPosition(m_sprite, cel, cel->y(), m_sprite->width() - cel->x() - image->width()); break; } } // 2) Rotate images int i = 0; for (Cel* cel : m_cels) { Image* image = cel->image(); if (image) { ImageRef new_image(Image::create(image->pixelFormat(), m_angle == 180 ? image->width(): image->height(), m_angle == 180 ? image->height(): image->width())); doc::rotate_image(image, new_image.get(), m_angle); api.replaceImage(m_sprite, cel->imageRef(), new_image); } jobProgress((float)i / m_cels.size()); ++i; // cancel all the operation? if (isCanceled()) return; // Transaction destructor will undo all operations } // rotate mask if (m_document->isMaskVisible()) { Mask* origMask = m_document->mask(); base::UniquePtr<Mask> new_mask(new Mask()); const gfx::Rect& origBounds = origMask->bounds(); int x = 0, y = 0; switch (m_angle) { case 180: x = m_sprite->width() - origBounds.x - origBounds.w; y = m_sprite->height() - origBounds.y - origBounds.h; break; case 90: x = m_sprite->height() - origBounds.y - origBounds.h; y = origBounds.x; break; case -90: x = origBounds.y; y = m_sprite->width() - origBounds.x - origBounds.w; break; } // create the new rotated mask new_mask->replace( gfx::Rect(x, y, m_angle == 180 ? origBounds.w: origBounds.h, m_angle == 180 ? origBounds.h: origBounds.w)); doc::rotate_image(origMask->bitmap(), new_mask->bitmap(), m_angle); // Copy new mask api.copyToCurrentMask(new_mask); // Regenerate mask m_document->resetTransformation(); m_document->generateMaskBoundaries(); } // change the sprite's size if (m_rotateSprite && m_angle != 180) api.setSpriteSize(m_sprite, m_sprite->height(), m_sprite->width()); // commit changes transaction.commit(); }
/** * [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 FilterManagerImpl::applyToTarget() { const bool paletteChange = paletteHasChanged(); bool cancelled = false; CelList cels; switch (m_celsTarget) { case CelsTarget::Selected: { auto range = App::instance()->timeline()->range(); if (range.enabled()) cels = get_unlocked_unique_cels(m_site.sprite(), range); else if (m_site.cel() && m_site.layer() && m_site.layer()->isEditable()) { cels.push_back(m_site.cel()); } break; } case CelsTarget::All: { for (Cel* cel : m_site.sprite()->uniqueCels()) { if (cel->layer()->isEditable()) cels.push_back(cel); } break; } } if (cels.empty() && !paletteChange) { // We don't have images/palette changes to do (there will not be a // transaction). return; } // Initialize writting operation ContextReader reader(m_context); ContextWriter writer(reader); m_transaction.reset(new Transaction(writer.context(), m_filter->getName(), ModifyDocument)); m_progressBase = 0.0f; m_progressWidth = (cels.size() > 0 ? 1.0f / cels.size(): 1.0f); std::set<ObjectId> visited; // Palette change if (paletteChange) { Palette newPalette = *getNewPalette(); restoreSpritePalette(); m_transaction->execute( new cmd::SetPalette(m_site.sprite(), m_site.frame(), &newPalette)); } // For each target image for (auto it = cels.begin(); it != cels.end() && !cancelled; ++it) { Image* image = (*it)->image(); // Avoid applying the filter two times to the same image if (visited.find(image->id()) == visited.end()) { visited.insert(image->id()); applyToCel(*it); } // Is there a delegate to know if the process was cancelled by the user? if (m_progressDelegate) cancelled = m_progressDelegate->isCancelled(); // Make progress m_progressBase += m_progressWidth; } // Reset m_oldPalette to avoid restoring the color palette m_oldPalette.reset(nullptr); }