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);
}
Beispiel #2
0
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);
  }
Beispiel #4
0
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;
    }

  }
}
Beispiel #5
0
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();
}
Beispiel #6
0
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);
}
Beispiel #7
0
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();
}
Beispiel #8
0
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;
}
Beispiel #9
0
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();
  }
Beispiel #11
0
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;
    }

  }
}
Beispiel #12
0
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;
}