1 // Aseprite
2 // Copyright (C) 2001-2017  David Capello
3 //
4 // This program is distributed under the terms of
5 // the End-User License Agreement for Aseprite.
6 
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10 
11 #include "base/unique_ptr.h"
12 #include "doc/algorithm/resize_image.h"
13 #include "doc/cel.h"
14 #include "doc/image.h"
15 #include "doc/layer.h"
16 #include "doc/palette.h"
17 #include "doc/primitives.h"
18 #include "doc/sprite.h"
19 #include "render/ordered_dither.h"
20 #include "render/quantization.h"
21 #include "render/render.h"
22 
23 #include <cmath>
24 
25 namespace app {
26 
27 using namespace doc;
28 
create_cel_copy(const Cel * srcCel,const Sprite * dstSprite,const Layer * dstLayer,const frame_t dstFrame)29 Cel* create_cel_copy(const Cel* srcCel,
30                      const Sprite* dstSprite,
31                      const Layer* dstLayer,
32                      const frame_t dstFrame)
33 {
34   const Image* celImage = srcCel->image();
35 
36   base::UniquePtr<Cel> dstCel(
37     new Cel(dstFrame,
38             ImageRef(Image::create(dstSprite->pixelFormat(),
39                                    celImage->width(),
40                                    celImage->height()))));
41 
42   if ((dstSprite->pixelFormat() != celImage->pixelFormat()) ||
43       // If both images are indexed but with different palette, we can
44       // convert the source cel to RGB first.
45       (dstSprite->pixelFormat() == IMAGE_INDEXED &&
46        celImage->pixelFormat() == IMAGE_INDEXED &&
47        srcCel->sprite()->palette(srcCel->frame())->countDiff(
48          dstSprite->palette(dstFrame), nullptr, nullptr))) {
49     ImageRef tmpImage(Image::create(IMAGE_RGB, celImage->width(), celImage->height()));
50     tmpImage->clear(0);
51 
52     render::convert_pixel_format(
53       celImage,
54       tmpImage.get(),
55       IMAGE_RGB,
56       render::DitheringAlgorithm::None,
57       render::DitheringMatrix(),
58       srcCel->sprite()->rgbMap(srcCel->frame()),
59       srcCel->sprite()->palette(srcCel->frame()),
60       srcCel->layer()->isBackground(),
61       0);
62 
63     render::convert_pixel_format(
64       tmpImage.get(),
65       dstCel->image(),
66       IMAGE_INDEXED,
67       render::DitheringAlgorithm::None,
68       render::DitheringMatrix(),
69       dstSprite->rgbMap(dstFrame),
70       dstSprite->palette(dstFrame),
71       srcCel->layer()->isBackground(),
72       dstSprite->transparentColor());
73   }
74   else {
75     render::composite_image(
76       dstCel->image(),
77       celImage,
78       srcCel->sprite()->palette(srcCel->frame()),
79       0, 0, 255, BlendMode::SRC);
80   }
81 
82   // Resize a referecen cel to a non-reference layer
83   if (srcCel->layer()->isReference() && !dstLayer->isReference()) {
84     gfx::RectF srcBounds = srcCel->boundsF();
85 
86     base::UniquePtr<Cel> dstCel2(
87       new Cel(dstFrame,
88               ImageRef(Image::create(dstSprite->pixelFormat(),
89                                      std::ceil(srcBounds.w),
90                                      std::ceil(srcBounds.h)))));
91     algorithm::resize_image(
92       dstCel->image(), dstCel2->image(),
93       algorithm::RESIZE_METHOD_NEAREST_NEIGHBOR,
94       nullptr, nullptr, 0);
95 
96     dstCel.reset(dstCel2.release());
97     dstCel->setPosition(gfx::Point(srcBounds.origin()));
98   }
99   // Copy original cel bounds
100   else {
101     if (srcCel->layer() &&
102         srcCel->layer()->isReference()) {
103       dstCel->setBoundsF(srcCel->boundsF());
104     }
105     else {
106       dstCel->setPosition(srcCel->position());
107     }
108   }
109 
110   dstCel->setOpacity(srcCel->opacity());
111   dstCel->data()->setUserData(srcCel->data()->userData());
112 
113   return dstCel.release();
114 }
115 
116 } // namespace app
117