1 /*
2  *  This file is part of RawTherapee.
3  *
4  *  Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
5  *  Copyright (c) 2018 Jean-Christophe FRISCH <natureh.510@gmail.com>
6  *
7  *  RawTherapee is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation, either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  RawTherapee is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with RawTherapee.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include "rtimage.h"
22 
23 #include <iostream>
24 
25 #include "options.h"
26 
27 namespace
28 {
29 
30 std::map<std::string, Glib::RefPtr<Gdk::Pixbuf> > pixbufCache;
31 std::map<std::string, Cairo::RefPtr<Cairo::ImageSurface> > surfaceCache;
32 
33 }
34 
35 double RTImage::dpiBack = 0.;
36 int RTImage::scaleBack = 0;
37 
RTImage()38 RTImage::RTImage () {}
39 
RTImage(RTImage & other)40 RTImage::RTImage (RTImage &other)
41 {
42     dpiBack = other.dpiBack;
43     scaleBack = other.scaleBack;
44     pixbuf = other.pixbuf;
45     surface = other.surface;
46     if (pixbuf) {
47         set(pixbuf);
48     } else if (surface) {
49         set(surface);
50     }
51 }
52 
RTImage(const Glib::ustring & fileName,const Glib::ustring & rtlFileName)53 RTImage::RTImage (const Glib::ustring& fileName, const Glib::ustring& rtlFileName) : Gtk::Image()
54 {
55     setImage (fileName, rtlFileName);
56 }
57 
RTImage(Glib::RefPtr<Gdk::Pixbuf> & pbuf)58 RTImage::RTImage (Glib::RefPtr<Gdk::Pixbuf> &pbuf)
59 {
60     if (surface) {
61         surface.clear();
62     }
63     if (pbuf) {
64         set(pbuf);
65         this->pixbuf = pbuf;
66     }
67 }
68 
RTImage(Cairo::RefPtr<Cairo::ImageSurface> & surf)69 RTImage::RTImage (Cairo::RefPtr<Cairo::ImageSurface> &surf)
70 {
71     if (pixbuf) {
72         pixbuf.clear();
73     }
74     if (surf) {
75         set(surf);
76         surface = surf;
77     }
78 }
79 
RTImage(Glib::RefPtr<RTImage> & other)80 RTImage::RTImage (Glib::RefPtr<RTImage> &other)
81 {
82     if (other) {
83         if (other->get_surface()) {
84             surface = other->get_surface();
85             set(surface);
86         } else {
87             pixbuf = other->get_pixbuf();
88             set(pixbuf);
89         }
90     }
91 }
92 
setImage(const Glib::ustring & fileName,const Glib::ustring & rtlFileName)93 void RTImage::setImage (const Glib::ustring& fileName, const Glib::ustring& rtlFileName)
94 {
95     Glib::ustring imageName;
96 
97     if (!rtlFileName.empty() && getDirection() == Gtk::TEXT_DIR_RTL) {
98         imageName = rtlFileName;
99     } else {
100         imageName = fileName;
101     }
102 
103     changeImage (imageName);
104 }
105 
106 /*
107  * On windows, if scale = 2, the dpi is non significant, i.e. should be considered = 192
108  */
setDPInScale(const double newDPI,const int newScale)109 void RTImage::setDPInScale (const double newDPI, const int newScale)
110 {
111     if (scaleBack != newScale || (scaleBack == 1 && dpiBack != newDPI)) {
112         RTScalable::setDPInScale(newDPI, newScale);
113         dpiBack = getDPI();
114         scaleBack = getScale();
115         updateImages();
116     }
117 }
118 
changeImage(const Glib::ustring & imageName)119 void RTImage::changeImage (const Glib::ustring& imageName)
120 {
121     clear ();
122 
123     if (imageName.empty()) {
124         return;
125     }
126 
127     if (pixbuf) {
128         auto iterator = pixbufCache.find (imageName);
129         assert(iterator != pixbufCache.end ());
130         pixbuf = iterator->second;
131         set(iterator->second);
132     } else  {  // if no Pixbuf is set, we update or create a Cairo::ImageSurface
133         auto iterator = surfaceCache.find (imageName);
134         if (iterator == surfaceCache.end ()) {
135             auto surf = createImgSurfFromFile(imageName);
136             iterator = surfaceCache.emplace (imageName, surf).first;
137         }
138         surface = iterator->second;
139         set(iterator->second);
140     }
141 }
142 
get_surface()143 Cairo::RefPtr<Cairo::ImageSurface> RTImage::get_surface()
144 {
145     return surface;
146 }
147 
get_width()148 int RTImage::get_width()
149 {
150     if (surface) {
151         return surface->get_width();
152     }
153     if (pixbuf) {
154         return pixbuf->get_width();
155     }
156     return -1;
157 }
158 
get_height()159 int RTImage::get_height()
160 {
161     if (surface) {
162         return surface->get_height();
163     }
164     if (pixbuf) {
165         return pixbuf->get_height();
166     }
167     return -1;
168 }
169 
init()170 void RTImage::init()
171 {
172     dpiBack = RTScalable::getDPI();
173     scaleBack = RTScalable::getScale();
174 }
175 
cleanup(bool all)176 void RTImage::cleanup(bool all)
177 {
178     for (auto& entry : pixbufCache) {
179         entry.second.reset();
180     }
181     for (auto& entry : surfaceCache) {
182         entry.second.clear();
183     }
184     RTScalable::cleanup(all);
185 }
186 
updateImages()187 void RTImage::updateImages()
188 {
189     for (auto& entry : pixbufCache) {
190         entry.second = createPixbufFromFile(entry.first);
191     }
192     for (auto& entry : surfaceCache) {
193         entry.second = createImgSurfFromFile(entry.first);
194     }
195 }
196 
createPixbufFromFile(const Glib::ustring & fileName)197 Glib::RefPtr<Gdk::Pixbuf> RTImage::createPixbufFromFile (const Glib::ustring& fileName)
198 {
199     Cairo::RefPtr<Cairo::ImageSurface> imgSurf = createImgSurfFromFile(fileName);
200     return Gdk::Pixbuf::create(imgSurf, 0, 0, imgSurf->get_width(), imgSurf->get_height());
201 }
202 
createImgSurfFromFile(const Glib::ustring & fileName)203 Cairo::RefPtr<Cairo::ImageSurface> RTImage::createImgSurfFromFile (const Glib::ustring& fileName)
204 {
205     Cairo::RefPtr<Cairo::ImageSurface> surf;
206 
207     try {
208         surf = loadImage(fileName, getTweakedDPI());
209 
210         // HOMBRE: As of now, GDK_SCALE is forced to 1, so setting the Cairo::ImageSurface scale is not required
211         /*
212         double x=0., y=0.;
213         cairo_surface_get_device_scale(surf->cobj(), &x, &y);
214         if (getScale() == 2) {
215             cairo_surface_set_device_scale(surf->cobj(), 0.5, 0.5);
216             cairo_surface_get_device_scale(surf->cobj(), &x, &y);
217             surf->flush();
218         }
219         */
220     } catch (const Glib::Exception& exception) {
221         if (options.rtSettings.verbose) {
222             std::cerr << "Failed to load image \"" << fileName << "\": " << exception.what() << std::endl;
223         }
224     }
225 
226     return surf;
227 }
228