File indexing completed on 2024-05-12 04:19:35

0001 /*
0002 Gwenview: an image viewer
0003 Copyright 2000-2004 Aurélien Gâteau <agateau@kde.org>
0004 Copyright 2022 Ilya Pominov <ipominov@astralinux.ru>
0005 
0006 This program is free software; you can redistribute it and/or
0007 modify it under the terms of the GNU General Public License
0008 as published by the Free Software Foundation; either version 2
0009 of the License, or (at your option) any later version.
0010 
0011 This program is distributed in the hope that it will be useful,
0012 but WITHOUT ANY WARRANTY; without even the implied warranty of
0013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014 GNU General Public License for more details.
0015 
0016 You should have received a copy of the GNU General Public License
0017 along with this program; if not, write to the Free Software
0018 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
0019 
0020 */
0021 #include "imageutils.h"
0022 
0023 #include <cmath>
0024 
0025 namespace Gwenview
0026 {
0027 namespace ImageUtils
0028 {
0029 inline int changeBrightness(int value, int brightness)
0030 {
0031     return qBound(0, value + brightness * 255 / 100, 255);
0032 }
0033 
0034 inline int changeContrast(int value, int contrast)
0035 {
0036     return qBound(0, ((value - 127) * contrast / 100) + 127, 255);
0037 }
0038 
0039 inline int changeGamma(int value, int gamma)
0040 {
0041     return qBound(0, int(pow(value / 255.0, 100.0 / gamma) * 255), 255);
0042 }
0043 
0044 inline int changeUsingTable(int value, const int table[])
0045 {
0046     return table[value];
0047 }
0048 
0049 /*
0050  Applies either brightness, contrast or gamma conversion on the image.
0051  If the image is not truecolor, the color table is changed. If it is
0052  truecolor, every pixel has to be changed. In order to make it as fast
0053  as possible, alpha value is converted only if necessary. Additionally,
0054  since color components (red/green/blue/alpha) can have only 256 values
0055  but images usually have many pixels, a conversion table is first
0056  created for every color component value, and pixels are converted
0057  using this table.
0058 */
0059 
0060 template<int operation(int, int)>
0061 static QImage changeImage(const QImage &image, int value)
0062 {
0063     QImage im = image;
0064     im.detach();
0065     if (im.colorCount() == 0) { /* truecolor */
0066         if (im.depth() != 32) { /* just in case */
0067             // im = im.convertDepth( 32 ); in old version
0068             im.convertTo(im.hasAlphaChannel() ? QImage::Format_ARGB32 : QImage::Format_RGB32);
0069         }
0070         int table[256];
0071         for (int i = 0; i < 256; ++i) {
0072             table[i] = operation(i, value);
0073         }
0074         if (im.hasAlphaChannel()) {
0075             for (int y = 0; y < im.height(); ++y) {
0076                 QRgb *line = reinterpret_cast<QRgb *>(im.scanLine(y));
0077                 for (int x = 0; x < im.width(); ++x) {
0078                     line[x] = qRgba(changeUsingTable(qRed(line[x]), table),
0079                                     changeUsingTable(qGreen(line[x]), table),
0080                                     changeUsingTable(qBlue(line[x]), table),
0081                                     changeUsingTable(qAlpha(line[x]), table));
0082                 }
0083             }
0084         } else {
0085             for (int y = 0; y < im.height(); ++y) {
0086                 QRgb *line = reinterpret_cast<QRgb *>(im.scanLine(y));
0087                 for (int x = 0; x < im.width(); ++x) {
0088                     line[x] = qRgb(changeUsingTable(qRed(line[x]), table), changeUsingTable(qGreen(line[x]), table), changeUsingTable(qBlue(line[x]), table));
0089                 }
0090             }
0091         }
0092     } else {
0093         auto colors = im.colorTable();
0094         for (int i = 0; i < im.colorCount(); ++i) {
0095             colors[i] = qRgb(operation(qRed(colors[i]), value), operation(qGreen(colors[i]), value), operation(qBlue(colors[i]), value));
0096         }
0097     }
0098     return im;
0099 }
0100 
0101 // brightness is multiplied by 100 in order to avoid floating point numbers
0102 QImage changeBrightness(const QImage &image, int brightness)
0103 {
0104     if (brightness == 0) { // no change
0105         return image;
0106     }
0107     return changeImage<changeBrightness>(image, brightness);
0108 }
0109 
0110 // contrast is multiplied by 100 in order to avoid floating point numbers
0111 QImage changeContrast(const QImage &image, int contrast)
0112 {
0113     if (contrast == 100) { // no change
0114         return image;
0115     }
0116     return changeImage<changeContrast>(image, contrast);
0117 }
0118 
0119 // gamma is multiplied by 100 in order to avoid floating point numbers
0120 QImage changeGamma(const QImage &image, int gamma)
0121 {
0122     if (gamma == 100) { // no change
0123         return image;
0124     }
0125     return changeImage<changeGamma>(image, gamma);
0126 }
0127 
0128 } // Namespace
0129 } // Namespace