1 // Aseprite
2 // Copyright (C) 2016  Carlo Caputo
3 //
4 // This program is distributed under the terms of
5 // the End-User License Agreement for Aseprite.
6 
7 #include "app/color_utils.h"
8 #include "app/doc.h"
9 #include "app/pref/preferences.h"
10 #include "app/thumbnails.h"
11 #include "doc/algorithm/resize_image.h"
12 #include "doc/cel.h"
13 #include "doc/conversion_she.h"
14 #include "doc/doc.h"
15 #include "doc/frame.h"
16 #include "doc/object.h"
17 #include "doc/object_id.h"
18 #include "render/render.h"
19 #include "she/surface.h"
20 #include "she/system.h"
21 
22 namespace app {
23 namespace thumb {
24 
get_cel_thumbnail(const doc::Cel * cel,const gfx::Size & thumb_size,gfx::Rect cel_image_on_thumb)25 she::Surface* get_cel_thumbnail(const doc::Cel* cel,
26                                 const gfx::Size& thumb_size,
27                                 gfx::Rect cel_image_on_thumb)
28 {
29   Doc* document = static_cast<Doc*>(cel->sprite()->document());
30   doc::frame_t frame = cel->frame();
31   doc::Image* image = cel->image();
32 
33   DocumentPreferences& docPref = Preferences::instance().document(document);
34 
35   doc::color_t bg1 = color_utils::color_for_image(docPref.bg.color1(), image->pixelFormat());
36   doc::color_t bg2 = color_utils::color_for_image(docPref.bg.color2(), image->pixelFormat());
37 
38   gfx::Size image_size = image->size();
39 
40   if (cel_image_on_thumb.isEmpty()) {
41     double zw = thumb_size.w / (double)image_size.w;
42     double zh = thumb_size.h / (double)image_size.h;
43     double zoom = MIN(1.0, MIN(zw, zh));
44 
45     cel_image_on_thumb = gfx::Rect(
46       (int)(thumb_size.w * 0.5 - image_size.w * zoom * 0.5),
47       (int)(thumb_size.h * 0.5 - image_size.h * zoom * 0.5),
48       MAX(1, (int)(image_size.w * zoom)),
49       MAX(1, (int)(image_size.h * zoom)));
50   }
51 
52   const doc::Sprite* sprite = document->sprite();
53   // TODO doc::Image::createCopy() from pre-rendered checkered background
54   base::UniquePtr<doc::Image> thumb_img(doc::Image::create(
55                                           image->pixelFormat(), thumb_size.w, thumb_size.h));
56 
57   int block_size = MID(4, thumb_size.w/8, 16);
58   for (int dst_y = 0; dst_y < thumb_size.h; dst_y++) {
59     for (int dst_x = 0; dst_x < thumb_size.w; dst_x++) {
60       thumb_img->putPixel(dst_x, dst_y,
61                           (((dst_x / block_size) % 2) ^
62                            ((dst_y / block_size) % 2)) ? bg2: bg1);
63     }
64   }
65 
66   base::UniquePtr<doc::Image> scale_img;
67   const doc::Image* source = image;
68 
69   if (cel_image_on_thumb.w != image_size.w || cel_image_on_thumb.h != image_size.h) {
70     scale_img.reset(doc::Image::create(
71                       image->pixelFormat(), cel_image_on_thumb.w, cel_image_on_thumb.h));
72 
73     doc::algorithm::resize_image(
74       image, scale_img,
75       doc::algorithm::ResizeMethod::RESIZE_METHOD_NEAREST_NEIGHBOR,
76       sprite->palette(frame),
77       sprite->rgbMap(frame),
78       sprite->transparentColor());
79 
80     source = scale_img.get();
81   }
82 
83   render::composite_image(
84     thumb_img, source,
85     sprite->palette(frame),
86     cel_image_on_thumb.x,
87     cel_image_on_thumb.y,
88     255, BlendMode::NORMAL);
89 
90   she::Surface* thumb_surf = she::instance()->createRgbaSurface(
91     thumb_img->width(), thumb_img->height());
92 
93   convert_image_to_surface(thumb_img, sprite->palette(frame), thumb_surf,
94                            0, 0, 0, 0, thumb_img->width(), thumb_img->height());
95 
96   return thumb_surf;
97 }
98 
99 } // thumb
100 } // app
101