1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2002-12-09
7  * Description : a tool to print images
8  *
9  * Copyright (C) 2002-2003 by Todd Shoemaker <todd at theshoemakers dot net>
10  * Copyright (C) 2007-2012 by Angelo Naselli <anaselli at linux dot it>
11  * Copyright (C) 2006-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
12  *
13  * This program is free software; you can redistribute it
14  * and/or modify it under the terms of the GNU General
15  * Public License as published by the Free Software Foundation;
16  * either version 2, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * ============================================================ */
24 
25 #include "advprintphoto.h"
26 
27 // Qt includes
28 
29 #include <QFileInfo>
30 #include <QPolygon>
31 
32 // KDE includes
33 
34 #include <klocalizedstring.h>
35 
36 // Local includes
37 
38 #include "digikam_debug.h"
39 #include "previewloadthread.h"
40 #include "advprintwizard.h"
41 
42 namespace DigikamGenericPrintCreatorPlugin
43 {
44 
AdvPrintPhotoSize()45 AdvPrintPhotoSize::AdvPrintPhotoSize()
46     : m_label     (i18n("Unsupported Paper Size")),
47       m_dpi       (0),
48       m_autoRotate(false)
49 {
50 }
51 
AdvPrintPhotoSize(const AdvPrintPhotoSize & other)52 AdvPrintPhotoSize::AdvPrintPhotoSize(const AdvPrintPhotoSize& other)
53     : m_label     (other.m_label),
54       m_dpi       (other.m_dpi),
55       m_autoRotate(other.m_autoRotate),
56       m_layouts   (other.m_layouts),
57       m_icon      (other.m_icon)
58 
59 {
60 }
61 
~AdvPrintPhotoSize()62 AdvPrintPhotoSize::~AdvPrintPhotoSize()
63 {
64 }
65 
66 // -----------------------------
67 
AdvPrintAdditionalInfo()68 AdvPrintAdditionalInfo::AdvPrintAdditionalInfo()
69     : m_unit                (0),
70       m_printPosition       (0),
71       m_scaleMode           (0),
72       m_keepRatio           (true),
73       m_autoRotate          (true),
74       m_printWidth          (0.0),
75       m_printHeight         (0.0),
76       m_enlargeSmallerImages(false)
77 {
78 }
79 
AdvPrintAdditionalInfo(const AdvPrintAdditionalInfo & other)80 AdvPrintAdditionalInfo::AdvPrintAdditionalInfo(const AdvPrintAdditionalInfo& other)
81     : m_unit                (other.m_unit),
82       m_printPosition       (other.m_printPosition),
83       m_scaleMode           (other.m_scaleMode),
84       m_keepRatio           (other.m_keepRatio),
85       m_autoRotate          (other.m_autoRotate),
86       m_printWidth          (other.m_printWidth),
87       m_printHeight         (other.m_printHeight),
88       m_enlargeSmallerImages(other.m_enlargeSmallerImages)
89 {
90 }
91 
~AdvPrintAdditionalInfo()92 AdvPrintAdditionalInfo::~AdvPrintAdditionalInfo()
93 {
94 }
95 
96 // -----------------------------
97 
AdvPrintCaptionInfo()98 AdvPrintCaptionInfo::AdvPrintCaptionInfo()
99     : m_captionType (AdvPrintSettings::NONE),
100       m_captionFont (QLatin1String("Sans Serif")),
101       m_captionColor(Qt::yellow),
102       m_captionSize (2),
103       m_captionText (QLatin1String(""))
104 {
105 }
106 
AdvPrintCaptionInfo(const AdvPrintCaptionInfo & other)107 AdvPrintCaptionInfo::AdvPrintCaptionInfo(const AdvPrintCaptionInfo& other)
108     : m_captionType (other.m_captionType),
109       m_captionFont (other.m_captionFont),
110       m_captionColor(other.m_captionColor),
111       m_captionSize (other.m_captionSize),
112       m_captionText (other.m_captionText)
113 {
114 }
115 
~AdvPrintCaptionInfo()116 AdvPrintCaptionInfo::~AdvPrintCaptionInfo()
117 {
118 }
119 
120 // -----------------------------
121 
AdvPrintPhoto(int thumbnailSize,DInfoInterface * const iface)122 AdvPrintPhoto::AdvPrintPhoto(int thumbnailSize, DInfoInterface* const iface)
123     : m_url                 (QUrl()),
124       m_thumbnailSize       (thumbnailSize),
125       m_cropRegion          (QRect(-1, -1, -1, -1)),
126       m_first               (false),
127       m_copies              (1),
128       m_rotation            (0),
129       m_pAddInfo            (nullptr),
130       m_pAdvPrintCaptionInfo(nullptr),
131       m_iface               (iface),
132       m_thumbnail           (nullptr),
133       m_size                (nullptr)
134 {
135 }
136 
AdvPrintPhoto(const AdvPrintPhoto & other)137 AdvPrintPhoto::AdvPrintPhoto(const AdvPrintPhoto& other)
138     : m_url                 (other.m_url),
139       m_thumbnailSize       (other.m_thumbnailSize),
140       m_cropRegion          (other.m_cropRegion),
141       m_first               (other.m_first),
142       m_copies              (other.m_copies),
143       m_rotation            (other.m_rotation),
144       m_pAddInfo            (nullptr),
145       m_pAdvPrintCaptionInfo(nullptr),
146       m_iface               (other.m_iface),
147       m_thumbnail           (nullptr),
148       m_size                (nullptr)
149 {
150     if (other.m_pAddInfo)
151     {
152         m_pAddInfo = new AdvPrintAdditionalInfo(*other.m_pAddInfo);
153     }
154 
155     if (other.m_pAdvPrintCaptionInfo)
156     {
157         m_pAdvPrintCaptionInfo = new AdvPrintCaptionInfo(*other.m_pAdvPrintCaptionInfo);
158     }
159 }
160 
~AdvPrintPhoto()161 AdvPrintPhoto::~AdvPrintPhoto()
162 {
163     delete m_thumbnail;
164     delete m_size;
165     delete m_pAddInfo;
166     delete m_pAdvPrintCaptionInfo;
167 }
168 
loadInCache()169 void AdvPrintPhoto::loadInCache()
170 {
171     // Load the thumbnail and size only once.
172 
173     delete m_thumbnail;
174     DImg photo  = loadPhoto();
175     m_thumbnail = new DImg(photo.smoothScale(m_thumbnailSize, m_thumbnailSize, Qt::KeepAspectRatio));
176 
177     delete m_size;
178     m_size      = new QSize(photo.width(), photo.height());
179 }
180 
thumbnail()181 DImg& AdvPrintPhoto::thumbnail()
182 {
183     if (!m_thumbnail)
184     {
185         loadInCache();
186     }
187 
188     return *m_thumbnail;
189 }
190 
loadPhoto()191 DImg AdvPrintPhoto::loadPhoto()
192 {
193     return PreviewLoadThread::loadHighQualitySynchronously(m_url.toLocalFile());
194 }
195 
size()196 QSize& AdvPrintPhoto::size()
197 {
198     if (m_size == nullptr)
199     {
200         loadInCache();
201     }
202 
203     return *m_size;
204 }
205 
width()206 int AdvPrintPhoto::width()
207 {
208     return size().width();
209 }
210 
height()211 int AdvPrintPhoto::height()
212 {
213     return size().height();
214 }
215 
scaleWidth(double unitToInches)216 double AdvPrintPhoto::scaleWidth(double unitToInches)
217 {
218     Q_ASSERT(m_pAddInfo != nullptr);
219 
220     m_cropRegion = QRect(0, 0,
221                          (int)(m_pAddInfo->m_printWidth  * unitToInches),
222                          (int)(m_pAddInfo->m_printHeight * unitToInches));
223 
224     return (m_pAddInfo->m_printWidth * unitToInches);
225 }
226 
scaleHeight(double unitToInches)227 double AdvPrintPhoto::scaleHeight(double unitToInches)
228 {
229     Q_ASSERT(m_pAddInfo != nullptr);
230 
231     m_cropRegion = QRect(0, 0,
232                          (int)(m_pAddInfo->m_printWidth  * unitToInches),
233                          (int)(m_pAddInfo->m_printHeight * unitToInches));
234 
235     return (m_pAddInfo->m_printHeight * unitToInches);
236 }
237 
updateCropRegion(int woutlay,int houtlay,bool autoRotate)238 QMatrix AdvPrintPhoto::updateCropRegion(int woutlay, int houtlay, bool autoRotate)
239 {
240     QSize thmSize        = thumbnail().size();
241     QRect imgRect        = QRect(0, 0, size().width(), size().height());
242     bool resetCropRegion = (m_cropRegion == QRect(-1, -1, -1, -1));
243 
244     if (resetCropRegion)
245     {
246         // First, let's see if we should rotate
247 
248         if (autoRotate)
249         {
250             if ((m_rotation == 0) &&
251                 (((woutlay > houtlay) && (thmSize.height() > thmSize.width())) ||
252                  ((houtlay > woutlay) && (thmSize.width()  > thmSize.height()))))
253             {
254                 // We will perform a rotation
255 
256                 m_rotation = 90;
257             }
258         }
259     }
260     else
261     {
262         // Does the crop region need updating (but the image shouldn't be rotated)?
263 
264         resetCropRegion = (m_cropRegion == QRect(-2, -2, -2, -2));
265     }
266 
267     // Rotate the image rectangle.
268 
269     QMatrix matrix;
270     matrix.rotate(m_rotation);
271     imgRect = matrix.mapToPolygon(imgRect).boundingRect();
272     imgRect.translate((-1)*imgRect.x(), (-1)*imgRect.y());
273 
274     // Size the rectangle based on the minimum image dimension.
275 
276     int w   = imgRect.width();
277     int h   = imgRect.height();
278 
279     if (w < h)
280     {
281         h = AdvPrintWizard::normalizedInt((double)w * ((double)houtlay / (double)woutlay));
282 
283         if (h > imgRect.height())
284         {
285             h = imgRect.height();
286             w = AdvPrintWizard::normalizedInt((double)h * ((double)woutlay / (double)houtlay));
287         }
288     }
289     else
290     {
291         w = AdvPrintWizard::normalizedInt((double)h * ((double)woutlay / (double)houtlay));
292 
293         if (w > imgRect.width())
294         {
295             w = imgRect.width();
296             h = AdvPrintWizard::normalizedInt((double)w * ((double)houtlay / (double)woutlay));
297         }
298     }
299 
300     if (resetCropRegion)
301     {
302         m_cropRegion = QRect((imgRect.width()  / 2) - (w / 2),
303                              (imgRect.height() / 2) - (h / 2),
304                              w, h);
305     }
306 
307     return matrix;
308 }
309 
310 } // Namespace Digikam
311