1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2007-08-02
7  * Description : save JPEG image options.
8  *
9  * Copyright (C) 2007-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
10  *
11  * This program is free software; you can redistribute it
12  * and/or modify it under the terms of the GNU General
13  * Public License as published by the Free Software Foundation;
14  * either version 2, or (at your option)
15  * any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * ============================================================ */
23 
24 #include "jpegsettings.h"
25 
26 // Qt includes
27 
28 #include <QApplication>
29 #include <QFrame>
30 #include <QGridLayout>
31 #include <QLabel>
32 #include <QLayout>
33 #include <QString>
34 #include <QComboBox>
35 #include <QStyle>
36 
37 // KDE includes
38 
39 #include <klocalizedstring.h>
40 
41 // Local includes
42 
43 #include "dnuminput.h"
44 
45 namespace Digikam
46 {
47 
48 class Q_DECL_HIDDEN JPEGSettings::Private
49 {
50 
51 public:
52 
Private()53     explicit Private()
54       : JPEGGrid            (nullptr),
55         labelJPEGcompression(nullptr),
56         labelWarning        (nullptr),
57         labelSubSampling    (nullptr),
58         subSamplingCB       (nullptr),
59         JPEGcompression     (nullptr)
60     {
61     }
62 
63     QGridLayout*  JPEGGrid;
64 
65     QLabel*       labelJPEGcompression;
66     QLabel*       labelWarning;
67     QLabel*       labelSubSampling;
68 
69     QComboBox*    subSamplingCB;
70 
71     DIntNumInput* JPEGcompression;
72 };
73 
JPEGSettings(QWidget * const parent)74 JPEGSettings::JPEGSettings(QWidget* const parent)
75     : QWidget(parent),
76       d      (new Private)
77 {
78     setAttribute(Qt::WA_DeleteOnClose);
79 
80     const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing);
81 
82     d->JPEGGrid             = new QGridLayout(this);
83     d->JPEGcompression      = new DIntNumInput(this);
84     d->JPEGcompression->setDefaultValue(75);
85     d->JPEGcompression->setRange(1, 100, 1);
86     d->labelJPEGcompression = new QLabel(i18n("JPEG quality:"), this);
87 
88     d->JPEGcompression->setWhatsThis(i18n("<p>The JPEG quality:</p>"
89                                           "<p><b>1</b>: low quality (high compression and small "
90                                           "file size)<br/>"
91                                           "<b>50</b>: medium quality<br/>"
92                                           "<b>75</b>: good quality (default)<br/>"
93                                           "<b>100</b>: high quality (no compression and "
94                                           "large file size)</p>"
95                                           "<p><b>Note: JPEG always uses lossy compression.</b></p>"));
96 
97     d->labelWarning = new QLabel(i18n("<font color='red'><i>"
98                                       "Warning: <a href='https://en.wikipedia.org/wiki/JPEG'>JPEG</a> is a "
99                                       "lossy image compression format."
100                                       "</i></font>"), this);
101 
102     d->labelWarning->setOpenExternalLinks(true);
103     d->labelWarning->setFrameStyle(QFrame::Box | QFrame::Plain);
104     d->labelWarning->setLineWidth(1);
105     d->labelWarning->setFrameShape(QFrame::Box);
106 
107     d->labelSubSampling = new QLabel(i18n("Chroma subsampling:"), this);
108 
109     d->subSamplingCB = new QComboBox(this);
110     d->subSamplingCB->insertItem(0, i18n("4:4:4 (best quality)")); // 1x1, 1x1, 1x1 (4:4:4)
111     d->subSamplingCB->insertItem(1, i18n("4:2:2 (good quality)")); // 2x1, 1x1, 1x1 (4:2:2)
112     d->subSamplingCB->insertItem(2, i18n("4:2:0 (low quality)"));  // 2x2, 1x1, 1x1 (4:2:0)
113     d->subSamplingCB->insertItem(3, i18n("4:1:1 (low quality)"));  // 4x1, 1x1, 1x1 (4:1:1)
114     d->subSamplingCB->setWhatsThis(i18n("<p>Chroma subsampling reduces file size by taking advantage of the "
115                                         "eye's lesser sensitivity to color resolution. How perceptible the "
116                                         "difference is depends on the image - large photos will generally "
117                                         "show no difference, while sharp, down-scaled pixel graphics may "
118                                         "lose fine color detail.</p>"
119                                         "<p><b>4:4:4</b> - No chroma subsampling, highest "
120                                         "quality but lowest compression.</p>"
121                                         "<p><b>4:2:2</b> - Chroma halved horizontally, average "
122                                         "compression, average quality.</p>"
123                                         "<p><b>4:2:0</b> - Chroma quartered in 2x2 blocks, "
124                                         "high compression but low quality.</p>"
125                                         "<p><b>4:1:1</b> - Chroma quartered in 4x1 blocks, "
126                                         "high compression but low quality.</p>"
127                                         "<p><b>Note: JPEG always uses lossy compression.</b></p>"));
128 
129     d->JPEGGrid->addWidget(d->labelJPEGcompression, 0, 0, 1, 2);
130     d->JPEGGrid->addWidget(d->JPEGcompression,      1, 0, 1, 2);
131     d->JPEGGrid->addWidget(d->labelSubSampling,     2, 0, 1, 2);
132     d->JPEGGrid->addWidget(d->subSamplingCB,        3, 0, 1, 2);
133     d->JPEGGrid->addWidget(d->labelWarning,         4, 0, 1, 1);
134     d->JPEGGrid->setColumnStretch(1, 10);
135     d->JPEGGrid->setRowStretch(5, 10);
136     d->JPEGGrid->setContentsMargins(spacing, spacing, spacing, spacing);
137     d->JPEGGrid->setSpacing(spacing);
138 
139     connect(d->JPEGcompression, SIGNAL(valueChanged(int)),
140             this, SIGNAL(signalSettingsChanged()));
141 
142     connect(d->subSamplingCB, SIGNAL(activated(int)),
143             this, SIGNAL(signalSettingsChanged()));
144 }
145 
~JPEGSettings()146 JPEGSettings::~JPEGSettings()
147 {
148     delete d;
149 }
150 
setCompressionValue(int val)151 void JPEGSettings::setCompressionValue(int val)
152 {
153     d->JPEGcompression->setValue(val);
154 }
155 
getCompressionValue() const156 int JPEGSettings::getCompressionValue() const
157 {
158     return d->JPEGcompression->value();
159 }
160 
setSubSamplingValue(int val)161 void JPEGSettings::setSubSamplingValue(int val)
162 {
163     d->subSamplingCB->setCurrentIndex(val);
164 }
165 
getSubSamplingValue() const166 int JPEGSettings::getSubSamplingValue() const
167 {
168     return d->subSamplingCB->currentIndex();
169 }
170 
convertCompressionForLibJpeg(int value)171 int JPEGSettings::convertCompressionForLibJpeg(int value)
172 {
173     // JPEG quality slider settings : 1 - 100 ==> libjpeg settings : 25 - 100.
174 
175     return ((int)((75.0 / 100.0) * (float)value + 26.0 - (75.0 / 100.0)));
176 }
177 
178 } // namespace Digikam
179