diff --git a/core/libs/dimg/dcolor.cpp b/core/libs/dimg/dcolor.cpp index 52a40d108f..5eb60ad3a2 100644 --- a/core/libs/dimg/dcolor.cpp +++ b/core/libs/dimg/dcolor.cpp @@ -1,400 +1,406 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2005-12-02 * Description : 8-16 bits color container. * * Copyright (C) 2005-2020 by Gilles Caulier * * RGB<->HLS transformation algorithms are inspired from methods * describe at this url : * http://www.paris-pc-gis.com/MI_Enviro/Colors/color_models.htm * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "dcolor.h" -#include "digikam_globals.h" // Local includes +#include "digikam_globals.h" #include "digikam_debug.h" namespace Digikam { DColor::DColor(const QColor& color, bool sixteenBit) + : m_alpha(255), + m_sixteenBit(false) { // initialize as eight bit if (color.isValid()) { m_red = color.red(); m_green = color.green(); m_blue = color.blue(); } else { qCDebug(DIGIKAM_DIMG_LOG) << "QColor is invalid. reset color component to zero"; m_red = 0; m_green = 0; m_blue = 0; } - m_alpha = 255; - m_sixteenBit = false; // convert to sixteen bit if requested if (sixteenBit) { convertToSixteenBit(); } } QColor DColor::getQColor() const { if (m_sixteenBit) { DColor eightBit(*this); eightBit.convertToEightBit(); + return eightBit.getQColor(); } return QColor(m_red, m_green, m_blue); } void DColor::convertToSixteenBit() { if (m_sixteenBit) { return; } m_red = (m_red + 1) * 256 - 1; m_green = (m_green + 1) * 256 - 1; m_blue = (m_blue + 1) * 256 - 1; m_alpha = (m_alpha + 1) * 256 - 1; m_sixteenBit = true; } void DColor::convertToEightBit() { if (!m_sixteenBit) { return; } m_red = (m_red + 1) / 256 - 1; m_green = (m_green + 1) / 256 - 1; m_blue = (m_blue + 1) / 256 - 1; m_alpha = (m_alpha + 1) / 256 - 1; m_sixteenBit = false; } void DColor::getHSL(int* const h, int* const s, int* const l) const { double min; double max; double red; double green; double blue; double sum; double hue, sat, lig; double range = m_sixteenBit ? 65535.0 : 255.0; red = m_red / range; green = m_green / range; blue = m_blue / range; if (red > green) { if (red > blue) { max = red; } else { max = blue; } if (green < blue) { min = green; } else { min = blue; } } else { if (green > blue) { max = green; } else { max = blue; } if (red < blue) { min = red; } else { min = blue; } } sum = max + min; lig = sum / 2; sat = 0; hue = 0; if (max != min) { double delta = max - min; if (lig <= 0.5) { sat = delta / sum; } else { sat = delta / (2 - sum); } if (red == max) { hue = (green - blue) / delta; } else if (green == max) { hue = 2 + (blue - red) / delta; } else if (blue == max) { hue = 4 + (red - green) / delta; } if (hue < 0) { hue += 6; } if (hue > 6) { hue -= 6; } hue *= 60; } *h = lround(hue * range / 360.0); *s = lround(sat * range); *l = lround(lig * range); } void DColor::setHSL(int h, int s, int l, bool sixteenBit) { double range = m_sixteenBit ? 65535.0 : 255.0; if (s == 0) { m_red = l; m_green = l; m_blue = l; } else { - double r, g, b, m2; + double r; + double g; + double b; + double m2; double hue = (double)(h * 360.0 / range); double lightness = (double)(l / range); double saturation = (double)(s / range); if (lightness <= 0.5) { m2 = lightness * (1 + saturation); } else { m2 = lightness + saturation - lightness * saturation; } double m1 = 2 * lightness - m2; double mh; mh = hue + 120; while (mh > 360) { mh -= 360; } while (mh < 0) { mh += 360; } if (mh < 60) { r = m1 + (m2 - m1) * mh / 60; } else if (mh < 180) { r = m2; } else if (mh < 240) { r = m1 + (m2 - m1) * (240 - mh) / 60; } else { r = m1; } mh = hue; while (mh > 360) { mh -= 360; } while (mh < 0) { mh += 360; } if (mh < 60) { g = m1 + (m2 - m1) * mh / 60; } else if (mh < 180) { g = m2; } else if (mh < 240) { g = m1 + (m2 - m1) * (240 - mh) / 60; } else { g = m1; } mh = hue - 120; while (mh > 360) { mh -= 360; } while (mh < 0) { mh += 360; } if (mh < 60) { b = m1 + (m2 - m1) * mh / 60; } else if (mh < 180) { b = m2; } else if (mh < 240) { b = m1 + (m2 - m1) * (240 - mh) / 60; } else { b = m1; } m_red = lround(r * range); m_green = lround(g * range); m_blue = lround(b * range); } m_sixteenBit = sixteenBit; // Fully opaque color. + if (m_sixteenBit) { m_alpha = 65535; } else { m_alpha = 255; } } void DColor::getYCbCr(double* const y, double* const cb, double* const cr) const { double r = m_red / (m_sixteenBit ? 65535.0 : 255.0); double g = m_green / (m_sixteenBit ? 65535.0 : 255.0); double b = m_blue / (m_sixteenBit ? 65535.0 : 255.0); *y = 0.2990 * r + 0.5870 * g + 0.1140 * b; *cb = -0.1687 * r - 0.3313 * g + 0.5000 * b + 0.5; *cr = 0.5000 * r - 0.4187 * g - 0.0813 * b + 0.5; } void DColor::setYCbCr(double y, double cb, double cr, bool sixteenBit) { double r = y + 1.40200 * (cr - 0.5); double g = y - 0.34414 * (cb - 0.5) - 0.71414 * (cr - 0.5); double b = y + 1.77200 * (cb - 0.5); double q = (sixteenBit ? 65535.0 : 255.0); m_red = CLAMP((int)lround(r * q), 0, (int)q); m_green = CLAMP((int)lround(g * q), 0, (int)q); m_blue = CLAMP((int)lround(b * q), 0, (int)q); m_sixteenBit = sixteenBit; // Fully opaque color. + if (m_sixteenBit) { m_alpha = 65535; } else { m_alpha = 255; } } /* DColor::DColor(const DColor& color) { m_red = color.m_red; m_green = color.m_green; m_blue = color.m_blue; m_alpha = color.m_alpha; m_sixteenBit = color.m_sixteenBit; } DColor& DColor::operator=(const DColor& color) { m_red = color.m_red; m_green = color.m_green; m_blue = color.m_blue; m_alpha = color.m_alpha; m_sixteenBit = color.m_sixteenBit; return *this; } */ } // namespace Digikam diff --git a/core/libs/dimg/dcolor.h b/core/libs/dimg/dcolor.h index 2a5a5b50b8..8f7e82195c 100644 --- a/core/libs/dimg/dcolor.h +++ b/core/libs/dimg/dcolor.h @@ -1,235 +1,249 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2005-12-02 * Description : 8-16 bits color container. * * Copyright (C) 2005-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_DCOLOR_H #define DIGIKAM_DCOLOR_H // C++ includes #include // Qt includes #include // Local includes #include "digikam_export.h" namespace Digikam { class DIGIKAM_EXPORT DColor { public: - /** Initialize with default value, fully transparent eight bit black + /** + * Initialize with default value, fully transparent eight bit black */ DColor() : m_red(0), m_green(0), m_blue(0), m_alpha(0), m_sixteenBit(false) { }; - /** Read value from data. Equivalent to setColor() + /** + * Read value from data. Equivalent to setColor() */ explicit DColor(uchar* data, bool sixteenBit = false) { setColor(data, sixteenBit); } - /** Initialize with given RGBA values + /** + * Initialize with given RGBA values */ DColor(int red, int green, int blue, int alpha, bool sixteenBit) : m_red(red), m_green(green), m_blue(blue), m_alpha(alpha), m_sixteenBit(sixteenBit) { }; - /** Read values from QColor, convert to sixteenBit of sixteenBit is true + /** + * Read values from QColor, convert to sixteenBit of sixteenBit is true */ explicit DColor(const QColor& color, bool sixteenBit=false); // Use default copy constructor, assignment operator and destructor - /** Read color values as RGBA from the given memory location. - If sixteenBit is false, 4 bytes are read. - If sixteenBit is true, 8 bytes are read. - Inline method. + /** + * Read color values as RGBA from the given memory location. + * If sixteenBit is false, 4 bytes are read. + * If sixteenBit is true, 8 bytes are read. + * Inline method. */ inline void setColor(uchar* const data, bool sixteenBit = false); - /** Write the values of this color to the given memory location. - If sixteenBit is false, 4 bytes are written. - If sixteenBit is true, 8 bytes are written. - Inline method. - */ + /** + * Write the values of this color to the given memory location. + * If sixteenBit is false, 4 bytes are written. + * If sixteenBit is true, 8 bytes are written. + * Inline method. + */ inline void setPixel(uchar* const data) const; - int red () const + int red() const { return m_red; } - int green() const + int green() const { return m_green; } - int blue () const + int blue() const { return m_blue; } - int alpha() const + int alpha() const { return m_alpha; } - bool sixteenBit() const + bool sixteenBit() const { return m_sixteenBit; } - void setRed (int red) + void setRed(int red) { m_red = red; } void setGreen(int green) { m_green = green; } void setBlue (int blue) { m_blue = blue; } void setAlpha(int alpha) { m_alpha = alpha; } void setSixteenBit(bool sixteenBit) { m_sixteenBit = sixteenBit; } QColor getQColor() const; inline bool isPureGrayValue(int v) { - return (m_red == v && m_green == v && m_blue == v); + return ((m_red == v) && (m_green == v) && (m_blue == v)); }; inline bool isPureGray() { - return ( (m_red == m_green) && (m_red == m_blue) ); + return ((m_red == m_green) && (m_red == m_blue)); }; - /** Convert the color values of this color to and from sixteen bit - and set the sixteenBit value accordingly - */ + /** + * Convert the color values of this color to and from sixteen bit + * and set the sixteenBit value accordingly + */ void convertToSixteenBit(); void convertToEightBit(); - /** Premultiply and demultiply this color. - DImg stores the color non-premultiplied. - Inline methods. - */ + /** + * Premultiply and demultiply this color. + * DImg stores the color non-premultiplied. + * Inline methods. + */ void premultiply(); void demultiply(); - /** Return the current RGB color values of this color - in the HSL color space. - Alpha is ignored for the conversion. - */ + /** + * Return the current RGB color values of this color + * in the HSL color space. + * Alpha is ignored for the conversion. + */ void getHSL(int* const h, int* const s, int* const l) const; - /** Set the RGB color values of this color - to the given HSL values converted to RGB. - Alpha is set to be fully opaque. - sixteenBit determines both how the HSL values are interpreted - and the sixteenBit value of this color after this operation. - */ + /** + * Set the RGB color values of this color + * to the given HSL values converted to RGB. + * Alpha is set to be fully opaque. + * sixteenBit determines both how the HSL values are interpreted + * and the sixteenBit value of this color after this operation. + */ void setHSL(int h, int s, int l, bool sixteenBit); - /** Return the current RGB color values of this color - in the YCrCb color space. - Alpha is ignored for the conversion. - */ + /** + * Return the current RGB color values of this color + * in the YCrCb color space. + * Alpha is ignored for the conversion. + */ void getYCbCr(double* const y, double* const cb, double* const cr) const; - /** Set the RGB color values of this color - to the given YCrCb values converted to RGB. - Alpha is set to be fully opaque. - sixteenBit determines both how the YCrCb values are interpreted - and the sixteenBit value of this color after this operation. - */ + /** + * Set the RGB color values of this color + * to the given YCrCb values converted to RGB. + * Alpha is set to be fully opaque. + * sixteenBit determines both how the YCrCb values are interpreted + * and the sixteenBit value of this color after this operation. + */ void setYCbCr(double y, double cb, double cr, bool sixteenBit); private: int m_red; int m_green; int m_blue; int m_alpha; bool m_sixteenBit; public: - // Inline alpha blending helper functions. - // These functions are used by DColorComposer. - // Look at that code to learn how to use them for - // composition if you want to use them in optimized code. + /** + * Inline alpha blending helper functions. + * These functions are used by DColorComposer. + * Look at that code to learn how to use them for + * composition if you want to use them in optimized code. + */ inline void blendZero(); inline void blendAlpha8(int alpha); inline void blendInvAlpha8(int alpha); inline void blendAlpha16(int alpha); inline void blendInvAlpha16(int alpha); inline void premultiply16(int alpha); inline void premultiply8(int alpha); inline void demultiply16(int alpha); inline void demultiply8(int alpha); inline void blendAdd(const DColor& src); inline void blendClamp8(); inline void blendClamp16(); inline void multiply(float factor); }; } // namespace Digikam // Inline methods #include "dcolorpixelaccess.h" #include "dcolorblend.h" #endif // DIGIKAM_DCOLOR_H diff --git a/core/libs/dimg/dcolorblend.h b/core/libs/dimg/dcolorblend.h index 97d2173eec..a7e354eb28 100644 --- a/core/libs/dimg/dcolorblend.h +++ b/core/libs/dimg/dcolorblend.h @@ -1,219 +1,212 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2006-03-01 * Description : DColor methods for blending + * Integer arithmetic inspired by DirectFB, + * src/gfx/generic/generic.c and src/display/idirectfbsurface.c * * Copyright (C) 2006-2009 by Marcel Wiesweg + * Copyright (C) 2000-2002 by convergence integrated media GmbH + * Copyright (C) 2002-2005 by Denis Oliver Kropp + * Copyright (C) 2002-2005 by Andreas Hundt + * Copyright (C) 2002-2005 by Sven Neumann + * Copyright (C) 2002-2005 by Ville Syrj + * Copyright (C) 2002-2005 by Claudio Ciccani * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ -/* - Inspired by DirectFB, src/gfx/generic/generic.c: - - (c) Copyright 2000-2002 convergence integrated media GmbH - (c) Copyright 2002-2005 convergence GmbH. - - All rights reserved. - - Written by Denis Oliver Kropp , - Andreas Hundt , - Sven Neumann , - Ville Syrjala and - Claudio Ciccani . -*/ - #ifndef DIGIKAM_DCOLOR_BLEND_H #define DIGIKAM_DCOLOR_BLEND_H namespace Digikam { inline void DColor::premultiply() { if (sixteenBit()) { premultiply16(alpha()); } else { premultiply8(alpha()); } } inline void DColor::demultiply() { if (sixteenBit()) { demultiply16(alpha()); blendClamp16(); } else { demultiply8(alpha()); blendClamp8(); } } inline void DColor::blendZero() { setAlpha(0); setRed(0); setGreen(0); setBlue(0); } inline void DColor::blendAlpha16(int alphaValue) { uint Sa = alphaValue + 1; setRed ((Sa * (uint)red()) >> 16); setGreen((Sa * (uint)green()) >> 16); setBlue ((Sa * (uint)blue()) >> 16); setAlpha((Sa * (uint)alpha()) >> 16); } inline void DColor::blendAlpha8(int alphaValue) { uint Sa = alphaValue + 1; setRed ((Sa * red()) >> 8); setGreen((Sa * green()) >> 8); setBlue ((Sa * blue()) >> 8); setAlpha((Sa * alpha()) >> 8); } inline void DColor::blendInvAlpha16(int alphaValue) { uint Sa = 65536 - alphaValue; setRed ((Sa * (uint)red()) >> 16); setGreen((Sa * (uint)green()) >> 16); setBlue ((Sa * (uint)blue()) >> 16); setAlpha((Sa * (uint)alpha()) >> 16); } inline void DColor::blendInvAlpha8(int alphaValue) { uint Sa = 256 - alphaValue; setRed ((Sa * red()) >> 8); setGreen((Sa * green()) >> 8); setBlue ((Sa * blue()) >> 8); setAlpha((Sa * alpha()) >> 8); } inline void DColor::premultiply16(int alphaValue) { uint Da = alphaValue + 1; setRed ((Da * (uint)red()) >> 16); setGreen((Da * (uint)green()) >> 16); setBlue ((Da * (uint)blue()) >> 16); } inline void DColor::premultiply8(int alphaValue) { uint Da = alphaValue + 1; setRed ((Da * red()) >> 8); setGreen((Da * green()) >> 8); setBlue ((Da * blue()) >> 8); } inline void DColor::demultiply16(int alphaValue) { uint Da = alphaValue + 1; setRed (((uint)red() << 16) / Da); setGreen(((uint)green() << 16) / Da); setBlue (((uint)blue() << 16) / Da); } inline void DColor::demultiply8(int alphaValue) { uint Da = alphaValue + 1; setRed ((red() << 8) / Da); setGreen((green() << 8) / Da); setBlue ((blue() << 8) / Da); } inline void DColor::blendAdd(const DColor& src) { setRed (red() + src.red()); setGreen(green() + src.green()); setBlue (blue() + src.blue()); setAlpha(alpha() + src.alpha()); } inline void DColor::blendClamp16() { if (0xFFFF0000 & red()) { setRed(65535); } if (0xFFFF0000 & green()) { setGreen(65535); } if (0xFFFF0000 & blue()) { setBlue(65535); } if (0xFFFF0000 & alpha()) { setAlpha(65535); } } inline void DColor::blendClamp8() { if (0xFFFFFF00 & red()) { setRed(255); } if (0xFFFFFF00 & green()) { setGreen(255); } if (0xFFFFFF00 & blue()) { setBlue(255); } if (0xFFFFFF00 & alpha()) { setAlpha(255); } } inline void DColor::multiply(float factor) { setRed(lround( red() * factor )); setGreen(lround( green() * factor )); setBlue(lround( blue() * factor )); setAlpha(lround( alpha() * factor )); } } // namespace Digikam #endif // DIGIKAM_DCOLOR_BLEND_H diff --git a/core/libs/dimg/dimg.cpp b/core/libs/dimg/dimg.cpp index b559332186..76d4081c93 100644 --- a/core/libs/dimg/dimg.cpp +++ b/core/libs/dimg/dimg.cpp @@ -1,192 +1,193 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2005-06-14 * Description : digiKam 8/16 bits image management API. * Contructors and destructor. * * Copyright (C) 2005 by Renchi Raju * Copyright (C) 2005-2020 by Gilles Caulier * Copyright (C) 2006-2013 by Marcel Wiesweg * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "dimg_p.h" namespace Digikam { /** * * DImg is a framework to support 16bits color depth image. it doesn't aim * to be a complete imaging library; it uses QImage/ImageMagick for * load/save files which are not supported natively by it. * some of the features: * * - Native Image Loaders, for some imageformats which are of interest to * us: JPEG (complete), TIFF (mostly complete), PNG (complete), JPEG2000 * (complete), RAW (complete through libraw), PGF (complete). * For the rest ImageMAgick codecs or qimageloader are used. * * - Metadata preservation: when a file is loaded, its metadata like XMP, * IPTC, EXIF, JFIF are read and held in memory. now when you save back the * file to the original file or to a different file, the metadata is * automatically written. All is delegate to Exiv2 library. * * - Explicitly Shared Container format (see qt docs): this is necessary for * performance reasons. * * - 8 bits and 16 bits support: if the file format is 16 bits, it will load up * the image in 16bits format (TIFF/PNG/JPEG2000/RAW/PGF support) and all * operations are done in 16 bits format, except when the rendering to screen * is done, when its converted on the fly to a temporary 8 bits image and then * rendered. * * - Basic image manipulation: rotate, flip, color modifications, crop, * scale. This has been ported from Imlib2 with 16 bits scaling support * and support for scaling of only a section of the image. * * - Rendering to Pixmap: using QImage/QPixmap. (see above for rendering of * 16 bits images). * * - Pixel format: the pixel format is different from QImage pixel * format. In QImage the pixel data is stored as unsigned ints and to * access the individual colors you need to use bit-shifting to ensure * endian correctness. in DImg, the pixel data is stored as unsigned char. * the color layout is B,G,R,A (blue, green, red, alpha) * * for 8 bits images: you can access individual color components like this: * * uchar* const pixels = image.bits(); * * for (int i = 0 ; i < image.width() * image.height() ; ++i) * { * pixel[0] // blue * pixel[1] // green * pixel[2] // red * pixel[3] // alpha * * pixel += 4; // go to next pixel * } * * and for 16 bits images: * * ushort* const pixels = (ushort*)image.bits(); * * for (int i = 0 ; i < image.width() * image.height() ; ++i) * { * pixel[0] // blue * pixel[1] // green * pixel[2] // red * pixel[3] // alpha * * pixel += 4; // go to next pixel * } * * The above is true for both big and little endian platforms. What this also * means is that the pixel format is different from that of QImage for big * endian machines. Functions are provided if you want to get a copy of the * DImg as a QImage. * */ DImg::DImg() : m_priv(new Private) { } DImg::DImg(const QByteArray& filePath, DImgLoaderObserver* const observer, const DRawDecoding& rawDecodingSettings) : m_priv(new Private) { load(QString::fromUtf8(filePath), observer, rawDecodingSettings); } DImg::DImg(const QString& filePath, DImgLoaderObserver* const observer, const DRawDecoding& rawDecodingSettings) : m_priv(new Private) { load(filePath, observer, rawDecodingSettings); } DImg::DImg(const DImg& image) : m_priv(image.m_priv) { } DImg::DImg(uint width, uint height, bool sixteenBit, bool alpha, uchar* const data, bool copyData) : m_priv(new Private) { putImageData(width, height, sixteenBit, alpha, data, copyData); } DImg::DImg(const DImg& image, int w, int h) : m_priv(new Private) { - // This private constructor creates a copy of everything except the data. - // The image size is set to the given values and a buffer corresponding to these values is allocated. - // This is used by copy and scale. + /** + * This private constructor creates a copy of everything except the data. + * The image size is set to the given values and a buffer corresponding to these values is allocated. + * This is used by copy and scale. + */ copyImageData(image.m_priv); copyMetaData(image.m_priv); setImageDimension(w, h); allocateData(); } DImg::DImg(const QImage& image) : m_priv(new Private) { if (!image.isNull()) { QImage target; - if (image.format() == QImage::Format_RGB32 || image.format() == QImage::Format_ARGB32) + if ((image.format() == QImage::Format_RGB32) || (image.format() == QImage::Format_ARGB32)) { target = image; } else { target = image.convertToFormat(QImage::Format_ARGB32); } setImageData(true, image.width(), image.height(), false, image.hasAlphaChannel()); if (allocateData()) { uint* sptr = reinterpret_cast(target.bits()); uchar* dptr = m_priv->data; const uint pixels = numPixels(); for (uint i = 0 ; i < pixels ; ++i) { dptr[0] = qBlue(*sptr); dptr[1] = qGreen(*sptr); dptr[2] = qRed(*sptr); dptr[3] = qAlpha(*sptr); - - dptr += 4; + dptr += 4; ++sptr; } } } } DImg::~DImg() { } } // namespace Digikam diff --git a/core/libs/dimg/dimg.h b/core/libs/dimg/dimg.h index d44973372e..398cf41994 100644 --- a/core/libs/dimg/dimg.h +++ b/core/libs/dimg/dimg.h @@ -1,731 +1,799 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2005-06-14 * Description : digiKam 8/16 bits image management API * * Copyright (C) 2005 by Renchi Raju * Copyright (C) 2005-2020 by Gilles Caulier * Copyright (C) 2006-2013 by Marcel Wiesweg * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_DIMG_H #define DIGIKAM_DIMG_H // Qt includes #include #include #include #include #include #include #include // Local includes #include "digikam_export.h" #include "drawdecoding.h" #include "dcolor.h" #include "dcolorcomposer.h" #include "historyimageid.h" #include "iccprofile.h" #include "metaengine_data.h" class QImage; class QPixmap; namespace Digikam { class ExposureSettingsContainer; class DImageHistory; class FilterAction; class IccTransform; class DImgLoaderObserver; class DIGIKAM_EXPORT DImg { public: enum FORMAT { - // NOTE: Order is important here: - // See filesaveoptionbox.cpp which use these values to fill a stack of widgets. + /** + * NOTE: Order is important here: + * See filesaveoptionbox.cpp which use these values to fill a stack of widgets. + */ NONE = 0, JPEG, PNG, TIFF, JP2K, PGF, HEIF, // Others file formats. RAW, - QIMAGE // QImage or ImageMagick + QIMAGE ///< QImage or ImageMagick }; enum ANGLE { ROT90 = 0, ROT180, ROT270, ROTNONE }; enum FLIP { HORIZONTAL = 0, VERTICAL }; enum COLORMODEL { COLORMODELUNKNOWN = 0, RGB, GRAYSCALE, MONOCHROME, INDEXED, YCBCR, CMYK, CIELAB, COLORMODELRAW }; public: - /** Identify file format + /** + * Identify file format */ static FORMAT fileFormat(const QString& filePath); static QString formatToMimeType(FORMAT frm); public: class Private; public: - /** Create null image + /** + * Create null image */ DImg(); - /** Load image using QByteArray as file path + /** + * Load image using QByteArray as file path */ explicit DImg(const QByteArray& filePath, DImgLoaderObserver* const observer = nullptr, const DRawDecoding& rawDecodingSettings = DRawDecoding()); - /** Load image using QString as file path + /** + * Load image using QString as file path */ explicit DImg(const QString& filePath, DImgLoaderObserver* const observer = nullptr, const DRawDecoding& rawDecodingSettings = DRawDecoding()); - /** Copy image: Creates a shallow copy that refers to the same shared data. - The two images will be equal. Call detach() or copy() to create deep copies. + /** + * Copy image: Creates a shallow copy that refers to the same shared data. + * The two images will be equal. Call detach() or copy() to create deep copies. */ DImg(const DImg& image); - /** Copy image: Creates a copy of a QImage object. If the QImage is null, a - null DImg will be created. + /** + * Copy image: Creates a copy of a QImage object. If the QImage is null, a + * null DImg will be created. */ explicit DImg(const QImage& image); - /** Create image from data. - If data is 0, a new buffer will be allocated, otherwise the given data will be used: - If copydata is true, the data will be copied to a newly allocated buffer. - If copyData is false, this DImg object will take ownership of the data pointer. - If there is an alpha channel, the data shall be in non-premultiplied form (unassociated alpha). + /** + * Create image from data. + * If data is 0, a new buffer will be allocated, otherwise the given data will be used: + * If copydata is true, the data will be copied to a newly allocated buffer. + * If copyData is false, this DImg object will take ownership of the data pointer. + * If there is an alpha channel, the data shall be in non-premultiplied form (unassociated alpha). */ DImg(uint width, uint height, bool sixteenBit, bool alpha = false, uchar* const data = nullptr, bool copyData = true); ~DImg(); - /** Equivalent to the copy constructor + /** + * Equivalent to the copy constructor */ DImg& operator=(const DImg& image); /** Detaches from shared data and makes sure that this image - is the only one referring to the data. - If multiple images share common data, this image makes a copy - of the data and detaches itself from the sharing mechanism. - Nothing is done if there is just a single reference. - */ + * is the only one referring to the data. + * If multiple images share common data, this image makes a copy + * of the data and detaches itself from the sharing mechanism. + * Nothing is done if there is just a single reference. + */ void detach(); /** Returns whether two images are equal. - Two images are equal if and only if they refer to the same shared data. - (Thus, DImg() == DImg() is not true, both instances refer two their - own shared data. image == DImg(image) is true.) - If two or more images refer to the same data, they have the same - image data, bits() returns the same data, they have the same metadata, - and a change to one image also affects the others. - Call detach() to split one image from the group of equal images. - */ + * Two images are equal if and only if they refer to the same shared data. + * (Thus, DImg() == DImg() is not true, both instances refer two their + * own shared data. image == DImg(image) is true.) + * If two or more images refer to the same data, they have the same + * image data, bits() returns the same data, they have the same metadata, + * and a change to one image also affects the others. + * Call detach() to split one image from the group of equal images. + */ bool operator==(const DImg& image) const; - /** Replaces image data of this object. Metadata is unchanged. Parameters like constructor above. + /** + * Replaces image data of this object. Metadata is unchanged. Parameters like constructor above. */ void putImageData(uint width, uint height, bool sixteenBit, bool alpha, uchar* const data, bool copyData = true); - /** Overloaded function, provided for convenience, behaves essentially - like the function above if data is not 0. - Uses current width, height, sixteenBit, and alpha values. - If data is 0, the current data is deleted and the image is set to null - (But metadata unchanged). + /** + * Overloaded function, provided for convenience, behaves essentially + * like the function above if data is not 0. + * Uses current width, height, sixteenBit, and alpha values. + * If data is 0, the current data is deleted and the image is set to null + * (But metadata unchanged). */ void putImageData(uchar* const data, bool copyData = true); - /** Reset metadata and image data to null image + /** + * Reset metadata and image data to null image */ void reset(); - /** Reset metadata, but do not change image data + /** + * Reset metadata, but do not change image data */ void resetMetaData(); - /** Returns the data of this image. - Ownership of the buffer is passed to the caller, this image will be null afterwards. + /** + * Returns the data of this image. + * Ownership of the buffer is passed to the caller, this image will be null afterwards. */ uchar* stripImageData(); bool load(const QString& filePath, DImgLoaderObserver* const observer = nullptr, const DRawDecoding& rawDecodingSettings = DRawDecoding()); bool load(const QString& filePath, bool loadMetadata, bool loadICCData, bool loadUniqueHash, bool loadHistory, DImgLoaderObserver* const observer = nullptr, const DRawDecoding& rawDecodingSettings = DRawDecoding()); bool load(const QString& filePath, int loadFlags, DImgLoaderObserver* const observer, const DRawDecoding& rawDecodingSettings = DRawDecoding()); bool save(const QString& filePath, FORMAT frm, DImgLoaderObserver* const observer = nullptr); bool save(const QString& filePath, const QString& format, DImgLoaderObserver* const observer = nullptr); /** * It is common that images are not directly saved to the destination path. * For this reason, save() does not call addAsReferredImage(), and the stored * save path may be wrong. * Call this method after save() with the final destination path. * This path will be stored in the image history as well. */ void imageSavedAs(const QString& savePath); - /** Loads most parts of the meta information, but never the image data. - If loadMetadata is true, the metadata will be available with getComments, getExif, getIptc, getXmp . - If loadICCData is true, the ICC profile will be available with getICCProfile. + /** + * Loads most parts of the meta information, but never the image data. + * If loadMetadata is true, the metadata will be available with getComments, getExif, getIptc, getXmp . + * If loadICCData is true, the ICC profile will be available with getICCProfile. */ bool loadItemInfo(const QString& filePath, bool loadMetadata = true, - bool loadICCData = true, bool loadUniqueHash = true, - bool loadImageHistory = true); + bool loadICCData = true, bool loadUniqueHash = true, + bool loadImageHistory = true); bool isNull() const; uint width() const; uint height() const; QSize size() const; uchar* copyBits() const; uchar* bits() const; uchar* scanLine(uint i) const; bool hasAlpha() const; bool sixteenBit() const; uint numBytes() const; uint numPixels() const; - /** Return the number of bytes depth of one pixel : 4 (non sixteenBit) or 8 (sixteen) + /** + * Return the number of bytes depth of one pixel : 4 (non sixteenBit) or 8 (sixteen) */ int bytesDepth() const; - /** Return the number of bits depth of one color component for one pixel : 8 (non sixteenBit) or 16 (sixteen) + /** + * Return the number of bits depth of one color component for one pixel : 8 (non sixteenBit) or 16 (sixteen) */ int bitsDepth() const; - /** Returns the file path from which this DImg was originally loaded. - * Returns a null string if the DImg was not loaded from a file. + /** + * Returns the file path from which this DImg was originally loaded. + * Returns a null string if the DImg was not loaded from a file. */ QString originalFilePath() const; - /** Returns the file path to which this DImg was saved. - * Returns the file path set with imageSavedAs(), if that was not called, - * save(), if that was not called, a null string. + /** + * Returns the file path to which this DImg was saved. + * Returns the file path set with imageSavedAs(), if that was not called, + * save(), if that was not called, a null string. */ QString lastSavedFilePath() const; - /** Returns the color model in which the image was stored in the file. - The color space of the loaded image data is always RGB. - */ + /** + * Returns the color model in which the image was stored in the file. + * The color space of the loaded image data is always RGB. + */ COLORMODEL originalColorModel() const; - /** Returns the bit depth (in bits per channel, e.g. 8 or 16) of the original file. + /** + * Returns the bit depth (in bits per channel, e.g. 8 or 16) of the original file. */ int originalBitDepth() const; - /** Returns the size of the original file. + /** + * Returns the size of the original file. */ QSize originalSize() const; - /** Returns the file format in form of the FORMAT enum that was detected in the load() - method. Other than the format attribute which is written by the DImgLoader, - this can include the QIMAGE or NONE values. - Returns NONE for images that have not been loaded. - For unknown image formats, a value of QIMAGE can be returned to indicate that the - QImage-based loader will have been used. To find out if this has worked, check - the return value you got from load(). + /** + * Returns the file format in form of the FORMAT enum that was detected in the load() + * method. Other than the format attribute which is written by the DImgLoader, + * this can include the QIMAGE or NONE values. + * Returns NONE for images that have not been loaded. + * For unknown image formats, a value of QIMAGE can be returned to indicate that the + * QImage-based loader will have been used. To find out if this has worked, check + * the return value you got from load(). */ FORMAT detectedFormat() const; - /** Returns the format string as written by the image loader this image was originally - loaded from. Format strings used include JPEG, PNG, TIFF, PGF, JP2K, RAW, PPM. - For images loaded with the platform QImage loader, the file suffix is used. - Returns null if this DImg was not loaded from a file, but created in memory. - */ + /** + * Returns the format string as written by the image loader this image was originally + * loaded from. Format strings used include JPEG, PNG, TIFF, PGF, JP2K, RAW, PPM. + * For images loaded with the platform QImage loader, the file suffix is used. + * Returns null if this DImg was not loaded from a file, but created in memory. + */ QString format() const; - /** Returns the format string of the format that this image was last saved to. - An image can be loaded from a file - retrieve that format with fileFormat() - and loadedFormat() - and can the multiple times be saved to different formats. - Format strings used include JPG, PGF, PNG, TIFF and JP2K. - If this file was not save, a null string is returned. - */ + /** + * Returns the format string of the format that this image was last saved to. + * An image can be loaded from a file - retrieve that format with fileFormat() + * and loadedFormat() - and can the multiple times be saved to different formats. + * Format strings used include JPG, PGF, PNG, TIFF and JP2K. + * If this file was not save, a null string is returned. + */ QString savedFormat() const; - /** Returns the DRawDecoding options that this DImg was loaded with. - * If this is not a RAW image or no options were specified, returns DRawDecoding(). + /** + * Returns the DRawDecoding options that this DImg was loaded with. + * If this is not a RAW image or no options were specified, returns DRawDecoding(). */ DRawDecoding rawDecodingSettings() const; - /** Access a single pixel of the image. - These functions add some safety checks and then use the methods from DColor. - In optimized code working directly on the data, - better use the inline methods from DColor. + /** + * Access a single pixel of the image. + * These functions add some safety checks and then use the methods from DColor. + * In optimized code working directly on the data, + * better use the inline methods from DColor. */ DColor getPixelColor(uint x, uint y) const; void setPixelColor(uint x, uint y, const DColor& color); void prepareSubPixelAccess(); DColor getSubPixelColor(float x, float y) const; DColor getSubPixelColorFast(float x, float y) const; - /** If the image has an alpha channel, check if there exist pixels - * which actually have non-opaque color, that is alpha < 1.0. - * Note that all pixels are scanned to reach a return value of "false". - * If hasAlpha() is false, always returns false. + /** + * If the image has an alpha channel, check if there exist pixels + * which actually have non-opaque color, that is alpha < 1.0. + * Note that all pixels are scanned to reach a return value of "false". + * If hasAlpha() is false, always returns false. */ bool hasTransparentPixels() const; - /** Return true if the original image file format cannot be saved. - This is depending of DImgLoader::save() implementation. For example - RAW file formats are supported by DImg using dcraw than cannot support - writing operations. + /** + * Return true if the original image file format cannot be saved. + * This is depending of DImgLoader::save() implementation. For example + * RAW file formats are supported by DImg using dcraw than cannot support + * writing operations. */ - bool isReadOnly() const; + bool isReadOnly() const; - /** Metadata manipulation methods + /** + * Metadata manipulation methods */ MetaEngineData getMetadata() const; - IccProfile getIccProfile() const; + IccProfile getIccProfile() const; void setMetadata(const MetaEngineData& data); void setIccProfile(const IccProfile& profile); void setAttribute(const QString& key, const QVariant& value); QVariant attribute(const QString& key) const; bool hasAttribute(const QString& key) const; void removeAttribute(const QString& key); void setEmbeddedText(const QString& key, const QString& text); QString embeddedText(const QString& key) const; const DImageHistory& getItemHistory() const; DImageHistory& getItemHistory(); void setItemHistory(const DImageHistory& history); bool hasImageHistory() const; DImageHistory getOriginalImageHistory() const; void addFilterAction(const FilterAction& action); - /** Sets a step in the history to constitute the beginning of a branch. - * Use setHistoryBranch() to take getOriginalImageHistory() and set the first added step as a branch. - * Use setHistoryBranchForLastSteps(n) to start the branch before the last n steps in the history. - * (Assume the history had 3 steps and you added 2, call setHistoryBranchForLastSteps(2)) - * Use setHistoryBranchAfter() if have a copy of the history before branching, - * the first added step on top of that history will be made a branch. + /** + * Sets a step in the history to constitute the beginning of a branch. + * Use setHistoryBranch() to take getOriginalImageHistory() and set the first added step as a branch. + * Use setHistoryBranchForLastSteps(n) to start the branch before the last n steps in the history. + * (Assume the history had 3 steps and you added 2, call setHistoryBranchForLastSteps(2)) + * Use setHistoryBranchAfter() if have a copy of the history before branching, + * the first added step on top of that history will be made a branch. */ void setHistoryBranchAfter(const DImageHistory& historyBeforeBranch, bool isBranch = true); void setHistoryBranchForLastSteps(int numberOfLastHistorySteps, bool isBranch = true); void setHistoryBranch(bool isBranch = true); /** * When saving, several changes to the image metadata are necessary * before it can safely be written to the new file. * This method updates the stored DMetadata object in preparation to a subsequent * call to save() with the same target file. * 'intendedDestPath' is the finally intended file name. Do not give the temporary * file name if you are going to save() to a temp file. * 'destMimeType' is destination type mime. In some cases, metadata is updated depending on this value. * 'originalFileName' is the original file's name, for simplistic history tracking in metadata. * This is completely independent from the DImageHistory framework. * For the 'flags' see below. * Not all steps are optional and can be controlled with flags. */ enum PrepareMetadataFlag { - /// A small preview can be stored in the metadata. - /// Remove old preview entries + /** + * A small preview can be stored in the metadata. + * Remove old preview entries + */ RemoveOldMetadataPreviews = 1 << 0, - /// Create a new preview from current image data. + /** + * Create a new preview from current image data. + */ CreateNewMetadataPreview = 1 << 1, - /// Set the exif orientation tag to "normal" - /// Applicable if the image data was rotated according to the tag + /** + * Set the exif orientation tag to "normal" + * Applicable if the image data was rotated according to the tag + */ ResetExifOrientationTag = 1 << 2, - /// Creates a new UUID for the image history. - /// Applicable if the file was changed. + /** + * Creates a new UUID for the image history. + * Applicable if the file was changed. + */ CreateNewImageHistoryUUID = 1 << 3, PrepareMetadataFlagsAll = RemoveOldMetadataPreviews | CreateNewMetadataPreview | ResetExifOrientationTag | CreateNewImageHistoryUUID }; Q_DECLARE_FLAGS(PrepareMetadataFlags, PrepareMetadataFlag) void prepareMetadataToSave(const QString& intendedDestPath, const QString& destMimeType, const QString& originalFileName = QString(), PrepareMetadataFlags flags = PrepareMetadataFlagsAll); - /** For convenience: Including all flags, except for ResetExifOrientationTag which can be selected. - * Uses originalFilePath() to fill the original file name. + /** + * For convenience: Including all flags, except for ResetExifOrientationTag which can be selected. + * Uses originalFilePath() to fill the original file name. */ void prepareMetadataToSave(const QString& intendedDestPath, const QString& destMimeType, bool resetExifOrientationTag); - /** Create a HistoryImageId for _this_ image _already_ saved at the given file path.*/ + /** + * Create a HistoryImageId for _this_ image _already_ saved at the given file path. + */ HistoryImageId createHistoryImageId(const QString& filePath, HistoryImageId::Type type); - /** If you have saved this DImg to filePath, and want to continue using this DImg object - * to add further changes to the image history, you can call this method to add to the image history - * a reference to the just saved image. - * First call updateMetadata(), then call save(), then call addAsReferredImage(). - * Do not call this directly after loading, before applying any changes: - * The history is correctly initialized when loading. - * If you need to insert the referred file to an entry which is not the last entry, - * which may happen if the added image was saved after this image's history was created, - * you can use insertAsReferredImage. - * The added id is returned. + /** + * If you have saved this DImg to filePath, and want to continue using this DImg object + * to add further changes to the image history, you can call this method to add to the image history + * a reference to the just saved image. + * First call updateMetadata(), then call save(), then call addAsReferredImage(). + * Do not call this directly after loading, before applying any changes: + * The history is correctly initialized when loading. + * If you need to insert the referred file to an entry which is not the last entry, + * which may happen if the added image was saved after this image's history was created, + * you can use insertAsReferredImage. + * The added id is returned. */ HistoryImageId addAsReferredImage(const QString& filePath, HistoryImageId::Type type = HistoryImageId::Intermediate); void addAsReferredImage(const HistoryImageId& id); void insertAsReferredImage(int afterHistoryStep, const HistoryImageId& otherImagesId); - /** In the history, adjusts the UUID of the ImageHistoryId of the current file. - * Call this if you have associated a UUID with this file which is not written to the metadata. - * If there is already a UUID present, read from metadata, it will not be replaced. + /** + * In the history, adjusts the UUID of the ImageHistoryId of the current file. + * Call this if you have associated a UUID with this file which is not written to the metadata. + * If there is already a UUID present, read from metadata, it will not be replaced. */ void addCurrentUniqueImageId(const QString& uuid); /** * Retrieves the Exif orientation, either from the LoadSaveThread info provider if available, * or from the metadata */ - int exifOrientation(const QString& filePath); - - /** When loaded from a file, some attributes like format and isReadOnly still depend on this - originating file. When saving in a different format to a different file, - you may wish to switch these attributes to the new file. - - fileOriginData() returns the current origin data, bundled in the returned QVariant. - - setFileOriginData() takes such a variant and adjusts the properties - - lastSavedFileOriginData() returns the origin data as if the image was loaded from - the last saved image. - - switchOriginToLastSaved is equivalent to setting origin data returned from lastSavedFileOriginData() - - Example: an image loaded from a RAW and saved to PNG will be read-only and format RAW. - After calling switchOriginToLastSaved, it will not be read-only, format will be PNG, - and rawDecodingSettings will be null. detectedFormat() will not change. - In the history, the last referred image that was added (as intermediate) is made - the new Current image. - NOTE: Set the saved image path with imageSavedAs() before! - */ + int exifOrientation(const QString& filePath); + + /** + * When loaded from a file, some attributes like format and isReadOnly still depend on this + * originating file. When saving in a different format to a different file, + * you may wish to switch these attributes to the new file. + * - fileOriginData() returns the current origin data, bundled in the returned QVariant. + * - setFileOriginData() takes such a variant and adjusts the properties + * - lastSavedFileOriginData() returns the origin data as if the image was loaded from + * the last saved image. + * - switchOriginToLastSaved is equivalent to setting origin data returned from lastSavedFileOriginData() + * + * Example: an image loaded from a RAW and saved to PNG will be read-only and format RAW. + * After calling switchOriginToLastSaved, it will not be read-only, format will be PNG, + * and rawDecodingSettings will be null. detectedFormat() will not change. + * In the history, the last referred image that was added (as intermediate) is made + * the new Current image. + * NOTE: Set the saved image path with imageSavedAs() before! + */ QVariant fileOriginData() const; void setFileOriginData(const QVariant& data); QVariant lastSavedFileOriginData() const; void switchOriginToLastSaved(); - /** Return a deep copy of full image - */ + /** + * Return a deep copy of full image + */ DImg copy() const; - /** Return a deep copy of the image, but do not include metadata. + /** + * Return a deep copy of the image, but do not include metadata. */ DImg copyImageData() const; - /** Return an image that contains a deep copy of - this image's metadata and the information associated - with the image data (width, height, hasAlpha, sixteenBit), - but no image data, i.e. isNull() is true. + /** + * Return an image that contains a deep copy of + * this image's metadata and the information associated + * with the image data (width, height, hasAlpha, sixteenBit), + * but no image data, i.e. isNull() is true. */ DImg copyMetaData() const; - /** Return a region of image + /** + * Return a region of image */ DImg copy(const QRect& rect) const; DImg copy(const QRectF& relativeRect) const; DImg copy(int x, int y, int w, int h) const; - /** Copy a region of pixels from a source image to this image. - Parameters: - sx|sy Coordinates in the source image of the rectangle to be copied - w h Width and height of the rectangle (Default, or when both are -1: whole source image) - dx|dy Coordinates in this image of the rectangle in which the region will be copied - (Default: 0|0) - The bit depth of source and destination must be identical. + /** + * Copy a region of pixels from a source image to this image. + * Parameters: + * sx|sy Coordinates in the source image of the rectangle to be copied + * w h Width and height of the rectangle (Default, or when both are -1: whole source image) + * dx|dy Coordinates in this image of the rectangle in which the region will be copied + * (Default: 0|0) + * The bit depth of source and destination must be identical. */ void bitBltImage(const DImg* const src, int dx, int dy); void bitBltImage(const DImg* const src, int sx, int sy, int dx, int dy); void bitBltImage(const DImg* const src, int sx, int sy, int w, int h, int dx, int dy); void bitBltImage(const uchar* const src, int sx, int sy, int w, int h, int dx, int dy, uint swidth, uint sheight, int sdepth); - /** Blend src image on this image (this is dest) with the specified composer - and multiplication flags. See documentation of DColorComposer for more info. - For the other arguments, see documentation of bitBltImage above. + /** + * Blend src image on this image (this is dest) with the specified composer + * and multiplication flags. See documentation of DColorComposer for more info. + * For the other arguments, see documentation of bitBltImage above. */ void bitBlendImage(DColorComposer* const composer, const DImg* const src, int sx, int sy, int w, int h, int dx, int dy, DColorComposer::MultiplicationFlags multiplicationFlags = DColorComposer::NoMultiplication); - /** For the specified region, blend this image on the given color with the specified - composer and multiplication flags. See documentation of DColorComposer for more info. - Note that the result pixel is again written to this image, which is, for the blending, source. + /** + * For the specified region, blend this image on the given color with the specified + * composer and multiplication flags. See documentation of DColorComposer for more info. + * Note that the result pixel is again written to this image, which is, for the blending, source. */ void bitBlendImageOnColor(DColorComposer* const composer, const DColor& color, int x, int y, int w, int h, DColorComposer::MultiplicationFlags multiplicationFlags = - DColorComposer::NoMultiplication); + DColorComposer::NoMultiplication); void bitBlendImageOnColor(const DColor& color, int x, int y, int w, int h); void bitBlendImageOnColor(const DColor& color); - /** QImage wrapper methods + /** + * QImage wrapper methods */ QImage copyQImage() const; QImage copyQImage(const QRect& rect) const; QImage copyQImage(const QRectF& relativeRect) const; QImage copyQImage(int x, int y, int w, int h) const; - /** Crop image to the specified region + /** + * Crop image to the specified region */ void crop(const QRect& rect); void crop(int x, int y, int w, int h); - /** Set width and height of this image, smoothScale it to the given size + /** + * Set width and height of this image, smoothScale it to the given size */ void resize(int w, int h); /** * If the image has an alpha channel and transparent pixels, * it will be blended on the specified color and the alpha channel will be removed. * This is a no-op if hasTransparentPixels() is false, but this method can be expensive, * therefore it is _not_ checked inside removeAlphaChannel(). * (the trivial hasAlpha() is checked) */ void removeAlphaChannel(const DColor& destColor); void removeAlphaChannel(); - /** Return a version of this image scaled to the specified size with the specified mode. - See QSize documentation for information on available modes + /** + * Return a version of this image scaled to the specified size with the specified mode. + * See QSize documentation for information on available modes */ DImg smoothScale(int width, int height, Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio) const; DImg smoothScale(const QSize& destSize, Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio) const; - /** Executes the same scaling as smoothScale(width, height), but from the result of this call, - * returns only the section specified by clipx, clipy, clipwidth, clipheight. - * This is thus equivalent to calling - * Dimg scaled = smoothScale(width, height); scaled.crop(clipx, clipy, clipwidth, clipheight); - * but potentially much faster. - * In smoothScaleSection, you specify the source region, here, the result region. - * It will often not be possible to find _integer_ source coordinates for a result region! + /** + * Executes the same scaling as smoothScale(width, height), but from the result of this call, + * returns only the section specified by clipx, clipy, clipwidth, clipheight. + * This is thus equivalent to calling + * Dimg scaled = smoothScale(width, height); scaled.crop(clipx, clipy, clipwidth, clipheight); + * but potentially much faster. + * In smoothScaleSection, you specify the source region, here, the result region. + * It will often not be possible to find _integer_ source coordinates for a result region! */ DImg smoothScaleClipped(int width, int height, int clipx, int clipy, int clipwidth, int clipheight) const; DImg smoothScaleClipped(const QSize& destSize, const QRect& clip) const; - /** Take the region specified by the rectangle sx|sy, width and height sw * sh, - and scale it to an image with size dw * dh + /** + * Take the region specified by the rectangle sx|sy, width and height sw * sh, + * and scale it to an image with size dw * dh */ DImg smoothScaleSection(int sx, int sy, int sw, int sh, int dw, int dh) const; DImg smoothScaleSection(const QRect& sourceRect, const QSize& destSize) const; void rotate(ANGLE angle); void flip(FLIP direction); - /** Rotates and/or flip the DImg according to the given DMetadata::Orientation, - * so that the current state is orientation and the resulting step is normal orientation. - * Returns true if the image was actually rotated or flipped (e.g. if ORIENTATION_NORMAL - * is given, returns false, because no action is taken). + /** + * Rotates and/or flip the DImg according to the given DMetadata::Orientation, + * so that the current state is orientation and the resulting step is normal orientation. + * Returns true if the image was actually rotated or flipped (e.g. if ORIENTATION_NORMAL + * is given, returns false, because no action is taken). */ bool rotateAndFlip(int orientation); - /** Reverses the previous function. + /** + * Reverses the previous function. */ bool reverseRotateAndFlip(int orientation); /** * Utility to make sure that an image is rotated according to Exif tag. * Detects if an image has previously already been rotated: You can * call this method more than one time on the same image. * Returns true if the image has actually been rotated or flipped. * Returns false if a rotation was not needed. */ bool wasExifRotated(); bool exifRotate(const QString& filePath); /** * Reverses the previous function */ bool reverseExifRotate(const QString& filePath); /** * Returns DMetadata::Orientation from rotates and/or flip the DImg */ int orientation() const; /** Rotates and/or flip the DImg according to the given transform action, - * which is a MetaEngineRotation::TransformAction. - * Returns true if the image was actually rotated or flipped. + * which is a MetaEngineRotation::TransformAction. + * Returns true if the image was actually rotated or flipped. */ bool transform(int transformAction); QPixmap convertToPixmap() const; QPixmap convertToPixmap(IccTransform& monitorICCtrans) const; - /** Return a mask image where pure white and pure black pixels are over-colored. - This way is used to identify over and under exposed pixels. + /** + * Return a mask image where pure white and pure black pixels are over-colored. + * This way is used to identify over and under exposed pixels. */ QImage pureColorMask(ExposureSettingsContainer* const expoSettings) const; - /** Convert depth of image. Depth is bytesDepth * bitsDepth. - If depth is 32, converts to 8 bits, - if depth is 64, converts to 16 bits. + /** + * Convert depth of image. Depth is bytesDepth * bitsDepth. + * If depth is 32, converts to 8 bits, + * if depth is 64, converts to 16 bits. */ void convertDepth(int depth); - /** Wrapper methods for convertDepth + /** + * Wrapper methods for convertDepth */ void convertToSixteenBit(); void convertToEightBit(); void convertToDepthOfImage(const DImg* const otherImage); - /** Fill whole image with specified color. - The bit depth of the color must be identical to the depth of this image. + /** + * Fill whole image with specified color. + * The bit depth of the color must be identical to the depth of this image. */ void fill(const DColor& color); - - /** This methods return a 128-bit MD5 hex digest which is meant to uniquely identify - the file. The hash is calculated on parts of the file and the file metadata. - It cannot be used to find similar images. It is not calculated from the image data. - The hash will be returned as a 32-byte hexadecimal string. - - If you already have a DImg object of the file, use the member method. - The object does not need to have the full image data loaded, but it shall at least - have been loaded with loadItemInfo with loadMetadata = true, or have the metadata - set later with setComments, setExif, setIptc, setXmp. - If the object does not have the metadata loaded, a non-null, but invalid hash will - be returned! In this case, use the static method. - If the image has been loaded with loadUniqueHash = true, the hash can be retrieved - with the member method. - - You do not need a DImg object of the file to retrieve the unique hash; - Use the static method and pass just the file path. + /** + * This methods return a 128-bit MD5 hex digest which is meant to uniquely identify + * the file. The hash is calculated on parts of the file and the file metadata. + * It cannot be used to find similar images. It is not calculated from the image data. + * The hash will be returned as a 32-byte hexadecimal string. + * + * If you already have a DImg object of the file, use the member method. + * The object does not need to have the full image data loaded, but it shall at least + * have been loaded with loadItemInfo with loadMetadata = true, or have the metadata + * set later with setComments, setExif, setIptc, setXmp. + * If the object does not have the metadata loaded, a non-null, but invalid hash will + * be returned! In this case, use the static method. + * If the image has been loaded with loadUniqueHash = true, the hash can be retrieved + * with the member method. + * + * You do not need a DImg object of the file to retrieve the unique hash; + * Use the static method and pass just the file path. */ QByteArray getUniqueHash(); static QByteArray getUniqueHash(const QString& filePath); - /** This methods return a 128-bit MD5 hex digest which is meant to uniquely identify - the file. The hash is calculated on parts of the file. - It cannot be used to find similar images. It is not calculated from the image data. - The hash will be returned as a 32-byte hexadecimal string. - - If you already have a DImg object loaded from the file, use the member method. - If the image has been loaded with loadUniqueHash = true, the hash will already - be available. - - You do not need a DImg object of the file to retrieve the unique hash; - Use the static method and pass just the file path. + /** + * This methods return a 128-bit MD5 hex digest which is meant to uniquely identify + * the file. The hash is calculated on parts of the file. + * It cannot be used to find similar images. It is not calculated from the image data. + * The hash will be returned as a 32-byte hexadecimal string. + * + * If you already have a DImg object loaded from the file, use the member method. + * If the image has been loaded with loadUniqueHash = true, the hash will already + * be available. + * + * You do not need a DImg object of the file to retrieve the unique hash; + * Use the static method and pass just the file path. */ QByteArray getUniqueHashV2(); static QByteArray getUniqueHashV2(const QString& filePath); - /** This method creates a new 256-bit UUID meant to be globally unique. - * The UUID will be returned as a 64-byte hexadecimal string. - * At least 128bits of the UUID will be created by the platform random number - * generator. The rest may be created from a content-based hash similar to the uniqueHash, see above. - * This method only generates a new UUID for this image without in any way changing this image object - * or saving the UUID anywhere. + /** + * This method creates a new 256-bit UUID meant to be globally unique. + * The UUID will be returned as a 64-byte hexadecimal string. + * At least 128bits of the UUID will be created by the platform random number + * generator. The rest may be created from a content-based hash similar to the uniqueHash, see above. + * This method only generates a new UUID for this image without in any way changing this image object + * or saving the UUID anywhere. */ QByteArray createImageUniqueId(); /** * Helper method to translate enum values to user presentable strings */ static QString colorModelToString(COLORMODEL colorModel); - /** Return true if image file is an animation, as GIFa or NMG + /** + * Return true if image file is an animation, as GIFa or NMG */ static bool isAnimatedImage(const QString& filePath); private: DImg(const DImg& image, int w, int h); void copyMetaData(const QExplicitlySharedDataPointer& src); void copyImageData(const QExplicitlySharedDataPointer& src); void setImageData(bool null, uint width, uint height, bool sixteenBit, bool alpha); void setImageDimension(uint width, uint height); size_t allocateData() const; bool clipped(int& x, int& y, int& w, int& h, uint width, uint height) const; QDateTime creationDateFromFilesystem(const QFileInfo& fileInfo) const; static QByteArray createUniqueHash(const QString& filePath, const QByteArray& ba); static QByteArray createUniqueHashV2(const QString& filePath); void bitBlt(const uchar* const src, uchar* const dest, int sx, int sy, int w, int h, int dx, int dy, uint swidth, uint sheight, uint dwidth, uint dheight, bool sixteenBit, int sdepth, int ddepth); void bitBlend(DColorComposer* const composer, uchar* const src, uchar* const dest, int sx, int sy, int w, int h, int dx, int dy, uint swidth, uint sheight, uint dwidth, uint dheight, bool sixteenBit, int sdepth, int ddepth, DColorComposer::MultiplicationFlags multiplicationFlags); void bitBlendOnColor(DColorComposer* const composer, const DColor& color, uchar* data, int x, int y, int w, int h, uint width, uint height, bool sixteenBit, int depth, DColorComposer::MultiplicationFlags multiplicationFlags); bool normalizeRegionArguments(int& sx, int& sy, int& w, int& h, int& dx, int& dy, uint swidth, uint sheight, uint dwidth, uint dheight) const; private: QExplicitlySharedDataPointer m_priv; friend class DImgLoader; }; } // namespace Digikam Q_DECLARE_OPERATORS_FOR_FLAGS(Digikam::DImg::PrepareMetadataFlags) #endif // DIGIKAM_DIMG_H diff --git a/core/libs/dimg/dimg_bitsops.cpp b/core/libs/dimg/dimg_bitsops.cpp index 62b5aa0642..5ce36bf026 100644 --- a/core/libs/dimg/dimg_bitsops.cpp +++ b/core/libs/dimg/dimg_bitsops.cpp @@ -1,318 +1,332 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2005-06-14 * Description : digiKam 8/16 bits image management API. * Bitwise operations. * * Copyright (C) 2005 by Renchi Raju * Copyright (C) 2005-2020 by Gilles Caulier * Copyright (C) 2006-2013 by Marcel Wiesweg * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "dimg_p.h" namespace Digikam { void DImg::bitBltImage(const DImg* const src, int dx, int dy) { bitBltImage(src, 0, 0, src->width(), src->height(), dx, dy); } void DImg::bitBltImage(const DImg* const src, int sx, int sy, int dx, int dy) { bitBltImage(src, sx, sy, src->width() - sx, src->height() - sy, dx, dy); } void DImg::bitBltImage(const DImg* const src, int sx, int sy, int w, int h, int dx, int dy) { if (isNull()) { return; } if (src->sixteenBit() != sixteenBit()) { qCWarning(DIGIKAM_DIMG_LOG) << "Blitting from 8-bit to 16-bit or vice versa is not supported"; return; } - if (w == -1 && h == -1) + if ((w == -1) && (h == -1)) { w = src->width(); h = src->height(); } bitBlt(src->bits(), bits(), sx, sy, w, h, dx, dy, src->width(), src->height(), width(), height(), sixteenBit(), src->bytesDepth(), bytesDepth()); } void DImg::bitBltImage(const uchar* const src, int sx, int sy, int w, int h, int dx, int dy, uint swidth, uint sheight, int sdepth) { if (isNull()) { return; } if (bytesDepth() != sdepth) { qCWarning(DIGIKAM_DIMG_LOG) << "Blitting from 8-bit to 16-bit or vice versa is not supported"; return; } - if (w == -1 && h == -1) + if ((w == -1) && (h == -1)) { w = swidth; h = sheight; } bitBlt(src, bits(), sx, sy, w, h, dx, dy, swidth, sheight, width(), height(), sixteenBit(), sdepth, bytesDepth()); } bool DImg::normalizeRegionArguments(int& sx, int& sy, int& w, int& h, int& dx, int& dy, uint swidth, uint sheight, uint dwidth, uint dheight) const { if (sx < 0) { // sx is negative, so + is - and - is + + dx -= sx; w += sx; - sx = 0; + sx = 0; } if (sy < 0) { dy -= sy; h += sy; - sy = 0; + sy = 0; } if (dx < 0) { sx -= dx; w += dx; - dx = 0; + dx = 0; } if (dy < 0) { sy -= dy; h += dy; - dy = 0; + dy = 0; } - if (sx + w > (int)swidth) + if ((sx + w) > (int)swidth) { w = swidth - sx; } - if (sy + h > (int)sheight) + if ((sy + h) > (int)sheight) { h = sheight - sy; } - if (dx + w > (int)dwidth) + if ((dx + w) > (int)dwidth) { w = dwidth - dx; } - if (dy + h > (int)dheight) + if ((dy + h) > (int)dheight) { h = dheight - dy; } // Nothing left to copy - if (w <= 0 || h <= 0) + + if ((w <= 0) || (h <= 0)) { return false; } return true; } void DImg::bitBlt(const uchar* const src, uchar* const dest, int sx, int sy, int w, int h, int dx, int dy, uint swidth, uint sheight, uint dwidth, uint dheight, bool /*sixteenBit*/, int sdepth, int ddepth) { // Normalize + if (!normalizeRegionArguments(sx, sy, w, h, dx, dy, swidth, sheight, dwidth, dheight)) { return; } // Same pixels - if (src == dest && dx == sx && dy == sy) + + if ((src == dest) && (dx == sx) && (dy == sy)) { return; } const uchar* sptr = nullptr; uchar* dptr = nullptr; uint slinelength = swidth * sdepth; uint dlinelength = dwidth * ddepth; int scurY = sy; int dcurY = dy; int sdepthlength = w * sdepth; for (int j = 0 ; j < h ; ++j, ++scurY, ++dcurY) { sptr = &src [ scurY * slinelength ] + sx * sdepth; dptr = &dest[ dcurY * dlinelength ] + dx * ddepth; // plain and simple bitBlt + for (int i = 0; i < sdepthlength ; ++i, ++sptr, ++dptr) { *dptr = *sptr; } } } void DImg::bitBlendImage(DColorComposer* const composer, const DImg* const src, int sx, int sy, int w, int h, int dx, int dy, DColorComposer::MultiplicationFlags multiplicationFlags) { if (isNull()) { return; } if (src->sixteenBit() != sixteenBit()) { qCWarning(DIGIKAM_DIMG_LOG) << "Blending from 8-bit to 16-bit or vice versa is not supported"; return; } bitBlend(composer, src->bits(), bits(), sx, sy, w, h, dx, dy, src->width(), src->height(), width(), height(), sixteenBit(), src->bytesDepth(), bytesDepth(), multiplicationFlags); } void DImg::bitBlend(DColorComposer* const composer, uchar* const src, uchar* const dest, int sx, int sy, int w, int h, int dx, int dy, uint swidth, uint sheight, uint dwidth, uint dheight, bool sixteenBit, int sdepth, int ddepth, DColorComposer::MultiplicationFlags multiplicationFlags) { // Normalize + if (!normalizeRegionArguments(sx, sy, w, h, dx, dy, swidth, sheight, dwidth, dheight)) { return; } uchar* sptr = nullptr; uchar* dptr = nullptr; uint slinelength = swidth * sdepth; uint dlinelength = dwidth * ddepth; int scurY = sy; int dcurY = dy; for (int j = 0 ; j < h ; ++j, ++scurY, ++dcurY) { sptr = &src [ scurY * slinelength ] + sx * sdepth; dptr = &dest[ dcurY * dlinelength ] + dx * ddepth; // blend src and destination + for (int i = 0 ; i < w ; ++i, sptr += sdepth, dptr += ddepth) { DColor src(sptr, sixteenBit); DColor dst(dptr, sixteenBit); // blend colors + composer->compose(dst, src, multiplicationFlags); dst.setPixel(dptr); } } } void DImg::bitBlendImageOnColor(const DColor& color) { bitBlendImageOnColor(color, 0, 0, width(), height()); } void DImg::bitBlendImageOnColor(const DColor& color, int x, int y, int w, int h) { // get composer for compositing rule + DColorComposer* const composer = DColorComposer::getComposer(DColorComposer::PorterDuffNone); + // flags would be MultiplicationFlagsDImg for anything but PorterDuffNone + bitBlendImageOnColor(composer, color, x, y, w, h, DColorComposer::NoMultiplication); delete composer; } void DImg::bitBlendImageOnColor(DColorComposer* const composer, const DColor& color, int x, int y, int w, int h, DColorComposer::MultiplicationFlags multiplicationFlags) { if (isNull()) { return; } DColor c = color; if (sixteenBit()) { c.convertToSixteenBit(); } else { c.convertToEightBit(); } bitBlendOnColor(composer, c, bits(), x, y, w, h, width(), height(), sixteenBit(), bytesDepth(), multiplicationFlags); } void DImg::bitBlendOnColor(DColorComposer* const composer, const DColor& color, uchar* const data, int x, int y, int w, int h, uint width, uint height, bool sixteenBit, int depth, DColorComposer::MultiplicationFlags multiplicationFlags) { // Normalize + if (!normalizeRegionArguments(x, y, w, h, x, y, width, height, width, height)) { return; } uchar* ptr = nullptr; uint linelength = width * depth; int curY = y; for (int j = 0 ; j < h ; ++j, ++curY) { ptr = &data[ curY * linelength ] + x * depth; // blend src and destination + for (int i = 0 ; i < w ; ++i, ptr += depth) { DColor src(ptr, sixteenBit); DColor dst(color); // blend colors + composer->compose(dst, src, multiplicationFlags); dst.setPixel(ptr); } } } } // namespace Digikam diff --git a/core/libs/dimg/dimg_colors.cpp b/core/libs/dimg/dimg_colors.cpp index 4bbc71b0bf..c5a0f9c9b8 100644 --- a/core/libs/dimg/dimg_colors.cpp +++ b/core/libs/dimg/dimg_colors.cpp @@ -1,185 +1,188 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2005-06-14 * Description : digiKam 8/16 bits image management API. * Color operations. * * Copyright (C) 2005-2020 by Gilles Caulier * Copyright (C) 2006-2013 by Marcel Wiesweg * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "dimg_p.h" namespace Digikam { void DImg::convertToSixteenBit() { convertDepth(64); } void DImg::convertToEightBit() { convertDepth(32); } void DImg::convertToDepthOfImage(const DImg* const otherImage) { if (otherImage->sixteenBit()) { convertToSixteenBit(); } else { convertToEightBit(); } } void DImg::convertDepth(int depth) { if (isNull()) { return; } - if (depth != 32 && depth != 64) + if ((depth != 32) && (depth != 64)) { qCDebug(DIGIKAM_DIMG_LOG) << " : wrong color depth!"; return; } if (((depth == 32) && !sixteenBit()) || ((depth == 64) && sixteenBit())) { return; } if (depth == 32) { // downgrading from 16 bit to 8 bit uchar* data = new uchar[width()*height() * 4]; uchar* dptr = data; ushort* sptr = reinterpret_cast(bits()); uint dim = width() * height() * 4; for (uint i = 0 ; i < dim ; ++i) { *dptr++ = (*sptr++ * 256UL) / 65536UL; } delete [] m_priv->data; m_priv->data = data; m_priv->sixteenBit = false; } else if (depth == 64) { // upgrading from 8 bit to 16 bit uchar* data = new uchar[width()*height() * 8]; ushort* dptr = reinterpret_cast(data); uchar* sptr = bits(); // use default seed of the generator + RandomNumberGenerator generator; ushort noise = 0; uint dim = width() * height() * 4; for (uint i = 0 ; i < dim ; ++i) { if (i % 4 < 3) { noise = generator.number(0, 255); } else { noise = 0; } *dptr++ = (*sptr++ * 65536ULL) / 256ULL + noise; } delete [] m_priv->data; m_priv->data = data; m_priv->sixteenBit = true; } } void DImg::fill(const DColor& color) { if (isNull()) { return; } // caching uint dim = width() * height() * 4; if (sixteenBit()) { unsigned short* imgData16 = reinterpret_cast(m_priv->data); unsigned short red = (unsigned short)color.red(); unsigned short green = (unsigned short)color.green(); unsigned short blue = (unsigned short)color.blue(); unsigned short alpha = (unsigned short)color.alpha(); for (uint i = 0 ; i < dim ; i += 4) { imgData16[i ] = blue; imgData16[i + 1] = green; imgData16[i + 2] = red; imgData16[i + 3] = alpha; } } else { uchar* imgData = m_priv->data; uchar red = (uchar)color.red(); uchar green = (uchar)color.green(); uchar blue = (uchar)color.blue(); uchar alpha = (uchar)color.alpha(); for (uint i = 0 ; i < dim ; i += 4) { imgData[i ] = blue; imgData[i + 1] = green; imgData[i + 2] = red; imgData[i + 3] = alpha; } } } void DImg::removeAlphaChannel() { removeAlphaChannel(DColor(0xFF, 0xFF, 0xFF, 0xFF, false)); } void DImg::removeAlphaChannel(const DColor& destColor) { if (isNull() || !hasAlpha()) { return; } bitBlendImageOnColor(destColor); + // unsure if alpha value is always 0xFF now + m_priv->alpha = false; } } // namespace Digikam diff --git a/core/libs/dimg/dimg_copy.cpp b/core/libs/dimg/dimg_copy.cpp index 9b95c4845a..8bd6cddab7 100644 --- a/core/libs/dimg/dimg_copy.cpp +++ b/core/libs/dimg/dimg_copy.cpp @@ -1,126 +1,132 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2005-06-14 * Description : digiKam 8/16 bits image management API. * Copying operations. * * Copyright (C) 2005-2020 by Gilles Caulier * Copyright (C) 2006-2013 by Marcel Wiesweg * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "dimg_p.h" namespace Digikam { DImg DImg::copy() const { DImg img(*this); img.detach(); return img; } DImg DImg::copyImageData() const { DImg img(width(), height(), sixteenBit(), hasAlpha(), bits(), true); return img; } DImg DImg::copyMetaData() const { DImg img; + // copy width, height, alpha, sixteenBit, null + img.copyImageData(m_priv); + // deeply copy metadata + img.copyMetaData(m_priv); + // set image to null + img.m_priv->null = true; return img; } DImg DImg::copy(const QRect& rect) const { return copy(rect.x(), rect.y(), rect.width(), rect.height()); } DImg DImg::copy(const QRectF& rel) const { if (isNull() || !rel.isValid()) { return DImg(); } return copy(QRectF(rel.x() * m_priv->width, rel.y() * m_priv->height, rel.width() * m_priv->width, rel.height() * m_priv->height) .toRect()); } DImg DImg::copy(int x, int y, int w, int h) const { - if (isNull() || w <= 0 || h <= 0) + if (isNull() || (w <= 0) || (h <= 0)) { qCDebug(DIGIKAM_DIMG_LOG) << " : return null image! (" << isNull() << ", " << w << ", " << h << ")"; return DImg(); } if (!clipped(x, y, w, h, m_priv->width, m_priv->height)) { return DImg(); } DImg image(*this, w, h); image.bitBltImage(this, x, y, w, h, 0, 0); return image; } /** -* x,y, w x h is a section of the image. The image size is width x height. -* Clips the section to the bounds of the image. -* Returns if the (clipped) section is a valid rectangle. -*/ + * x,y, w x h is a section of the image. The image size is width x height. + * Clips the section to the bounds of the image. + * Returns if the (clipped) section is a valid rectangle. + */ bool DImg::clipped(int& x, int& y, int& w, int& h, uint width, uint height) const { QRect inner(x, y, w, h); QRect outer(0, 0, width, height); if (!outer.contains(inner)) { QRect pt = inner.intersected(outer); x = pt.x(); y = pt.y(); w = pt.width(); h = pt.height(); return pt.isValid(); } return inner.isValid(); } } // namespace Digikam diff --git a/core/libs/dimg/dimg_data.cpp b/core/libs/dimg/dimg_data.cpp index 533d34ba42..8ce2ae1f8c 100644 --- a/core/libs/dimg/dimg_data.cpp +++ b/core/libs/dimg/dimg_data.cpp @@ -1,189 +1,199 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2005-06-14 * Description : digiKam 8/16 bits image management API. * Data management. * * Copyright (C) 2005-2020 by Gilles Caulier * Copyright (C) 2006-2013 by Marcel Wiesweg * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "dimg_p.h" namespace Digikam { DImg& DImg::operator=(const DImg& image) { m_priv = image.m_priv; + return *this; } bool DImg::operator==(const DImg& image) const { - return m_priv == image.m_priv; + return (m_priv == image.m_priv); } void DImg::reset() { m_priv = new Private; } void DImg::detach() { // are we being shared? + if (m_priv->ref == 1) { return; } QExplicitlySharedDataPointer old(m_priv.data()); m_priv = new Private; copyImageData(old); copyMetaData(old); if (old->data) { size_t size = allocateData(); memcpy(m_priv->data, old->data, size); } } void DImg::putImageData(uint width, uint height, bool sixteenBit, bool alpha, uchar* const data, bool copyData) { // set image data, metadata is untouched bool null = (width == 0) || (height == 0); + // allocateData, or code below will set null to false + setImageData(true, width, height, sixteenBit, alpha); // replace data + delete [] m_priv->data; if (null) { // image is null - no data + m_priv->data = nullptr; } else if (copyData) { size_t size = allocateData(); if (data) { memcpy(m_priv->data, data, size); } } else { if (data) { m_priv->data = data; m_priv->null = false; } else { allocateData(); } } } void DImg::putImageData(uchar* const data, bool copyData) { if (!data) { delete [] m_priv->data; m_priv->data = nullptr; m_priv->null = true; } else if (copyData) { memcpy(m_priv->data, data, numBytes()); } else { m_priv->data = data; } } void DImg::resetMetaData() { QMutexLocker lock(&m_priv->mutex); m_priv->attributes.clear(); m_priv->embeddedText.clear(); m_priv->metaData = MetaEngineData(); } uchar* DImg::stripImageData() { uchar* const data = m_priv->data; m_priv->data = nullptr; m_priv->null = true; + return data; } void DImg::copyMetaData(const QExplicitlySharedDataPointer& src) { QMutexLocker lock(&m_priv->mutex); m_priv->metaData = src->metaData; m_priv->attributes = src->attributes; m_priv->embeddedText = src->embeddedText; m_priv->iccProfile = src->iccProfile; m_priv->imageHistory = src->imageHistory; - //FIXME: what about sharing and deleting lanczos_func? + + // FIXME: what about sharing and deleting lanczos_func? } void DImg::copyImageData(const QExplicitlySharedDataPointer& src) { setImageData(src->null, src->width, src->height, src->sixteenBit, src->alpha); } size_t DImg::allocateData() const { size_t size = m_priv->width * m_priv->height * (m_priv->sixteenBit ? 8 : 4); m_priv->data = DImgLoader::new_failureTolerant(size); if (!m_priv->data) { m_priv->null = true; + return 0; } m_priv->null = false; + return size; } void DImg::setImageDimension(uint width, uint height) { m_priv->width = width; m_priv->height = height; } void DImg::setImageData(bool null, uint width, uint height, bool sixteenBit, bool alpha) { m_priv->null = null; m_priv->width = width; m_priv->height = height; m_priv->alpha = alpha; m_priv->sixteenBit = sixteenBit; } } // namespace Digikam diff --git a/core/libs/dimg/dimg_fileio.cpp b/core/libs/dimg/dimg_fileio.cpp index 000e31169f..941d94d1c0 100644 --- a/core/libs/dimg/dimg_fileio.cpp +++ b/core/libs/dimg/dimg_fileio.cpp @@ -1,368 +1,368 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2005-06-14 * Description : digiKam 8/16 bits image management API * Files input output * * Copyright (C) 2005-2020 by Gilles Caulier * Copyright (C) 2006-2013 by Marcel Wiesweg * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ -#include "dimg.h" #include "dimg_p.h" namespace Digikam { bool DImg::loadItemInfo(const QString& filePath, bool loadMetadata, bool loadICCData, bool loadUniqueHash, bool loadImageHistory) { DImgLoader::LoadFlags loadFlags = DImgLoader::LoadItemInfo; if (loadMetadata) { loadFlags |= DImgLoader::LoadMetadata; } if (loadICCData) { loadFlags |= DImgLoader::LoadICCData; } if (loadUniqueHash) { loadFlags |= DImgLoader::LoadUniqueHash; } if (loadImageHistory) { loadFlags |= DImgLoader::LoadImageHistory; } return load(filePath, loadFlags, nullptr, DRawDecoding()); } bool DImg::load(const QString& filePath, DImgLoaderObserver* const observer, const DRawDecoding& rawDecodingSettings) { return load(filePath, DImgLoader::LoadAll, observer, rawDecodingSettings); } bool DImg::load(const QString& filePath, bool loadMetadata, bool loadICCData, bool loadUniqueHash, bool loadImageHistory, DImgLoaderObserver* const observer, const DRawDecoding& rawDecodingSettings) { DImgLoader::LoadFlags loadFlags = DImgLoader::LoadItemInfo | DImgLoader::LoadImageData; if (loadMetadata) { loadFlags |= DImgLoader::LoadMetadata; } if (loadICCData) { loadFlags |= DImgLoader::LoadICCData; } if (loadUniqueHash) { loadFlags |= DImgLoader::LoadUniqueHash; } if (loadImageHistory) { loadFlags |= DImgLoader::LoadImageHistory; } return load(filePath, loadFlags, observer, rawDecodingSettings); } bool DImg::load(const QString& filePath, int loadFlagsInt, DImgLoaderObserver* const observer, const DRawDecoding& rawDecodingSettings) { QFileInfo fileInfo(filePath); if (!fileInfo.exists() || !fileInfo.isReadable()) { qCDebug(DIGIKAM_DIMG_LOG) << "File" << filePath << "does not exist"; return false; } QList pluginList = m_priv->pluginsForFile(fileInfo, false); DImgLoader::LoadFlags loadFlags = (DImgLoader::LoadFlags)loadFlagsInt; setAttribute(QLatin1String("originalFilePath"), filePath); FileReadLocker lock(filePath); // First step we check the file extension to find the right loader. foreach (DPluginDImg* const plug, pluginList) { if (observer && !observer->continueQuery()) { return false; } if (loadFlags & DImgLoader::LoadPreview && !plug->previewSupported()) { continue; } qCDebug(DIGIKAM_DIMG_LOG) << filePath << ":" << plug->loaderName() << "file identified"; FORMAT format = m_priv->loaderNameToFormat(plug->loaderName()); DImgLoader* const loader = plug->loader(this, rawDecodingSettings); setAttribute(QLatin1String("detectedFileFormat"), format); loader->setLoadFlags(loadFlags); if (loader->load(filePath, observer)) { m_priv->null = !loader->hasLoadedData(); m_priv->alpha = loader->hasAlpha(); m_priv->sixteenBit = loader->sixteenBit(); setAttribute(QLatin1String("isReadOnly"), loader->isReadOnly()); delete loader; return true; } delete loader; } if (observer && !observer->continueQuery()) { return false; } // In the second step we check the magic bytes to find the right loader. pluginList = m_priv->pluginsForFile(fileInfo, true); foreach (DPluginDImg* const plug, pluginList) { if (observer && !observer->continueQuery()) { return false; } if (loadFlags & DImgLoader::LoadPreview && !plug->previewSupported()) { continue; } qCDebug(DIGIKAM_DIMG_LOG) << filePath << ":" << plug->loaderName() << "file identified (magic)"; FORMAT format = m_priv->loaderNameToFormat(plug->loaderName()); DImgLoader* const loader = plug->loader(this, rawDecodingSettings); setAttribute(QLatin1String("detectedFileFormat"), format); loader->setLoadFlags(loadFlags); if (loader->load(filePath, observer)) { m_priv->null = !loader->hasLoadedData(); m_priv->alpha = loader->hasAlpha(); m_priv->sixteenBit = loader->sixteenBit(); setAttribute(QLatin1String("isReadOnly"), loader->isReadOnly()); delete loader; return true; } delete loader; } if (pluginList.isEmpty() && !(loadFlags & DImgLoader::LoadPreview)) { qCWarning(DIGIKAM_DIMG_LOG) << filePath << ": Unknown image format !!!"; return false; } if (observer && observer->continueQuery() && !(loadFlags & DImgLoader::LoadPreview)) { qCWarning(DIGIKAM_DIMG_LOG) << filePath << ": Cannot load file !!!"; } return false; } QString DImg::formatToMimeType(FORMAT frm) { QString format; switch (frm) { case (NONE): { return format; } case (JPEG): { format = QLatin1String("JPG"); break; } case (TIFF): { format = QLatin1String("TIF"); break; } case (PNG): { format = QLatin1String("PNG"); break; } case (JP2K): { format = QLatin1String("JP2"); break; } case (PGF): { format = QLatin1String("PGF"); break; } default: { // For QImage or ImageMagick based. break; } } return format; } bool DImg::save(const QString& filePath, FORMAT frm, DImgLoaderObserver* const observer) { if (isNull()) { return false; } return(save(filePath, formatToMimeType(frm), observer)); } bool DImg::save(const QString& filePath, const QString& format, DImgLoaderObserver* const observer) { qCDebug(DIGIKAM_DIMG_LOG) << "Saving to " << filePath << " with format: " << format; if (isNull()) { return false; } if (format.isEmpty()) { return false; } QString frm = format.toUpper(); setAttribute(QLatin1String("savedFilePath"), filePath); FileWriteLocker lock(filePath); DPluginDImg* const plug = m_priv->pluginForFormat(frm); DImg copyForSave = copy(); - if (frm == QLatin1String("JPEG") || frm == QLatin1String("JPG") || frm == QLatin1String("JPE")) + if ((frm == QLatin1String("JPEG")) || (frm == QLatin1String("JPG")) || (frm == QLatin1String("JPE"))) { // JPEG does not support transparency, so we shall provide an image without alpha channel. // This is only necessary if the image has an alpha channel, and there are actually transparent pixels + if (hasTransparentPixels()) { copyForSave.removeAlphaChannel(); } } if (plug) { DImgLoader* const loader = plug->loader(©ForSave); copyForSave.setAttribute(QLatin1String("savedFormat-isReadOnly"), loader->isReadOnly()); bool ret = loader->save(filePath, observer); delete loader; return ret; } qCWarning(DIGIKAM_DIMG_LOG) << filePath << " : Unknown save format !!!"; return false; } DImg::FORMAT DImg::fileFormat(const QString& filePath) { FORMAT format = DImg::NONE; if (filePath.isEmpty()) { return format; } QFileInfo fileInfo(filePath); if (!fileInfo.exists() || !fileInfo.isReadable()) { return format; } QList pluginList = DImg::Private::pluginsForFile(fileInfo, false); if (!pluginList.isEmpty()) { QString name = pluginList.first()->loaderName(); format = DImg::Private::loaderNameToFormat(name); } return format; } QDateTime DImg::creationDateFromFilesystem(const QFileInfo& fileInfo) const { // creation date is not what it seems on Unix #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) QDateTime ctime = fileInfo.birthTime(); #else QDateTime ctime = fileInfo.created(); #endif QDateTime mtime = fileInfo.lastModified(); if (ctime.isNull()) { return mtime; } if (mtime.isNull()) { return ctime; } return qMin(ctime, mtime); } } // namespace Digikam diff --git a/core/libs/dimg/dimg_metadata.cpp b/core/libs/dimg/dimg_metadata.cpp index 65092c1802..3a5c0a52b1 100644 --- a/core/libs/dimg/dimg_metadata.cpp +++ b/core/libs/dimg/dimg_metadata.cpp @@ -1,539 +1,559 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2005-06-14 * Description : digiKam 8/16 bits image management API. * Metadata operations. * * Copyright (C) 2005-2020 by Gilles Caulier * Copyright (C) 2006-2013 by Marcel Wiesweg * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "dimg_p.h" namespace Digikam { QByteArray DImg::getUniqueHash() { if (hasAttribute(QLatin1String("uniqueHash"))) { return attribute(QLatin1String("uniqueHash")).toByteArray(); } if (!hasAttribute(QLatin1String("originalFilePath"))) { qCWarning(DIGIKAM_DIMG_LOG) << "DImg::getUniqueHash called without originalFilePath property set!"; return QByteArray(); } QString filePath = attribute(QLatin1String("originalFilePath")).toString(); if (filePath.isEmpty()) { return QByteArray(); } FileReadLocker lock(filePath); DMetadata meta(getMetadata()); - QByteArray ba = meta.getExifEncoded(); + QByteArray ba = meta.getExifEncoded(); - QByteArray hash = DImg::createUniqueHash(filePath, ba); + QByteArray hash = DImg::createUniqueHash(filePath, ba); setAttribute(QLatin1String("uniqueHash"), hash); return hash; } QByteArray DImg::getUniqueHash(const QString& filePath) { DMetadata meta(filePath); QByteArray ba = meta.getExifEncoded(); return DImg::createUniqueHash(filePath, ba); } QByteArray DImg::getUniqueHashV2() { if (hasAttribute(QLatin1String("uniqueHashV2"))) { return attribute(QLatin1String("uniqueHashV2")).toByteArray(); } if (!hasAttribute(QLatin1String("originalFilePath"))) { qCWarning(DIGIKAM_DIMG_LOG) << "DImg::getUniqueHash called without originalFilePath property set!"; return QByteArray(); } QString filePath = attribute(QLatin1String("originalFilePath")).toString(); if (filePath.isEmpty()) { return QByteArray(); } FileReadLocker lock(filePath); QByteArray hash = DImg::createUniqueHashV2(filePath); setAttribute(QLatin1String("uniqueHashV2"), hash); return hash; } QByteArray DImg::getUniqueHashV2(const QString& filePath) { return DImg::createUniqueHashV2(filePath); } QByteArray DImg::createImageUniqueId() { NonDeterministicRandomData randomData(16); QByteArray imageUUID = randomData.toHex(); imageUUID += getUniqueHashV2(); return imageUUID; } void DImg::prepareMetadataToSave(const QString& intendedDestPath, const QString& destMimeType, bool resetExifOrientationTag) { PrepareMetadataFlags flags = PrepareMetadataFlagsAll; if (!resetExifOrientationTag) { flags &= ~ResetExifOrientationTag; } QUrl url = QUrl::fromLocalFile(originalFilePath()); prepareMetadataToSave(intendedDestPath, destMimeType, url.fileName(), flags); } void DImg::prepareMetadataToSave(const QString& intendedDestPath, const QString& destMimeType, const QString& originalFileName, PrepareMetadataFlags flags) { if (isNull()) { return; } // Get image Exif/IPTC data. + DMetadata meta(getMetadata()); qCDebug(DIGIKAM_DIMG_LOG) << "Prepare Metadata to save for" << intendedDestPath; if (flags & RemoveOldMetadataPreviews || flags & CreateNewMetadataPreview) { // Clear IPTC preview + meta.removeIptcTag("Iptc.Application2.Preview"); meta.removeIptcTag("Iptc.Application2.PreviewFormat"); meta.removeIptcTag("Iptc.Application2.PreviewVersion"); // Clear Exif thumbnail + meta.removeExifThumbnail(); // Clear Tiff thumbnail + MetaEngine::MetaDataMap tiffThumbTags = meta.getExifTagsDataList(QStringList() << QLatin1String("SubImage1")); - for (MetaEngine::MetaDataMap::iterator it = tiffThumbTags.begin(); it != tiffThumbTags.end(); ++it) + for (MetaEngine::MetaDataMap::iterator it = tiffThumbTags.begin() ; it != tiffThumbTags.end() ; ++it) { meta.removeExifTag(it.key().toLatin1().constData()); } // Clear Xmp preview from digiKam namespace + meta.removeXmpTag("Xmp.digiKam.Preview"); } bool createNewPreview = false; QSize previewSize; // Refuse preview creation for images with transparency // as long as we have no format to support this. See bug 286127 + bool skipPreviewCreation = hasTransparentPixels(); if (flags & CreateNewMetadataPreview && !skipPreviewCreation) { const QSize standardPreviewSize(1280, 1280); previewSize = size(); // Scale to standard preview size. Only scale down, not up + if (width() > (uint)standardPreviewSize.width() && height() > (uint)standardPreviewSize.height()) { previewSize.scale(standardPreviewSize, Qt::KeepAspectRatio); } // Only store a new preview if it is worth it - the original should be significantly larger than the preview createNewPreview = (2 * (uint)previewSize.width() <= width()); } if (createNewPreview) { // Create the preview QImage QImage preview; { if (!IccManager::isSRGB(*this)) { DImg previewDImg; if (previewSize.width() >= (int)width()) { previewDImg = copy(); } else { previewDImg = smoothScale(previewSize.width(), previewSize.height(), Qt::IgnoreAspectRatio); } IccManager manager(previewDImg); manager.transformToSRGB(); preview = previewDImg.copyQImage(); } else { // Ensure that preview is not upscaled if (previewSize.width() >= (int)width()) { preview = copyQImage(); } else { preview = smoothScale(previewSize.width(), previewSize.height(), Qt::IgnoreAspectRatio).copyQImage(); } } } // Update IPTC preview. // see bug #130525. a JPEG segment is limited to 64K. If the IPTC byte array is // bigger than 64K during of image preview tag size, the target JPEG image will be // broken. Note that IPTC image preview tag is limited to 256K!!! // There is no limitation with TIFF and PNG about IPTC byte array size. // So for a JPEG file, we don't store the IPTC preview. - if ((destMimeType.toUpper() != QLatin1String("JPG") && destMimeType.toUpper() != QLatin1String("JPEG") && - destMimeType.toUpper() != QLatin1String("JPE")) + + if (((destMimeType.toUpper() != QLatin1String("JPG")) && + (destMimeType.toUpper() != QLatin1String("JPEG")) && + (destMimeType.toUpper() != QLatin1String("JPE"))) ) { // Non JPEG file, we update IPTC and XMP preview + meta.setItemPreview(preview); } - if (destMimeType.toUpper() == QLatin1String("TIFF") || destMimeType.toUpper() == QLatin1String("TIF")) + if ((destMimeType.toUpper() == QLatin1String("TIFF")) || + (destMimeType.toUpper() == QLatin1String("TIF"))) { // With TIFF file, we don't store JPEG thumbnail, we even need to erase it and store // a thumbnail at a special location. See bug #211758 + QImage thumb = preview.scaled(160, 120, Qt::KeepAspectRatio, Qt::SmoothTransformation); meta.setTiffThumbnail(thumb); } else { // Update Exif thumbnail. + QImage thumb = preview.scaled(160, 120, Qt::KeepAspectRatio, Qt::SmoothTransformation); meta.setExifThumbnail(thumb); } } // Update Exif Image dimensions. + meta.setItemDimensions(size()); // Update Exif Document Name tag with the original file name. + if (!originalFileName.isEmpty()) { meta.setExifTagString("Exif.Image.DocumentName", originalFileName); } // Update Exif Orientation tag if necessary. + if (flags & ResetExifOrientationTag) { meta.setItemOrientation(DMetadata::ORIENTATION_NORMAL); } if (!m_priv->imageHistory.isEmpty()) { DImageHistory forSaving(m_priv->imageHistory); forSaving.adjustReferredImages(); QUrl url = QUrl::fromLocalFile(intendedDestPath); QString filePath = url.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).toLocalFile() + QLatin1Char('/'); QString fileName = url.fileName(); if (!filePath.isEmpty() && !fileName.isEmpty()) { forSaving.purgePathFromReferredImages(filePath, fileName); } QString imageHistoryXml = forSaving.toXml(); meta.setItemHistory(imageHistoryXml); } if (flags & CreateNewImageHistoryUUID) { meta.setItemUniqueId(QString::fromUtf8(createImageUniqueId())); } // Store new Exif/IPTC/XMP data into image. + setMetadata(meta.data()); } HistoryImageId DImg::createHistoryImageId(const QString& filePath, HistoryImageId::Type type) { QFileInfo fileInfo(filePath); if (!fileInfo.exists()) { return HistoryImageId(); } DMetadata metadata(getMetadata()); HistoryImageId id(metadata.getItemUniqueId()); QDateTime dt = metadata.getItemDateTime(); if (dt.isNull()) { dt = creationDateFromFilesystem(fileInfo); } id.setCreationDate(dt); id.setFileName(fileInfo.fileName()); id.setPath(fileInfo.path()); id.setUniqueHash(QString::fromUtf8(getUniqueHashV2()), fileInfo.size()); id.setType(type); return id; } HistoryImageId DImg::addAsReferredImage(const QString& filePath, HistoryImageId::Type type) { HistoryImageId id = createHistoryImageId(filePath, type); m_priv->imageHistory.purgePathFromReferredImages(id.path(), id.fileName()); addAsReferredImage(id); return id; } void DImg::addAsReferredImage(const HistoryImageId& id) { m_priv->imageHistory << id; } void DImg::insertAsReferredImage(int afterHistoryStep, const HistoryImageId& id) { m_priv->imageHistory.insertReferredImage(afterHistoryStep, id); } void DImg::addCurrentUniqueImageId(const QString& uuid) { m_priv->imageHistory.adjustCurrentUuid(uuid); } void DImg::addFilterAction(const Digikam::FilterAction& action) { m_priv->imageHistory << action; } const DImageHistory& DImg::getItemHistory() const { return m_priv->imageHistory; } DImageHistory& DImg::getItemHistory() { return m_priv->imageHistory; } void DImg::setItemHistory(const DImageHistory& history) { m_priv->imageHistory = history; } bool DImg::hasImageHistory() const { if (m_priv->imageHistory.isEmpty()) { return false; } else { return true; } } DImageHistory DImg::getOriginalImageHistory() const { return attribute(QLatin1String("originalImageHistory")).value(); } void DImg::setHistoryBranch(bool isBranch) { setHistoryBranchAfter(getOriginalImageHistory(), isBranch); } void DImg::setHistoryBranchAfter(const DImageHistory& historyBeforeBranch, bool isBranch) { int addedSteps = m_priv->imageHistory.size() - historyBeforeBranch.size(); setHistoryBranchForLastSteps(addedSteps, isBranch); } void DImg::setHistoryBranchForLastSteps(int numberOfLastHistorySteps, bool isBranch) { int firstStep = m_priv->imageHistory.size() - numberOfLastHistorySteps; if (firstStep < m_priv->imageHistory.size()) { if (isBranch) { m_priv->imageHistory[firstStep].action.addFlag(FilterAction::ExplicitBranch); } else { m_priv->imageHistory[firstStep].action.removeFlag(FilterAction::ExplicitBranch); } } } QString DImg::colorModelToString(COLORMODEL colorModel) { switch (colorModel) { case RGB: return i18nc("Color Model: RGB", "RGB"); case GRAYSCALE: return i18nc("Color Model: Grayscale", "Grayscale"); case MONOCHROME: return i18nc("Color Model: Monochrome", "Monochrome"); case INDEXED: return i18nc("Color Model: Indexed", "Indexed"); case YCBCR: return i18nc("Color Model: YCbCr", "YCbCr"); case CMYK: return i18nc("Color Model: CMYK", "CMYK"); case CIELAB: return i18nc("Color Model: CIE L*a*b*", "CIE L*a*b*"); case COLORMODELRAW: return i18nc("Color Model: Uncalibrated (RAW)", "Uncalibrated (RAW)"); case COLORMODELUNKNOWN: default: return i18nc("Color Model: Unknown", "Unknown"); } } bool DImg::isAnimatedImage(const QString& filePath) { QImageReader reader(filePath); reader.setDecideFormatFromContent(true); if (reader.supportsAnimation() && (reader.imageCount() > 1)) { qCDebug(DIGIKAM_DIMG_LOG) << "File \"" << filePath << "\" is an animated image"; return true; } return false; } int DImg::exifOrientation(const QString& filePath) { QVariant preview(attribute(QLatin1String("fromRawEmbeddedPreview"))); return LoadSaveThread::exifOrientation(filePath, DMetadata(getMetadata()), (detectedFormat() == DImg::RAW), (preview.isValid() && preview.toBool())); } QByteArray DImg::createUniqueHash(const QString& filePath, const QByteArray& ba) { // Create the unique ID QCryptographicHash md5(QCryptographicHash::Md5); // First, read the Exif data into the hash md5.addData(ba); // Second, read in the first 8KB of the file QFile qfile(filePath); char databuf[8192]; QByteArray hash; if (qfile.open(QIODevice::Unbuffered | QIODevice::ReadOnly)) { int readlen = 0; if ((readlen = qfile.read(databuf, 8192)) > 0) { QByteArray size; md5.addData(databuf, readlen); md5.addData(size.setNum(qfile.size())); hash = md5.result().toHex(); } qfile.close(); } return hash; } QByteArray DImg::createUniqueHashV2(const QString& filePath) { QFile file(filePath); if (!file.open(QIODevice::Unbuffered | QIODevice::ReadOnly)) { return QByteArray(); } QCryptographicHash md5(QCryptographicHash::Md5); // Specified size: 100 kB; but limit to file size + const qint64 specifiedSize = 100 * 1024; // 100 kB qint64 size = qMin(file.size(), specifiedSize); if (size) { QScopedArrayPointer databuf(new char[size]); int read; // Read first 100 kB + if ((read = file.read(databuf.data(), size)) > 0) { md5.addData(databuf.data(), read); } // Read last 100 kB + file.seek(file.size() - size); if ((read = file.read(databuf.data(), size)) > 0) { md5.addData(databuf.data(), read); } } file.close(); return md5.result().toHex(); } } // namespace Digikam diff --git a/core/libs/dimg/dimg_p.h b/core/libs/dimg/dimg_p.h index cf6f145387..d7bfbb798c 100644 --- a/core/libs/dimg/dimg_p.h +++ b/core/libs/dimg/dimg_p.h @@ -1,275 +1,275 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2005-06-15 * Description : digiKam 8/16 bits image management API. * Private data container. * * Copyright (C) 2005 by Renchi Raju * Copyright (C) 2005-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_DIMG_PRIVATE_H #define DIGIKAM_DIMG_PRIVATE_H #include "digikam_config.h" // C ANSI includes #ifndef Q_OS_WIN extern "C" { #endif #include #ifndef Q_OS_WIN #include } #endif // C++ includes #include // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "dimg.h" #include "dplugindimg.h" #include "digikam_export.h" #include "digikam_debug.h" #include "dmetadata.h" #include "dimagehistory.h" #include "iccprofile.h" #include "metaengine_rotation.h" #include "drawdecoder.h" #include "loadsavethread.h" #include "filereadwritelock.h" #include "iccmanager.h" #include "icctransform.h" #include "exposurecontainer.h" #include "dimgloaderobserver.h" #include "randomnumbergenerator.h" /** * Lanczos kernel is precomputed in a table with this resolution * The value below seems to be enough for HQ upscaling up to eight times */ #define LANCZOS_TABLE_RES 256 /** * A support of 3 gives an overall sharper looking image, but * it is a) slower b) gives more sharpening artifacts */ #define LANCZOS_SUPPORT 2 /** * Define this to use a floating-point implementation of Lanczos interpolation. * The integer implementation is a little bit less accurate, but MUCH faster * (even on machines with FPU - ~2.5 times faster on Core2); besides, it will * run a hell lot faster on computers without a FPU (e.g. PDAs). */ //#define LANCZOS_DATA_FLOAT #ifdef LANCZOS_DATA_FLOAT # define LANCZOS_DATA_TYPE float # define LANCZOS_DATA_ONE 1.0 #else # define LANCZOS_DATA_TYPE int # define LANCZOS_DATA_ONE 4096 #endif typedef uint64_t ullong; // krazy:exclude=typedefs typedef int64_t llong; // krazy:exclude=typedefs namespace Digikam { class DIGIKAM_EXPORT DImg::Private : public QSharedData { public: explicit Private() : null(true), alpha(false), sixteenBit(false), width(0), height(0), data(nullptr), lanczos_func(nullptr), mutex(QMutex::Recursive), orientation(DMetadata::ORIENTATION_UNSPECIFIED) { } ~Private() { delete [] data; delete [] lanczos_func; } static QList pluginsForFile(const QFileInfo& fileInfo, bool magic) { QMap pluginMap; foreach (DPlugin* const p, DPluginLoader::instance()->allPlugins()) { int prio; DPluginDImg* const plug = dynamic_cast(p); if (plug && ((prio = plug->canRead(fileInfo, magic)) > 0)) { - /* + /* qCDebug(DIGIKAM_DIMG_LOG) << "File path:" << filePath << "Priority:" << prio << "Loader:" << plug->loaderName(); - */ + */ pluginMap.insertMulti(prio, plug); } } return pluginMap.values(); } static DPluginDImg* pluginForFormat(const QString& format) { QMap pluginMap; if (!format.isNull()) { foreach (DPlugin* const p, DPluginLoader::instance()->allPlugins()) { int prio; DPluginDImg* const plug = dynamic_cast(p); if (plug && ((prio = plug->canWrite(format)) > 0)) { pluginMap.insertMulti(prio, plug); } } } if (pluginMap.isEmpty()) { return nullptr; } return pluginMap.first(); } static DImg::FORMAT loaderNameToFormat(const QString& name) { - if (name.isNull()) + if (name.isNull()) { return DImg::NONE; } else if (name == QLatin1String("JPEG")) { return DImg::JPEG; } else if (name == QLatin1String("PNG")) { return DImg::PNG; } else if (name == QLatin1String("TIFF")) { return DImg::TIFF; } else if (name == QLatin1String("RAW")) { return DImg::RAW; } else if (name == QLatin1String("JPEG2000")) { return DImg::JP2K; } else if (name == QLatin1String("PGF")) { return DImg::PGF; } else if (name == QLatin1String("HEIF")) { return DImg::HEIF; } // In others cases, ImageMagick or QImage will be used to try to open file. return DImg::QIMAGE; } static QStringList fileOriginAttributes() { QStringList list; list << QLatin1String("format") << QLatin1String("isReadOnly") << QLatin1String("originalFilePath") << QLatin1String("originalSize") << QLatin1String("originalImageHistory") << QLatin1String("rawDecodingSettings") << QLatin1String("rawDecodingFilterAction") << QLatin1String("uniqueHash") << QLatin1String("uniqueHashV2"); return list; } public: bool null; bool alpha; bool sixteenBit; unsigned int width; unsigned int height; unsigned char* data; LANCZOS_DATA_TYPE* lanczos_func; QMutex mutex; int orientation; MetaEngineData metaData; QMap attributes; QMap embeddedText; IccProfile iccProfile; DImageHistory imageHistory; }; } // namespace Digikam #endif // DIGIKAM_DIMG_PRIVATE_H diff --git a/core/libs/dimg/dimg_props.cpp b/core/libs/dimg/dimg_props.cpp index 2574fb49ed..dff7d39e70 100644 --- a/core/libs/dimg/dimg_props.cpp +++ b/core/libs/dimg/dimg_props.cpp @@ -1,703 +1,707 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2005-06-14 * Description : digiKam 8/16 bits image management API. * Properties accessors. * * Copyright (C) 2005-2020 by Gilles Caulier * Copyright (C) 2006-2013 by Marcel Wiesweg * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "dimg_p.h" namespace Digikam { bool DImg::isNull() const { return m_priv->null; } uint DImg::width() const { return m_priv->width; } uint DImg::height() const { return m_priv->height; } QSize DImg::size() const { return QSize(m_priv->width, m_priv->height); } uchar* DImg::bits() const { return m_priv->data; } uchar* DImg::copyBits() const { uchar* const data = new uchar[numBytes()]; memcpy(data, bits(), numBytes()); + return data; } uchar* DImg::scanLine(uint i) const { if (i >= height()) { return nullptr; } uchar* const data = bits() + (width() * bytesDepth() * i); + return data; } bool DImg::hasAlpha() const { return m_priv->alpha; } bool DImg::sixteenBit() const { return m_priv->sixteenBit; } bool DImg::isReadOnly() const { return attribute(QLatin1String("isReadOnly")).toBool(); } DImg::COLORMODEL DImg::originalColorModel() const { if (hasAttribute(QLatin1String("originalColorModel"))) { return (COLORMODEL)attribute(QLatin1String("originalColorModel")).toInt(); } else { return COLORMODELUNKNOWN; } } int DImg::originalBitDepth() const { return attribute(QLatin1String("originalBitDepth")).toInt(); } QSize DImg::originalSize() const { if (hasAttribute(QLatin1String("originalSize"))) { QSize size = attribute(QLatin1String("originalSize")).toSize(); if (size.isValid() && !size.isNull()) { return size; } } return size(); } DImg::FORMAT DImg::detectedFormat() const { if (hasAttribute(QLatin1String("detectedFileFormat"))) { return (FORMAT)attribute(QLatin1String("detectedFileFormat")).toInt(); } else { return NONE; } } QString DImg::format() const { return attribute(QLatin1String("format")).toString(); } QString DImg::savedFormat() const { return attribute(QLatin1String("savedFormat")).toString(); } DRawDecoding DImg::rawDecodingSettings() const { if (hasAttribute(QLatin1String("rawDecodingSettings"))) { return attribute(QLatin1String("rawDecodingSettings")).value(); } else { return DRawDecoding(); } } IccProfile DImg::getIccProfile() const { QMutexLocker lock(&m_priv->mutex); return m_priv->iccProfile; } void DImg::setIccProfile(const IccProfile& profile) { QMutexLocker lock(&m_priv->mutex); m_priv->iccProfile = profile; } MetaEngineData DImg::getMetadata() const { QMutexLocker lock(&m_priv->mutex); return m_priv->metaData; } void DImg::setMetadata(const MetaEngineData& data) { QMutexLocker lock(&m_priv->mutex); m_priv->metaData = data; } uint DImg::numBytes() const { return (width() * height() * bytesDepth()); } uint DImg::numPixels() const { return (width() * height()); } int DImg::bytesDepth() const { if (m_priv->sixteenBit) { return 8; } return 4; } int DImg::bitsDepth() const { if (m_priv->sixteenBit) { return 16; } return 8; } void DImg::setAttribute(const QString& key, const QVariant& value) { QMutexLocker lock(&m_priv->mutex); m_priv->attributes.insert(key, value); } QVariant DImg::attribute(const QString& key) const { QMutexLocker lock(&m_priv->mutex); if (m_priv->attributes.contains(key)) { return m_priv->attributes[key]; } return QVariant(); } bool DImg::hasAttribute(const QString& key) const { QMutexLocker lock(&m_priv->mutex); return m_priv->attributes.contains(key); } void DImg::removeAttribute(const QString& key) { QMutexLocker lock(&m_priv->mutex); m_priv->attributes.remove(key); } void DImg::setEmbeddedText(const QString& key, const QString& text) { QMutexLocker lock(&m_priv->mutex); m_priv->embeddedText.insert(key, text); } QString DImg::embeddedText(const QString& key) const { QMutexLocker lock(&m_priv->mutex); if (m_priv->embeddedText.contains(key)) { return m_priv->embeddedText[key]; } return QString(); } void DImg::imageSavedAs(const QString& savePath) { setAttribute(QLatin1String("savedFilePath"), savePath); addAsReferredImage(savePath); } QString DImg::originalFilePath() const { return attribute(QLatin1String("originalFilePath")).toString(); } QString DImg::lastSavedFilePath() const { return attribute(QLatin1String("savedFilePath")).toString(); } QVariant DImg::fileOriginData() const { QVariantMap map; foreach (const QString& key, m_priv->fileOriginAttributes()) { QVariant attr = attribute(key); if (!attr.isNull()) { map.insert(key, attr); } } return map; } QVariant DImg::lastSavedFileOriginData() const { QVariantMap map; QVariant savedformat = attribute(QLatin1String("savedFormat")); if (!savedformat.isNull()) { map.insert(QLatin1String("format"), savedformat); } QVariant readonly = attribute(QLatin1String("savedFormat-isReadOnly")); if (!readonly.isNull()) { map.insert(QLatin1String("isReadOnly"), readonly); } QVariant filePath = attribute(QLatin1String("savedFilePath")); if (!filePath.isNull()) { map.insert(QLatin1String("originalFilePath"), filePath); } DImageHistory history = m_priv->imageHistory; if (!history.isEmpty()) { history.adjustReferredImages(); if (!history.entries().last().referredImages.isEmpty()) { history.entries().last().referredImages.last().setType(HistoryImageId::Current); } map.insert(QLatin1String("originalImageHistory"), QVariant::fromValue(history)); } return map; } void DImg::setFileOriginData(const QVariant& data) { QVariantMap map = data.toMap(); foreach (const QString& key, m_priv->fileOriginAttributes()) { removeAttribute(key); QVariant attr = map.value(key); if (!attr.isNull()) { setAttribute(key, attr); } } } void DImg::switchOriginToLastSaved() { setFileOriginData(lastSavedFileOriginData()); } DColor DImg::getPixelColor(uint x, uint y) const { - if (m_priv->null || x >= m_priv->width || y >= m_priv->height) + if (m_priv->null || (x >= m_priv->width) || (y >= m_priv->height)) { return DColor(); } int depth = bytesDepth(); uchar* const data = m_priv->data + x * depth + (m_priv->width * y * depth); return (DColor(data, m_priv->sixteenBit)); } void DImg::prepareSubPixelAccess() { if (m_priv->lanczos_func) { return; } /* Precompute the Lanczos kernel */ LANCZOS_DATA_TYPE* lanczos_func = new LANCZOS_DATA_TYPE[LANCZOS_SUPPORT * LANCZOS_SUPPORT * LANCZOS_TABLE_RES]; - for (int i = 0; i < LANCZOS_SUPPORT * LANCZOS_SUPPORT * LANCZOS_TABLE_RES; ++i) + for (int i = 0 ; (i < LANCZOS_SUPPORT * LANCZOS_SUPPORT * LANCZOS_TABLE_RES) ; ++i) { if (i == 0) { lanczos_func [i] = LANCZOS_DATA_ONE; } else { float d = sqrt(((float)i) / LANCZOS_TABLE_RES); lanczos_func [i] = (LANCZOS_DATA_TYPE)((LANCZOS_DATA_ONE * LANCZOS_SUPPORT * sin(M_PI * d) * sin((M_PI / LANCZOS_SUPPORT) * d)) / (M_PI * M_PI * d * d)); } } m_priv->lanczos_func = lanczos_func; } #ifdef LANCZOS_DATA_FLOAT static inline int normalizeAndClamp(float norm, int sum, int max) { int r = 0; if (norm != 0.0) { r = sum / norm; } - if (r < 0) + if (r < 0) { r = 0; } else if (r > max) { r = max; } return r; } #else /* LANCZOS_DATA_FLOAT */ static inline int normalizeAndClamp(int norm, int sum, int max) { int r = 0; if (norm != 0) { r = sum / norm; } - if (r < 0) + if (r < 0) { r = 0; } else if (r > max) { r = max; } return r; } #endif /* LANCZOS_DATA_FLOAT */ DColor DImg::getSubPixelColor(float x, float y) const { if (isNull()) { return DColor(); } const LANCZOS_DATA_TYPE* lanczos_func = m_priv->lanczos_func; if (lanczos_func == nullptr) { return DColor(); } x = qBound(0.0f, x, (float)width() - 1); y = qBound(0.0f, y, (float)height() - 1); Digikam::DColor col(0, 0, 0, 0xFFFF, sixteenBit()); #ifdef LANCZOS_DATA_FLOAT float xs = ::ceilf(x) - LANCZOS_SUPPORT; float xe = ::floorf(x) + LANCZOS_SUPPORT; float ys = ::ceilf(y) - LANCZOS_SUPPORT; float ye = ::floorf(y) + LANCZOS_SUPPORT; - if (xs >= 0 && ys >= 0 && xe < width() && ye < height()) + if ((xs >= 0) && (ys >= 0) && (xe < width()) && (ye < height())) { float norm = 0.0; float sumR = 0.0; float sumG = 0.0; float sumB = 0.0; float _dx = x - xs; float dy = y - ys; - for (; ys <= ye; ys += 1.0, dy -= 1.0) + for ( ; ys <= ye ; ys += 1.0, dy -= 1.0) { float xc, dx = _dx; - for (xc = xs; xc <= xe; xc += 1.0, dx -= 1.0) + for (xc = xs ; xc <= xe ; xc += 1.0, dx -= 1.0) { uchar* const data = bits() + (int)(xs * bytesDepth()) + (int)(width() * ys * bytesDepth()); DColor src = DColor(data, sixteenBit()); float d = dx * dx + dy * dy; if (d >= LANCZOS_SUPPORT * LANCZOS_SUPPORT) { continue; } d = lanczos_func [(int)(d * LANCZOS_TABLE_RES)]; norm += d; sumR += d * src.red(); sumG += d * src.green(); sumB += d * src.blue(); } } int max = sixteenBit() ? 65535 : 255; col.setRed(normalizeAndClamp(norm, sumR, max)); col.setGreen(normalizeAndClamp(norm, sumG, max)); col.setBlue(normalizeAndClamp(norm, sumB, max)); } #else /* LANCZOS_DATA_FLOAT */ - /* Do it in integer arithmetic, it's faster */ + // Do it in integer arithmetic, it's faster + int xx = (int)x; int yy = (int)y; int xs = xx + 1 - LANCZOS_SUPPORT; int xe = xx + LANCZOS_SUPPORT; int ys = yy + 1 - LANCZOS_SUPPORT; int ye = yy + LANCZOS_SUPPORT; int norm = 0; int sumR = 0; int sumG = 0; int sumB = 0; int _dx = (int)(x * 4096.0) - (xs << 12); int dy = (int)(y * 4096.0) - (ys << 12); - for (; ys <= ye; ++ys, dy -= 4096) + for ( ; ys <= ye ; ++ys, dy -= 4096) { - int xc, dx = _dx; + int xc; + int dx = _dx; - for (xc = xs; xc <= xe; ++xc, dx -= 4096) + for (xc = xs ; xc <= xe ; ++xc, dx -= 4096) { DColor src(0, 0, 0, 0xFFFF, sixteenBit()); - if (xc >= 0 && ys >= 0 && xc < (int)width() && ys < (int)height()) + if ((xc >= 0) && (ys >= 0) && (xc < (int)width()) && (ys < (int)height())) { uchar* const data = bits() + xc * bytesDepth() + width() * ys * bytesDepth(); src.setColor(data, sixteenBit()); } int d = (dx * dx + dy * dy) >> 12; - if (d >= 4096 * LANCZOS_SUPPORT * LANCZOS_SUPPORT) + if (d >= (4096 * LANCZOS_SUPPORT * LANCZOS_SUPPORT)) { continue; } d = lanczos_func [(d * LANCZOS_TABLE_RES) >> 12]; norm += d; sumR += d * src.red(); sumG += d * src.green(); sumB += d * src.blue(); } } int max = sixteenBit() ? 65535 : 255; col.setRed(normalizeAndClamp(norm, sumR, max)); col.setGreen(normalizeAndClamp(norm, sumG, max)); col.setBlue(normalizeAndClamp(norm, sumB, max)); #endif /* LANCZOS_DATA_FLOAT */ return col; } DColor DImg::getSubPixelColorFast(float x, float y) const { if (isNull()) { return DColor(); } x = qBound(0.0f, x, (float)width() - 1); y = qBound(0.0f, y, (float)height() - 1); int xx = (int)x; int yy = (int)y; float d_x = x - (int)x; float d_y = y - (int)y; uchar* data = nullptr; (void)data; // To prevent cppcheck warnings. DColor d00, d01, d10, d11; DColor col; data = bits() + xx * bytesDepth() + yy * width() * bytesDepth(); d00.setColor(data, sixteenBit()); if ((xx + 1) < (int)width()) { data = bits() + (xx + 1) * bytesDepth() + yy * width() * bytesDepth(); d10.setColor(data, sixteenBit()); } if ((yy + 1) < (int)height()) { data = bits() + xx * bytesDepth() + (yy + 1) * width() * bytesDepth(); d01.setColor(data, sixteenBit()); } - if ((xx + 1) < (int)width() && (yy + 1) < (int)height()) + if (((xx + 1) < (int)width()) && ((yy + 1) < (int)height())) { data = bits() + (xx + 1) * bytesDepth() + (yy + 1) * width() * bytesDepth(); d11.setColor(data, sixteenBit()); } d00.multiply(1.0 - d_x); d00.multiply(1.0 - d_y); d10.multiply(d_x); d10.multiply(1.0 - d_y); d01.multiply(1.0 - d_x); d01.multiply(d_y); d11.multiply(d_x); d11.multiply(d_y); col.blendAdd(d00); col.blendAdd(d10); col.blendAdd(d01); col.blendAdd(d11); if (sixteenBit()) { col.blendClamp16(); } else { col.blendClamp8(); } return col; } void DImg::setPixelColor(uint x, uint y, const DColor& color) { - if (m_priv->null || x >= m_priv->width || y >= m_priv->height) + if (m_priv->null || (x >= m_priv->width) || (y >= m_priv->height)) { return; } if (color.sixteenBit() != m_priv->sixteenBit) { return; } int depth = bytesDepth(); uchar* const data = m_priv->data + x * depth + (m_priv->width * y * depth); color.setPixel(data); } bool DImg::hasTransparentPixels() const { if (m_priv->null || !m_priv->alpha) { return false; } const uint w = m_priv->width; const uint h = m_priv->height; if (!m_priv->sixteenBit) // 8 bits image. { uchar* srcPtr = m_priv->data; - for (uint j = 0; j < h; ++j) + for (uint j = 0 ; j < h ; ++j) { - for (uint i = 0; i < w; ++i) + for (uint i = 0 ; i < w ; ++i) { if (srcPtr[3] != 0xFF) { return true; } srcPtr += 4; } } } else { unsigned short* srcPtr = reinterpret_cast(m_priv->data); - for (uint j = 0; j < h; ++j) + for (uint j = 0 ; j < h ; ++j) { - for (uint i = 0; i < w; ++i) + for (uint i = 0 ; i < w ; ++i) { if (srcPtr[3] != 0xFFFF) { return true; } srcPtr += 4; } } } return false; } } // namespace Digikam diff --git a/core/libs/dimg/dimg_qimage.cpp b/core/libs/dimg/dimg_qimage.cpp index da6904de56..3174d8d6fc 100644 --- a/core/libs/dimg/dimg_qimage.cpp +++ b/core/libs/dimg/dimg_qimage.cpp @@ -1,107 +1,107 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2005-06-14 * Description : digiKam 8/16 bits image management API. * QImage accessors. * * Copyright (C) 2005-2020 by Gilles Caulier * Copyright (C) 2006-2013 by Marcel Wiesweg * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "dimg_p.h" namespace Digikam { QImage DImg::copyQImage() const { if (isNull()) { return QImage(); } if (sixteenBit()) { DImg img(*this); img.detach(); img.convertDepth(32); return img.copyQImage(); } QImage img(width(), height(), QImage::Format_ARGB32); if (img.isNull()) { qCDebug(DIGIKAM_DIMG_LOG) << "Failed to allocate memory to copy DImg of size" << size() << "to QImage"; return QImage(); } uchar* sptr = bits(); uint* dptr = reinterpret_cast(img.bits()); - for (uint i = 0; i < width()*height(); ++i) + for (uint i = 0 ; i < width()*height() ; ++i) { *dptr++ = qRgba(sptr[2], sptr[1], sptr[0], sptr[3]); - sptr += 4; + sptr += 4; } // NOTE: Qt4 do not provide anymore QImage::setAlphaChannel() because // alpha channel is auto-detected during QImage->QPixmap conversion return img; } QImage DImg::copyQImage(const QRect& rect) const { return (copyQImage(rect.x(), rect.y(), rect.width(), rect.height())); } QImage DImg::copyQImage(const QRectF& rel) const { if (isNull() || !rel.isValid()) { return QImage(); } return copyQImage(QRectF(rel.x() * m_priv->width, rel.y() * m_priv->height, rel.width() * m_priv->width, rel.height() * m_priv->height) .toRect()); } QImage DImg::copyQImage(int x, int y, int w, int h) const { if (isNull()) { return QImage(); } DImg img = copy(x, y, w, h); if (img.sixteenBit()) { img.convertDepth(32); } return img.copyQImage(); } } // namespace Digikam diff --git a/core/libs/dimg/dimg_qpixmap.cpp b/core/libs/dimg/dimg_qpixmap.cpp index f813ecfb4a..1a55ad2320 100644 --- a/core/libs/dimg/dimg_qpixmap.cpp +++ b/core/libs/dimg/dimg_qpixmap.cpp @@ -1,283 +1,289 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2005-06-14 * Description : digiKam 8/16 bits image management API. * QPixmap accessors. * * Copyright (C) 2005-2020 by Gilles Caulier * Copyright (C) 2006-2013 by Marcel Wiesweg * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "dimg_p.h" namespace Digikam { class Q_DECL_HIDDEN PixmapPaintEngineDetector { public: PixmapPaintEngineDetector() : m_isRaster(detectRasterFromPixmap()) { } bool isRaster() const { return m_isRaster; } private: static bool detectRasterFromPixmap() { QPixmap pix(1, 1); QPainter p(&pix); - return (p.paintEngine() && p.paintEngine()->type() == QPaintEngine::Raster); + return (p.paintEngine() && (p.paintEngine()->type() == QPaintEngine::Raster)); } const bool m_isRaster; }; Q_GLOBAL_STATIC(PixmapPaintEngineDetector, pixmapPaintEngineDetector) // -------------------------------------------------------------------------------------- QPixmap DImg::convertToPixmap() const { if (isNull()) { return QPixmap(); } if (sixteenBit()) { - // make fastaaaa... + // make faster... + return QPixmap::fromImage(copyQImage(0, 0, width(), height())); } if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { QImage img(width(), height(), hasAlpha() ? QImage::Format_ARGB32 : QImage::Format_RGB32); uchar* sptr = bits(); uint* dptr = reinterpret_cast(img.bits()); uint dim = width() * height(); - for (uint i = 0; i < dim; ++i) + for (uint i = 0 ; i < dim ; ++i) { *dptr++ = qRgba(sptr[2], sptr[1], sptr[0], sptr[3]); - sptr += 4; + sptr += 4; } // alpha channel is auto-detected during QImage->QPixmap conversion + return QPixmap::fromImage(img); } else { // This is a temporary image operating on the DImg buffer + QImage img(bits(), width(), height(), hasAlpha() ? QImage::Format_ARGB32 : QImage::Format_RGB32); // For paint engines which base the QPixmap internally on a QImage, we must use a persistent QImage + if (pixmapPaintEngineDetector->isRaster()) { img = img.copy(); } // alpha channel is auto-detected during QImage->QPixmap conversion + return QPixmap::fromImage(img); } } QPixmap DImg::convertToPixmap(IccTransform& monitorICCtrans) const { if (isNull()) { return QPixmap(); } if (monitorICCtrans.outputProfile().isNull()) { return convertToPixmap(); } DImg img = copy(); monitorICCtrans.apply(img); return (img.convertToPixmap()); } QImage DImg::pureColorMask(ExposureSettingsContainer* const expoSettings) const { if (isNull() || (!expoSettings->underExposureIndicator && !expoSettings->overExposureIndicator)) { return QImage(); } QImage img(size(), QImage::Format_ARGB32); img.fill(0x00000000); // Full transparent. // NOTE: Qt4 do not provide anymore QImage::setAlphaChannel() because // alpha channel is auto-detected during QImage->QPixmap conversion uchar* bits = img.bits(); // NOTE: Using DImgScale before to compute Mask clamp to 65534 | 254. Why ? int max = lround(sixteenBit() ? 65535.0 - (65535.0 * expoSettings->overExposurePercent / 100.0) : 255.0 - (255.0 * expoSettings->overExposurePercent / 100.0)); int min = lround(sixteenBit() ? 0.0 + (65535.0 * expoSettings->underExposurePercent / 100.0) : 0.0 + (255.0 * expoSettings->underExposurePercent / 100.0)); // -------------------------------------------------------- // caching + int u_red = expoSettings->underExposureColor.red(); int u_green = expoSettings->underExposureColor.green(); int u_blue = expoSettings->underExposureColor.blue(); int o_red = expoSettings->overExposureColor.red(); int o_green = expoSettings->overExposureColor.green(); int o_blue = expoSettings->overExposureColor.blue(); bool under = expoSettings->underExposureIndicator; bool over = expoSettings->overExposureIndicator; bool pure = expoSettings->exposureIndicatorMode; // -------------------------------------------------------- uint dim = m_priv->width * m_priv->height; uchar* dptr = bits; int s_blue, s_green, s_red; bool match = false; if (sixteenBit()) { unsigned short* sptr = reinterpret_cast(m_priv->data); - for (uint i = 0; i < dim; ++i) + for (uint i = 0 ; i < dim ; ++i) { s_blue = *sptr++; s_green = *sptr++; s_red = *sptr++; sptr++; match = pure ? (s_red <= min) && (s_green <= min) && (s_blue <= min) : (s_red <= min) || (s_green <= min) || (s_blue <= min); if (under && match) { if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { dptr[0] = 0xFF; dptr[1] = u_red; dptr[2] = u_green; dptr[3] = u_blue; } else { dptr[0] = u_blue; dptr[1] = u_green; dptr[2] = u_red; dptr[3] = 0xFF; } } match = pure ? (s_red >= max) && (s_green >= max) && (s_blue >= max) : (s_red >= max) || (s_green >= max) || (s_blue >= max); if (over && match) { if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { dptr[0] = 0xFF; dptr[1] = o_red; dptr[2] = o_green; dptr[3] = o_blue; } else { dptr[0] = o_blue; dptr[1] = o_green; dptr[2] = o_red; dptr[3] = 0xFF; } } dptr += 4; } } else { uchar* sptr = m_priv->data; - for (uint i = 0; i < dim; ++i) + for (uint i = 0 ; i < dim ; ++i) { s_blue = *sptr++; s_green = *sptr++; s_red = *sptr++; sptr++; match = pure ? (s_red <= min) && (s_green <= min) && (s_blue <= min) : (s_red <= min) || (s_green <= min) || (s_blue <= min); if (under && match) { if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { dptr[0] = 0xFF; dptr[1] = u_red; dptr[2] = u_green; dptr[3] = u_blue; } else { dptr[0] = u_blue; dptr[1] = u_green; dptr[2] = u_red; dptr[3] = 0xFF; } } match = pure ? (s_red >= max) && (s_green >= max) && (s_blue >= max) : (s_red >= max) || (s_green >= max) || (s_blue >= max); if (over && match) { if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { dptr[0] = 0xFF; dptr[1] = o_red; dptr[2] = o_green; dptr[3] = o_blue; } else { dptr[0] = o_blue; dptr[1] = o_green; dptr[2] = o_red; dptr[3] = 0xFF; } } dptr += 4; } } return img; } } // namespace Digikam diff --git a/core/libs/dimg/dimg_scale.cpp b/core/libs/dimg/dimg_scale.cpp index a541f92174..34d664015d 100644 --- a/core/libs/dimg/dimg_scale.cpp +++ b/core/libs/dimg/dimg_scale.cpp @@ -1,2463 +1,2492 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2005-06-14 * Description : digiKam 8/16 bits image management API. * Description : Smoothscale method based on Imlib2's implementations. * https://git.enlightenment.org/legacy/imlib2.git/tree/src/lib/scale.c * Ported to C++ and QImage * Add smoothScaleSection to scale only an image section. * Add 16 bits color depth image support. * * Copyright (C) 1999-2004 by Carsten Haitzler * Copyright (C) 2004 by Willem Monsuwe * Copyright (C) 2005 by Renchi Raju * Copyright (C) 2005 by Daniel M. Duley * Copyright (C) 2006-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ // C ANSI includes extern "C" { #include } // C++ includes #include #include #include // Local includes #include "digikam_debug.h" #include "dimg.h" #include "dimg_p.h" typedef uint64_t ullong; // krazy:exclude=typedefs typedef int64_t llong; // krazy:exclude=typedefs namespace Digikam { namespace DImgScale { class Q_DECL_HIDDEN DImgScaleInfo { public: DImgScaleInfo() : xpoints(nullptr), ypoints(nullptr), ypoints16(nullptr), xapoints(nullptr), yapoints(nullptr), xup_yup(0) { } ~DImgScaleInfo() { delete [] xpoints; delete [] ypoints; delete [] ypoints16; delete [] xapoints; delete [] yapoints; } int* xpoints; uint** ypoints; ullong** ypoints16; int* xapoints; int* yapoints; int xup_yup; }; uint** dimgCalcYPoints(uint* const src, int sw, int sh, int dh); ullong** dimgCalcYPoints16(ullong* const src, int sw, int sh, int dh); int* dimgCalcXPoints(int sw, int dw); int* dimgCalcApoints(int s, int d, int up); DImgScaleInfo* dimgCalcScaleInfo(const DImg& img, int sw, int sh, int dw, int dh, bool aa); // 8 bit, not smoothed void dimgSampleRGBA(DImgScaleInfo* const isi, uint* const dest, int dxx, int dyy, int dw, int dh, int dow); void dimgSampleRGBA(DImgScaleInfo* const isi, uint* const dest, int dxx, int dyy, int dw, int dh, int dow, int clip_dx, int clip_dy, int clip_dw, int clip_dh); // 16 bit, not smoothed void dimgSampleRGBA16(DImgScaleInfo* const isi, ullong* const dest, int dxx, int dyy, int dw, int dh, int dow); void dimgSampleRGBA16(DImgScaleInfo* const isi, ullong* const dest, int dxx, int dyy, int dw, int dh, int dow, int clip_dx, int clip_dy, int clip_dw, int clip_dh); // 8 bit, RGBA void dimgScaleAARGBA(DImgScaleInfo* const isi, uint* const dest, int dxx, int dyy, int dw, int dh, int dow, int sow); void dimgScaleAARGBA(DImgScaleInfo* const isi, uint* const dest, int dxx, int dyy, int dw, int dh, int dow, int sow, int clip_dx, int clip_dy, int clip_dw, int clip_dh); // 8 bit, RGB void dimgScaleAARGB(DImgScaleInfo* const isi, uint* const dest, int dxx, int dyy, int dw, int dh, int dow, int sow); void dimgScaleAARGB(DImgScaleInfo* const isi, uint* const dest, int dxx, int dyy, int dw, int dh, int dow, int sow, int clip_dx, int clip_dy, int clip_dw, int clip_dh); // 16 bit, RGBA void dimgScaleAARGBA16(DImgScaleInfo* const isi, ullong* const dest, int dxx, int dyy, int dw, int dh, int dow, int sow); void dimgScaleAARGBA16(DImgScaleInfo* const isi, ullong* const dest, int dxx, int dyy, int dw, int dh, int dow, int sow, int clip_dx, int clip_dy, int clip_dw, int clip_dh); // 16 bit, RGB void dimgScaleAARGB16(DImgScaleInfo* const isi, ullong* const dest, int dxx, int dyy, int dw, int dh, int dow, int sow); void dimgScaleAARGB16(DImgScaleInfo* const isi, ullong* const dest, int dxx, int dyy, int dw, int dh, int dow, int sow, int clip_dx, int clip_dy, int clip_dw, int clip_dh); } using namespace DImgScale; /* #define CLIP(x, y, w, h, xx, yy, ww, hh) \ if (x < (xx)) {w += (x - (xx)); x = (xx);} \ if (y < (yy)) {h += (y - (yy)); y = (yy);} \ if ((x + w) > ((xx) + (ww))) {w = (ww) - (x - xx);} \ if ((y + h) > ((yy) + (hh))) {h = (hh) - (y - yy);} */ DImg DImg::smoothScale(const QSize& destSize, Qt::AspectRatioMode aspectRatioMode) const { QSize scaleSize = size(); scaleSize.scale(destSize, aspectRatioMode); if (scaleSize.isEmpty()) { return DImg(); } return smoothScaleClipped(scaleSize, QRect(QPoint(0, 0), scaleSize)); } DImg DImg::smoothScale(int dw, int dh, Qt::AspectRatioMode aspectRatioMode) const { return smoothScale(QSize(dw, dh), aspectRatioMode); } DImg DImg::smoothScaleClipped(const QSize& destSize, const QRect& clip) const { return DImg::smoothScaleClipped(destSize.width(), destSize.height(), clip.x(), clip.y(), clip.width(), clip.height()); } DImg DImg::smoothScaleClipped(int dw, int dh, int clipx, int clipy, int clipw, int cliph) const { - if (dw <= 0 || dh <= 0 || clipw <= 0 || cliph <= 0 || isNull()) + if ((dw <= 0) || (dh <= 0) || (clipw <= 0) || (cliph <= 0) || isNull()) { return DImg(); } uint w = width(); uint h = height(); - if (w <= 0 || h <= 0) + if ((w <= 0) || (h <= 0)) { return DImg(); } // ensure clip is valid if (!clipped(clipx, clipy, clipw, cliph, dw, dh)) { return DImg(); } // do we actually need to scale? if ((w == (uint)dw) && (h == (uint)dh)) { - if (clipw == dw && cliph == dh) + if ((clipw == dw) && (cliph == dh)) { return copy(); } else { return copy(clipx, clipy, clipw, cliph); } } DImgScaleInfo* const scaleinfo = dimgCalcScaleInfo(*this, w, h, dw, dh, true); DImg buffer(*this, clipw, cliph); if (sixteenBit()) { if (hasAlpha()) { dimgScaleAARGBA16(scaleinfo, reinterpret_cast(buffer.bits()), 0, 0, dw, dh, clipw, w, clipx, clipy, clipw, cliph); } else { dimgScaleAARGB16(scaleinfo, reinterpret_cast(buffer.bits()), 0, 0, dw, dh, clipw, w, clipx, clipy, clipw, cliph); } } else { if (hasAlpha()) { dimgScaleAARGBA(scaleinfo, reinterpret_cast(buffer.bits()), 0, 0, dw, dh, clipw, w, clipx, clipy, clipw, cliph); } else { dimgScaleAARGB(scaleinfo, reinterpret_cast(buffer.bits()), 0, 0, dw, dh, clipw, w, clipx, clipy, clipw, cliph); } } delete scaleinfo; return buffer; } DImg DImg::smoothScaleSection(const QRect& sourceRect, const QSize& destSize) const { return smoothScaleSection(sourceRect.x(), sourceRect.y(), sourceRect.width(), sourceRect.height(), destSize.width(), destSize.height()); } DImg DImg::smoothScaleSection(int sx, int sy, int sw, int sh, int dw, int dh) const { uint w = width(); uint h = height(); // sanity checks if ((dw <= 0) || (dh <= 0)) { return DImg(); } if ((sw <= 0) || (sh <= 0)) { return DImg(); } // clip the source rect to be within the actual image int /*psx, psy,*/ psw, psh; // psx = sx; // psy = sy; psw = sw; psh = sh; if (!clipped(sx, sy, sw, sh, w, h)) { return DImg(); } // clip output coords to clipped input coords if (psw != sw) { dw = (dw * sw) / psw; } if (psh != sh) { dh = (dh * sh) / psh; } // do a second check to see if we now have invalid coords // do not do anything if we have a 0 width or height image to render if ((dw <= 0) || (dh <= 0)) { return DImg(); } // if the input rect size < 0 do not render either if ((sw <= 0) || (sh <= 0)) { return DImg(); } // do we actually need to scale? if ((sw == dw) && (sh == dh)) { return copy(sx, sy, sw, sh); } // calculate scaleinfo DImgScaleInfo* const scaleinfo = dimgCalcScaleInfo(*this, sw, sh, dw, dh, true); DImg buffer(*this, dw, dh); if (sixteenBit()) { if (hasAlpha()) { dimgScaleAARGBA16(scaleinfo, reinterpret_cast(buffer.bits()), ((sx * dw) / sw), ((sy * dh) / sh), dw, dh, dw, w); } else { dimgScaleAARGB16(scaleinfo, reinterpret_cast(buffer.bits()), ((sx * dw) / sw), ((sy * dh) / sh), dw, dh, dw, w); } } else { if (hasAlpha()) { dimgScaleAARGBA(scaleinfo, reinterpret_cast(buffer.bits()), ((sx * dw) / sw), ((sy * dh) / sh), dw, dh, dw, w); } else { dimgScaleAARGB(scaleinfo, reinterpret_cast(buffer.bits()), ((sx * dw) / sw), ((sy * dh) / sh), dw, dh, dw, w); } } delete scaleinfo; return buffer; } // // Code ported from Imlib2... // // FIXME: replace with mRed, etc... These work on pointers to pixels, not // pixel values #define A_VAL(p) ((unsigned char*)(p))[3] #define R_VAL(p) ((unsigned char*)(p))[2] #define G_VAL(p) ((unsigned char*)(p))[1] #define B_VAL(p) ((unsigned char*)(p))[0] #define INV_XAP (256 - xapoints[x]) #define XAP (xapoints[x]) #define INV_YAP (256 - yapoints[dyy + y]) #define YAP (yapoints[dyy + y]) uint** DImgScale::dimgCalcYPoints(uint* const src, int sw, int sh, int dh) { uint** p = nullptr; (void)p; // To prevent cppcheck warnings. int i, j = 0; ullong val, inc; p = new uint* [dh+1]; val = 0; inc = (((ullong)sh) << 16) / dh; for (i = 0 ; i < dh ; ++i) { p[j++] = src + ((val >> 16) * sw); - val += inc; + val += inc; } return(p); } ullong** DImgScale::dimgCalcYPoints16(ullong* const src, int sw, int sh, int dh) { ullong** p = nullptr; (void)p; // To prevent cppcheck warnings. int i, j = 0; ullong val, inc; p = new ullong*[(dh+1)]; val = 0; inc = (((ullong)sh) << 16) / dh; for (i = 0 ; i < dh ; ++i) { p[j++] = src + ((val >> 16) * sw); val += inc; } return p; } int* DImgScale::dimgCalcXPoints(int sw, int dw) { int* p = nullptr, i, j = 0; (void)p; // To prevent cppcheck warnings. ullong val, inc; p = new int[dw+1]; val = 0; inc = (((ullong)sw) << 16) / dw; for (i = 0 ; i < dw ; ++i) { p[j++] = (val >> 16); val += inc; } return(p); } int* DImgScale::dimgCalcApoints(int s, int d, int up) { int* p = nullptr, i, j = 0; (void)p; // To prevent cppcheck warnings. p = new int[d]; - /* scaling up */ if (up) { + // scaling up ullong val, inc; val = 0; inc = (((ullong)s) << 16) / d; for (i = 0 ; i < d ; ++i) { p[j++] = (val >> 8) - ((val >> 8) & 0xffffff00); if ((int)(val >> 16) >= (s - 1)) { p[j - 1] = 0; } - val += inc; + val += inc; } } - /* scaling down */ else { + // scaling down ullong val, inc; int ap, Cp; val = 0; inc = (((ullong)s) << 16) / d; Cp = ((d << 14) / s) + 1; for (i = 0 ; i < d ; ++i) { ap = ((0x100 - ((val >> 8) & 0xff)) * Cp) >> 8; p[j] = ap | (Cp << 16); ++j; - val += inc; + val += inc; } } return(p); } DImgScaleInfo* DImgScale::dimgCalcScaleInfo(const DImg& img, int sw, int sh, int dw, int dh, bool aa) { DImgScaleInfo* const isi = new DImgScaleInfo; int scw, sch; scw = dw * img.width() / sw; sch = dh * img.height() / sh; isi->xup_yup = (abs(dw) >= sw) + ((abs(dh) >= sh) << 1); isi->xpoints = dimgCalcXPoints(img.width(), scw); if (img.sixteenBit()) { isi->ypoints = nullptr; isi->ypoints16 = dimgCalcYPoints16(reinterpret_cast(img.bits()), img.width(), img.height(), sch); } else { isi->ypoints16 = nullptr; isi->ypoints = dimgCalcYPoints(reinterpret_cast(img.bits()), img.width(), img.height(), sch); } if (aa) { isi->xapoints = dimgCalcApoints(img.width(), scw, isi->xup_yup & 1); isi->yapoints = dimgCalcApoints(img.height(), sch, isi->xup_yup & 2); } else { isi->xapoints = new int[scw]; - for (int i = 0; i < scw; ++i) + for (int i = 0 ; i < scw ; ++i) { isi->xapoints[i] = 0; } isi->yapoints = new int[sch]; - for (int i = 0; i < sch; ++i) + for (int i = 0 ; i < sch ; ++i) { isi->yapoints[i] = 0; } } return isi; } /** scale by pixel sampling only */ void DImgScale::dimgSampleRGBA(DImgScaleInfo* const isi, uint* const dest, int dxx, int dyy, int dw, int dh, int dow) { dimgSampleRGBA(isi, dest, dxx, dyy, dw, dh, dow, 0, 0, dw, dh); } void DImgScale::dimgSampleRGBA(DImgScaleInfo* const isi, uint* const dest, int dxx, int dyy, int dw, int dh, int dow, int clip_dx, int clip_dy, int clip_dw, int clip_dh) { Q_UNUSED(dw); Q_UNUSED(dh); uint* sptr = nullptr; uint* dptr = nullptr; int x, y; uint** ypoints = isi->ypoints; int* xpoints = isi->xpoints; const int x_begin = dxx + clip_dx; // no clip set = dxx const int x_end = x_begin + clip_dw; // no clip set = dxx + dw const int y_begin = clip_dy; // no clip set = 0 const int y_end = clip_dy + clip_dh; // no clip set = dh /* go through every scanline in the output buffer */ - for (y = y_begin; y < y_end; ++y) + for (y = y_begin ; y < y_end ; ++y) { /* get the pointer to the start of the destination scanline */ dptr = dest + (y - y_begin) * dow; /* calculate the source line we'll scan from */ sptr = ypoints[dyy + y]; /* go through the scanline and copy across */ - for (x = x_begin; x < x_end; ++x) + for (x = x_begin ; x < x_end ; ++x) { *dptr++ = sptr[xpoints[x]]; } } } void DImgScale::dimgSampleRGBA16(DImgScaleInfo* const isi, ullong* const dest, int dxx, int dyy, int dw, int dh, int dow) { dimgSampleRGBA16(isi, dest, dxx, dyy, dw, dh, dow, 0, 0, dw, dh); } void DImgScale::dimgSampleRGBA16(DImgScaleInfo* const isi, ullong* const dest, int dxx, int dyy, int dw, int dh, int dow, int clip_dx, int clip_dy, int clip_dw, int clip_dh) { Q_UNUSED(dw); Q_UNUSED(dh); ullong* sptr = nullptr; ullong* dptr = nullptr; int x, y; ullong** ypoints = isi->ypoints16; int* xpoints = isi->xpoints; const int x_begin = dxx + clip_dx; // no clip set = dxx const int x_end = x_begin + clip_dw; // no clip set = dxx + dw const int y_begin = clip_dy; // no clip set = 0 const int y_end = clip_dy + clip_dh; // no clip set = dh /* go through every scanline in the output buffer */ - for (y = y_begin; y < y_end; ++y) + for (y = y_begin ; y < y_end ; ++y) { /* get the pointer to the start of the destination scanline */ dptr = dest + (y - y_begin) * dow; /* calculate the source line we'll scan from */ sptr = ypoints[dyy + y]; /* go through the scanline and copy across */ - for (x = x_begin; x < x_end; ++x) + for (x = x_begin ; x < x_end ; ++x) { *dptr++ = sptr[xpoints[x]]; } } } /* FIXME: NEED to optimize ScaleAARGBA - currently its "ok" but needs work*/ /** dimgScaleAARGBA : scale by area sampling. Arguments: DImgScaleInfo* isi, // scaleinfo uint* dest, // destination img data int dxx, // destination x location corresponding to start x of src section int dyy, // destination y location corresponding to start y of src section int dw, // destination width int dh, // destination height int dow, // destination scanline width int sow); // src scanline width */ void DImgScale::dimgScaleAARGBA(DImgScaleInfo* const isi, uint* const dest, int dxx, int dyy, int dw, int dh, int dow, int sow) { dimgScaleAARGBA(isi, dest, dxx, dyy, dw, dh, dow, sow, 0, 0, dw, dh); } void DImgScale::dimgScaleAARGBA(DImgScaleInfo* const isi, uint* const dest, int dxx, int dyy, int dw, int dh, int dow, int sow, int clip_dx, int clip_dy, int clip_dw, int clip_dh) { Q_UNUSED(dw); Q_UNUSED(dh); uint* sptr = nullptr; uint* dptr = nullptr; int x, y; uint** ypoints = isi->ypoints; int* xpoints = isi->xpoints; int* xapoints = isi->xapoints; int* yapoints = isi->yapoints; const int x_begin = dxx + clip_dx; // no clip set = dxx const int x_end = x_begin + clip_dw; // no clip set = dxx + dw const int y_begin = clip_dy; // no clip set = 0 const int y_end = clip_dy + clip_dh; // no clip set = dh /* scaling up both ways */ if (isi->xup_yup == 3) { /* go through every scanline in the output buffer */ - for (y = y_begin; y < y_end; ++y) + for (y = y_begin ; y < y_end ; ++y) { /* calculate the source line we'll scan from */ dptr = dest + (y - y_begin) * dow; sptr = ypoints[dyy + y]; if (YAP > 0) { - for (x = x_begin; x < x_end; ++x) + for (x = x_begin ; x < x_end ; ++x) { int r, g, b, a; uint* pix = nullptr; if (XAP > 0) { int rr, gg, bb, aa; pix = ypoints[dyy + y] + xpoints[x]; r = R_VAL(pix) * INV_XAP; g = G_VAL(pix) * INV_XAP; b = B_VAL(pix) * INV_XAP; a = A_VAL(pix) * INV_XAP; ++pix; r += R_VAL(pix) * XAP; g += G_VAL(pix) * XAP; b += B_VAL(pix) * XAP; a += A_VAL(pix) * XAP; pix += sow; rr = R_VAL(pix) * XAP; gg = G_VAL(pix) * XAP; bb = B_VAL(pix) * XAP; aa = A_VAL(pix) * XAP; --pix; rr += R_VAL(pix) * INV_XAP; gg += G_VAL(pix) * INV_XAP; bb += B_VAL(pix) * INV_XAP; aa += A_VAL(pix) * INV_XAP; r = ((rr * YAP) + (r * INV_YAP)) >> 16; g = ((gg * YAP) + (g * INV_YAP)) >> 16; b = ((bb * YAP) + (b * INV_YAP)) >> 16; a = ((aa * YAP) + (a * INV_YAP)) >> 16; A_VAL(dptr) = a; R_VAL(dptr) = r; G_VAL(dptr) = g; B_VAL(dptr) = b; ++dptr; } else { pix = ypoints[dyy + y] + xpoints[x]; r = R_VAL(pix) * INV_YAP; g = G_VAL(pix) * INV_YAP; b = B_VAL(pix) * INV_YAP; a = A_VAL(pix) * INV_YAP; pix += sow; r += R_VAL(pix) * YAP; g += G_VAL(pix) * YAP; b += B_VAL(pix) * YAP; a += A_VAL(pix) * YAP; r >>= 8; g >>= 8; b >>= 8; a >>= 8; A_VAL(dptr) = a; R_VAL(dptr) = r; G_VAL(dptr) = g; B_VAL(dptr) = b; ++dptr; } } } else { - for (x = x_begin; x < x_end; ++x) + for (x = x_begin ; x < x_end ; ++x) { uint* pix = nullptr; if (XAP > 0) { int r, g, b, a; pix = ypoints[dyy + y] + xpoints[x]; r = R_VAL(pix) * INV_XAP; g = G_VAL(pix) * INV_XAP; b = B_VAL(pix) * INV_XAP; a = A_VAL(pix) * INV_XAP; ++pix; r += R_VAL(pix) * XAP; g += G_VAL(pix) * XAP; b += B_VAL(pix) * XAP; a += A_VAL(pix) * XAP; r >>= 8; g >>= 8; b >>= 8; a >>= 8; A_VAL(dptr) = a; R_VAL(dptr) = r; G_VAL(dptr) = g; B_VAL(dptr) = b; ++dptr; } else { *dptr++ = sptr[xpoints[x] ]; } } } } } /* if we're scaling down vertically */ else if (isi->xup_yup == 1) { /*\ 'Correct' version, with math units prepared for MMXification \*/ int Cy, j; uint* pix = nullptr; int r, g, b, a, rr, gg, bb, aa; int yap; /* go through every scanline in the output buffer */ - for (y = y_begin; y < y_end; ++y) + for (y = y_begin ; y < y_end ; ++y) { Cy = YAP >> 16; yap = YAP & 0xffff; dptr = dest + (y - y_begin) * dow; - for (x = x_begin; x < x_end; ++x) + for (x = x_begin ; x < x_end ; ++x) { pix = ypoints[dyy + y] + xpoints[x]; r = (R_VAL(pix) * yap) >> 10; g = (G_VAL(pix) * yap) >> 10; b = (B_VAL(pix) * yap) >> 10; a = (A_VAL(pix) * yap) >> 10; - for (j = (1 << 14) - yap; j > Cy; j -= Cy) + for (j = (1 << 14) - yap ; j > Cy ; j -= Cy) { pix += sow; r += (R_VAL(pix) * Cy) >> 10; g += (G_VAL(pix) * Cy) >> 10; b += (B_VAL(pix) * Cy) >> 10; a += (A_VAL(pix) * Cy) >> 10; } if (j > 0) { pix += sow; r += (R_VAL(pix) * j) >> 10; g += (G_VAL(pix) * j) >> 10; b += (B_VAL(pix) * j) >> 10; a += (A_VAL(pix) * j) >> 10; } if (XAP > 0) { pix = ypoints[dyy + y] + xpoints[x] + 1; rr = (R_VAL(pix) * yap) >> 10; gg = (G_VAL(pix) * yap) >> 10; bb = (B_VAL(pix) * yap) >> 10; aa = (A_VAL(pix) * yap) >> 10; - for (j = (1 << 14) - yap; j > Cy; j -= Cy) + for (j = (1 << 14) - yap ; j > Cy ; j -= Cy) { pix += sow; rr += (R_VAL(pix) * Cy) >> 10; gg += (G_VAL(pix) * Cy) >> 10; bb += (B_VAL(pix) * Cy) >> 10; aa += (A_VAL(pix) * Cy) >> 10; } if (j > 0) { pix += sow; rr += (R_VAL(pix) * j) >> 10; gg += (G_VAL(pix) * j) >> 10; bb += (B_VAL(pix) * j) >> 10; aa += (A_VAL(pix) * j) >> 10; } r = r * INV_XAP; g = g * INV_XAP; b = b * INV_XAP; a = a * INV_XAP; r = (r + ((rr * XAP))) >> 12; g = (g + ((gg * XAP))) >> 12; b = (b + ((bb * XAP))) >> 12; a = (a + ((aa * XAP))) >> 12; } else { r >>= 4; g >>= 4; b >>= 4; a >>= 4; } A_VAL(dptr) = a; R_VAL(dptr) = r; G_VAL(dptr) = g; B_VAL(dptr) = b; ++dptr; } } } /* if we're scaling down horizontally */ else if (isi->xup_yup == 2) { - /*\ 'Correct' version, with math units prepared for MMXification \*/ + // 'Correct' version, with math units prepared for MMXification + int Cx, j; uint* pix = nullptr; int r, g, b, a, rr, gg, bb, aa; int xap; - /* go through every scanline in the output buffer */ - for (y = y_begin; y < y_end; ++y) + // go through every scanline in the output buffer + + for (y = y_begin ; y < y_end ; ++y) { dptr = dest + (y - y_begin) * dow; - for (x = x_begin; x < x_end; ++x) + for (x = x_begin ; x < x_end ; ++x) { Cx = XAP >> 16; xap = XAP & 0xffff; pix = ypoints[dyy + y] + xpoints[x]; r = (R_VAL(pix) * xap) >> 10; g = (G_VAL(pix) * xap) >> 10; b = (B_VAL(pix) * xap) >> 10; a = (A_VAL(pix) * xap) >> 10; - for (j = (1 << 14) - xap; j > Cx; j -= Cx) + for (j = (1 << 14) - xap ; j > Cx ; j -= Cx) { ++pix; r += (R_VAL(pix) * Cx) >> 10; g += (G_VAL(pix) * Cx) >> 10; b += (B_VAL(pix) * Cx) >> 10; a += (A_VAL(pix) * Cx) >> 10; } if (j > 0) { ++pix; r += (R_VAL(pix) * j) >> 10; g += (G_VAL(pix) * j) >> 10; b += (B_VAL(pix) * j) >> 10; a += (A_VAL(pix) * j) >> 10; } if (YAP > 0) { pix = ypoints[dyy + y] + xpoints[x] + sow; rr = (R_VAL(pix) * xap) >> 10; gg = (G_VAL(pix) * xap) >> 10; bb = (B_VAL(pix) * xap) >> 10; aa = (A_VAL(pix) * xap) >> 10; - for (j = (1 << 14) - xap; j > Cx; j -= Cx) + for (j = (1 << 14) - xap ; j > Cx ; j -= Cx) { ++pix; rr += (R_VAL(pix) * Cx) >> 10; gg += (G_VAL(pix) * Cx) >> 10; bb += (B_VAL(pix) * Cx) >> 10; aa += (A_VAL(pix) * Cx) >> 10; } if (j > 0) { ++pix; rr += (R_VAL(pix) * j) >> 10; gg += (G_VAL(pix) * j) >> 10; bb += (B_VAL(pix) * j) >> 10; aa += (A_VAL(pix) * j) >> 10; } r = r * INV_YAP; g = g * INV_YAP; b = b * INV_YAP; a = a * INV_YAP; r = (r + ((rr * YAP))) >> 12; g = (g + ((gg * YAP))) >> 12; b = (b + ((bb * YAP))) >> 12; a = (a + ((aa * YAP))) >> 12; } else { r >>= 4; g >>= 4; b >>= 4; a >>= 4; } A_VAL(dptr) = a; R_VAL(dptr) = r; G_VAL(dptr) = g; B_VAL(dptr) = b; ++dptr; } } } /* if we're scaling down horizontally & vertically */ else { - /*\ 'Correct' version, with math units prepared for MMXification: - |*| The operation 'b = (b * c) >> 16' translates to pmulhw, - |*| so the operation 'b = (b * c) >> d' would translate to - |*| psllw (16 - d), %mmb; pmulh %mmc, %mmb - \*/ + /** + *'Correct' version, with math units prepared for MMXification: + * The operation 'b = (b * c) >> 16' translates to pmulhw, + * so the operation 'b = (b * c) >> d' would translate to + * psllw (16 - d), %mmb; pmulh %mmc, %mmb + */ int Cx, Cy, i, j; uint* pix = nullptr; int a, r, g, b, ax, rx, gx, bx; int xap, yap; - for (y = y_begin; y < y_end; ++y) + for (y = y_begin ; y < y_end ; ++y) { Cy = YAP >> 16; yap = YAP & 0xffff; dptr = dest + (y - y_begin) * dow; - for (x = x_begin; x < x_end; ++x) + for (x = x_begin ; x < x_end ; ++x) { Cx = XAP >> 16; xap = XAP & 0xffff; if (ypoints && xpoints) { sptr = ypoints[dyy + y] + xpoints[x]; pix = sptr; sptr += sow; rx = (R_VAL(pix) * xap) >> 9; gx = (G_VAL(pix) * xap) >> 9; bx = (B_VAL(pix) * xap) >> 9; ax = (A_VAL(pix) * xap) >> 9; ++pix; - for (i = (1 << 14) - xap; i > Cx; i -= Cx) + for (i = (1 << 14) - xap ; i > Cx ; i -= Cx) { rx += (R_VAL(pix) * Cx) >> 9; gx += (G_VAL(pix) * Cx) >> 9; bx += (B_VAL(pix) * Cx) >> 9; ax += (A_VAL(pix) * Cx) >> 9; ++pix; } if (i > 0) { rx += (R_VAL(pix) * i) >> 9; gx += (G_VAL(pix) * i) >> 9; bx += (B_VAL(pix) * i) >> 9; ax += (A_VAL(pix) * i) >> 9; } r = (rx * yap) >> 14; g = (gx * yap) >> 14; b = (bx * yap) >> 14; a = (ax * yap) >> 14; - for (j = (1 << 14) - yap; j > Cy; j -= Cy) + for (j = (1 << 14) - yap ; j > Cy ; j -= Cy) { pix = sptr; sptr += sow; rx = (R_VAL(pix) * xap) >> 9; gx = (G_VAL(pix) * xap) >> 9; bx = (B_VAL(pix) * xap) >> 9; ax = (A_VAL(pix) * xap) >> 9; ++pix; - for (i = (1 << 14) - xap; i > Cx; i -= Cx) + for (i = (1 << 14) - xap ; i > Cx ; i -= Cx) { rx += (R_VAL(pix) * Cx) >> 9; gx += (G_VAL(pix) * Cx) >> 9; bx += (B_VAL(pix) * Cx) >> 9; ax += (A_VAL(pix) * Cx) >> 9; ++pix; } if (i > 0) { rx += (R_VAL(pix) * i) >> 9; gx += (G_VAL(pix) * i) >> 9; bx += (B_VAL(pix) * i) >> 9; ax += (A_VAL(pix) * i) >> 9; } r += (rx * Cy) >> 14; g += (gx * Cy) >> 14; b += (bx * Cy) >> 14; a += (ax * Cy) >> 14; } if (j > 0) { pix = sptr; sptr += sow; (void)sptr; // disable clang warning. rx = (R_VAL(pix) * xap) >> 9; gx = (G_VAL(pix) * xap) >> 9; bx = (B_VAL(pix) * xap) >> 9; ax = (A_VAL(pix) * xap) >> 9; ++pix; - for (i = (1 << 14) - xap; i > Cx; i -= Cx) + for (i = (1 << 14) - xap ; i > Cx ; i -= Cx) { rx += (R_VAL(pix) * Cx) >> 9; gx += (G_VAL(pix) * Cx) >> 9; bx += (B_VAL(pix) * Cx) >> 9; ax += (A_VAL(pix) * Cx) >> 9; ++pix; } if (i > 0) { rx += (R_VAL(pix) * i) >> 9; gx += (G_VAL(pix) * i) >> 9; bx += (B_VAL(pix) * i) >> 9; ax += (A_VAL(pix) * i) >> 9; } r += (rx * j) >> 14; g += (gx * j) >> 14; b += (bx * j) >> 14; a += (ax * j) >> 14; } R_VAL(dptr) = r >> 5; G_VAL(dptr) = g >> 5; B_VAL(dptr) = b >> 5; A_VAL(dptr) = a >> 5; ++dptr; } } } } } void DImgScale::dimgScaleAARGB(DImgScaleInfo* const isi, uint* const dest, int dxx, int dyy, int dw, int dh, int dow, int sow) { dimgScaleAARGB(isi, dest, dxx, dyy, dw, dh, dow, sow, 0, 0, dw, dh); } /** scale by area sampling - IGNORE the ALPHA byte */ void DImgScale::dimgScaleAARGB(DImgScaleInfo* const isi, uint* const dest, int dxx, int dyy, int dw, int dh, int dow, int sow, int clip_dx, int clip_dy, int clip_dw, int clip_dh) { Q_UNUSED(dw); Q_UNUSED(dh); uint* sptr = nullptr; uint* dptr = nullptr; int x, y; uint** ypoints = isi->ypoints; int* xpoints = isi->xpoints; int* xapoints = isi->xapoints; int* yapoints = isi->yapoints; const int x_begin = dxx + clip_dx; // no clip set = dxx const int x_end = x_begin + clip_dw; // no clip set = dxx + dw const int y_begin = clip_dy; // no clip set = 0 const int y_end = clip_dy + clip_dh; // no clip set = dh - /* scaling up both ways */ + // scaling up both ways + if (isi->xup_yup == 3) { - /* go through every scanline in the output buffer */ - for (y = y_begin; y < y_end; ++y) + // go through every scanline in the output buffer + + for (y = y_begin ; y < y_end ; ++y) { - /* calculate the source line we'll scan from */ + // calculate the source line we'll scan from + dptr = dest + (y - y_begin) * dow; sptr = ypoints[dyy + y]; if (YAP > 0) { - for (x = x_begin; x < x_end; ++x) + for (x = x_begin ; x < x_end ; ++x) { int r = 0, g = 0, b = 0; uint* pix = nullptr; if (XAP > 0) { int rr = 0, gg = 0, bb = 0; pix = ypoints[dyy + y] + xpoints[x]; r = R_VAL(pix) * INV_XAP; g = G_VAL(pix) * INV_XAP; b = B_VAL(pix) * INV_XAP; ++pix; r += R_VAL(pix) * XAP; g += G_VAL(pix) * XAP; b += B_VAL(pix) * XAP; pix += sow; rr = R_VAL(pix) * XAP; gg = G_VAL(pix) * XAP; bb = B_VAL(pix) * XAP; pix--; rr += R_VAL(pix) * INV_XAP; gg += G_VAL(pix) * INV_XAP; bb += B_VAL(pix) * INV_XAP; r = ((rr * YAP) + (r * INV_YAP)) >> 16; g = ((gg * YAP) + (g * INV_YAP)) >> 16; b = ((bb * YAP) + (b * INV_YAP)) >> 16; R_VAL(dptr) = r; G_VAL(dptr) = g; B_VAL(dptr) = b; A_VAL(dptr) = 0xFF; ++dptr; } else { pix = ypoints[dyy + y] + xpoints[x]; r = R_VAL(pix) * INV_YAP; g = G_VAL(pix) * INV_YAP; b = B_VAL(pix) * INV_YAP; pix += sow; r += R_VAL(pix) * YAP; g += G_VAL(pix) * YAP; b += B_VAL(pix) * YAP; - r >>= 8; - g >>= 8; - b >>= 8; + r >>= 8; + g >>= 8; + b >>= 8; R_VAL(dptr) = r; G_VAL(dptr) = g; B_VAL(dptr) = b; A_VAL(dptr) = 0xFF; ++dptr; } } } else { - for (x = x_begin; x < x_end; ++x) + for (x = x_begin ; x < x_end ; ++x) { uint* pix = nullptr; if (XAP > 0) { int r = 0, g = 0, b = 0; pix = ypoints[dyy + y] + xpoints[x]; r = R_VAL(pix) * INV_XAP; g = G_VAL(pix) * INV_XAP; b = B_VAL(pix) * INV_XAP; ++pix; - r += R_VAL(pix) * XAP; - g += G_VAL(pix) * XAP; - b += B_VAL(pix) * XAP; + r += R_VAL(pix) * XAP; + g += G_VAL(pix) * XAP; + b += B_VAL(pix) * XAP; r >>= 8; g >>= 8; b >>= 8; R_VAL(dptr) = r; G_VAL(dptr) = g; B_VAL(dptr) = b; A_VAL(dptr) = 0xFF; ++dptr; } else { *dptr++ = sptr[xpoints[x] ]; } } } } } - /* if we're scaling down vertically */ + // if we're scaling down vertically else if (isi->xup_yup == 1) { - /*\ 'Correct' version, with math units prepared for MMXification \*/ + // 'Correct' version, with math units prepared for MMXification + int Cy, j; uint* pix = nullptr; int r, g, b, rr, gg, bb; int yap; - /* go through every scanline in the output buffer */ - for (y = y_begin; y < y_end; ++y) + // go through every scanline in the output buffer + + for (y = y_begin ; y < y_end ; ++y) { Cy = YAP >> 16; yap = YAP & 0xffff; dptr = dest + (y - y_begin) * dow; - for (x = x_begin; x < x_end; ++x) + for (x = x_begin ; x < x_end ; ++x) { pix = ypoints[dyy + y] + xpoints[x]; r = (R_VAL(pix) * yap) >> 10; g = (G_VAL(pix) * yap) >> 10; b = (B_VAL(pix) * yap) >> 10; pix += sow; - for (j = (1 << 14) - yap; j > Cy; j -= Cy) + for (j = (1 << 14) - yap ; j > Cy ; j -= Cy) { r += (R_VAL(pix) * Cy) >> 10; g += (G_VAL(pix) * Cy) >> 10; b += (B_VAL(pix) * Cy) >> 10; pix += sow; } if (j > 0) { r += (R_VAL(pix) * j) >> 10; g += (G_VAL(pix) * j) >> 10; b += (B_VAL(pix) * j) >> 10; } if (XAP > 0) { pix = ypoints[dyy + y] + xpoints[x] + 1; rr = (R_VAL(pix) * yap) >> 10; gg = (G_VAL(pix) * yap) >> 10; bb = (B_VAL(pix) * yap) >> 10; pix += sow; - for (j = (1 << 14) - yap; j > Cy; j -= Cy) + for (j = (1 << 14) - yap ; j > Cy ; j -= Cy) { rr += (R_VAL(pix) * Cy) >> 10; gg += (G_VAL(pix) * Cy) >> 10; bb += (B_VAL(pix) * Cy) >> 10; pix += sow; } if (j > 0) { rr += (R_VAL(pix) * j) >> 10; gg += (G_VAL(pix) * j) >> 10; bb += (B_VAL(pix) * j) >> 10; } r = r * INV_XAP; g = g * INV_XAP; b = b * INV_XAP; r = (r + ((rr * XAP))) >> 12; g = (g + ((gg * XAP))) >> 12; b = (b + ((bb * XAP))) >> 12; } else { r >>= 4; g >>= 4; b >>= 4; } R_VAL(dptr) = r; G_VAL(dptr) = g; B_VAL(dptr) = b; A_VAL(dptr) = 0xFF; ++dptr; } } } - /* if we're scaling down horizontally */ + // if we're scaling down horizontally else if (isi->xup_yup == 2) { - /*\ 'Correct' version, with math units prepared for MMXification \*/ + // 'Correct' version, with math units prepared for MMXification + int Cx, j; uint* pix = nullptr; int r, g, b, rr, gg, bb; int xap; - /* go through every scanline in the output buffer */ - for (y = y_begin; y < y_end; ++y) + // go through every scanline in the output buffer + + for (y = y_begin ; y < y_end ; ++y) { dptr = dest + (y - y_begin) * dow; - for (x = x_begin; x < x_end; ++x) + for (x = x_begin ; x < x_end ; ++x) { Cx = XAP >> 16; xap = XAP & 0xffff; pix = ypoints[dyy + y] + xpoints[x]; r = (R_VAL(pix) * xap) >> 10; g = (G_VAL(pix) * xap) >> 10; b = (B_VAL(pix) * xap) >> 10; ++pix; - for (j = (1 << 14) - xap; j > Cx; j -= Cx) + for (j = (1 << 14) - xap ; j > Cx ; j -= Cx) { r += (R_VAL(pix) * Cx) >> 10; g += (G_VAL(pix) * Cx) >> 10; b += (B_VAL(pix) * Cx) >> 10; ++pix; } if (j > 0) { r += (R_VAL(pix) * j) >> 10; g += (G_VAL(pix) * j) >> 10; b += (B_VAL(pix) * j) >> 10; } if (YAP > 0) { pix = ypoints[dyy + y] + xpoints[x] + sow; rr = (R_VAL(pix) * xap) >> 10; gg = (G_VAL(pix) * xap) >> 10; bb = (B_VAL(pix) * xap) >> 10; ++pix; - for (j = (1 << 14) - xap; j > Cx; j -= Cx) + for (j = (1 << 14) - xap ; j > Cx ; j -= Cx) { rr += (R_VAL(pix) * Cx) >> 10; gg += (G_VAL(pix) * Cx) >> 10; bb += (B_VAL(pix) * Cx) >> 10; ++pix; } if (j > 0) { rr += (R_VAL(pix) * j) >> 10; gg += (G_VAL(pix) * j) >> 10; bb += (B_VAL(pix) * j) >> 10; } r = r * INV_YAP; g = g * INV_YAP; b = b * INV_YAP; r = (r + ((rr * YAP))) >> 12; g = (g + ((gg * YAP))) >> 12; b = (b + ((bb * YAP))) >> 12; } else { r >>= 4; g >>= 4; b >>= 4; } R_VAL(dptr) = r; G_VAL(dptr) = g; B_VAL(dptr) = b; A_VAL(dptr) = 0xFF; ++dptr; } } } - /* fully optimized (i think) - only change of algorithm can help */ - /* if we're scaling down horizontally & vertically */ + /** + * fully optimized (i think) - only change of algorithm can help + * if we're scaling down horizontally & vertically + */ else { - /*\ 'Correct' version, with math units prepared for MMXification \*/ + // 'Correct' version, with math units prepared for MMXification + int Cx, Cy, i, j; uint* pix = nullptr; int r, g, b, rx, gx, bx; int xap, yap; - for (y = y_begin; y < y_end; ++y) + for (y = y_begin ; y < y_end ; ++y) { Cy = YAP >> 16; yap = YAP & 0xffff; dptr = dest + (y - y_begin) * dow; - for (x = x_begin; x < x_end; ++x) + for (x = x_begin ; x < x_end ; ++x) { Cx = XAP >> 16; xap = XAP & 0xffff; if (ypoints && xpoints) { sptr = ypoints[dyy + y] + xpoints[x]; pix = sptr; sptr += sow; rx = (R_VAL(pix) * xap) >> 9; gx = (G_VAL(pix) * xap) >> 9; bx = (B_VAL(pix) * xap) >> 9; ++pix; - for (i = (1 << 14) - xap; i > Cx; i -= Cx) + for (i = (1 << 14) - xap ; i > Cx ; i -= Cx) { rx += (R_VAL(pix) * Cx) >> 9; gx += (G_VAL(pix) * Cx) >> 9; bx += (B_VAL(pix) * Cx) >> 9; ++pix; } if (i > 0) { rx += (R_VAL(pix) * i) >> 9; gx += (G_VAL(pix) * i) >> 9; bx += (B_VAL(pix) * i) >> 9; } r = (rx * yap) >> 14; g = (gx * yap) >> 14; b = (bx * yap) >> 14; - for (j = (1 << 14) - yap; j > Cy; j -= Cy) + for (j = (1 << 14) - yap ; j > Cy ; j -= Cy) { pix = sptr; sptr += sow; rx = (R_VAL(pix) * xap) >> 9; gx = (G_VAL(pix) * xap) >> 9; bx = (B_VAL(pix) * xap) >> 9; ++pix; - for (i = (1 << 14) - xap; i > Cx; i -= Cx) + for (i = (1 << 14) - xap ; i > Cx ; i -= Cx) { rx += (R_VAL(pix) * Cx) >> 9; gx += (G_VAL(pix) * Cx) >> 9; bx += (B_VAL(pix) * Cx) >> 9; ++pix; } if (i > 0) { rx += (R_VAL(pix) * i) >> 9; gx += (G_VAL(pix) * i) >> 9; bx += (B_VAL(pix) * i) >> 9; } r += (rx * Cy) >> 14; g += (gx * Cy) >> 14; b += (bx * Cy) >> 14; } if (j > 0) { pix = sptr; sptr += sow; (void)sptr; // disable clang warning. rx = (R_VAL(pix) * xap) >> 9; gx = (G_VAL(pix) * xap) >> 9; bx = (B_VAL(pix) * xap) >> 9; ++pix; - for (i = (1 << 14) - xap; i > Cx; i -= Cx) + for (i = (1 << 14) - xap ; i > Cx ; i -= Cx) { rx += (R_VAL(pix) * Cx) >> 9; gx += (G_VAL(pix) * Cx) >> 9; bx += (B_VAL(pix) * Cx) >> 9; ++pix; } if (i > 0) { rx += (R_VAL(pix) * i) >> 9; gx += (G_VAL(pix) * i) >> 9; bx += (B_VAL(pix) * i) >> 9; } r += (rx * j) >> 14; g += (gx * j) >> 14; b += (bx * j) >> 14; } R_VAL(dptr) = r >> 5; G_VAL(dptr) = g >> 5; B_VAL(dptr) = b >> 5; A_VAL(dptr) = 0xFF; ++dptr; } } } } } #define A_VAL16(p) ((ushort*)(p))[3] #define R_VAL16(p) ((ushort*)(p))[2] #define G_VAL16(p) ((ushort*)(p))[1] #define B_VAL16(p) ((ushort*)(p))[0] void DImgScale::dimgScaleAARGB16(DImgScaleInfo* const isi, ullong* const dest, int dxx, int dyy, int dw, int dh, int dow, int sow) { dimgScaleAARGB16(isi, dest, dxx, dyy, dw, dh, dow, sow, 0, 0, dw, dh); } /** scale by area sampling - IGNORE the ALPHA byte*/ void DImgScale::dimgScaleAARGB16(DImgScaleInfo* const isi, ullong* const dest, int dxx, int dyy, int dw, int dh, int dow, int sow, int clip_dx, int clip_dy, int clip_dw, int clip_dh) { Q_UNUSED(dw); Q_UNUSED(dh); ullong* sptr = nullptr; ullong* dptr = nullptr; int x, y; ullong** ypoints = isi->ypoints16; int* xpoints = isi->xpoints; int* xapoints = isi->xapoints; int* yapoints = isi->yapoints; const int x_begin = dxx + clip_dx; // no clip set = dxx const int x_end = x_begin + clip_dw; // no clip set = dxx + dw const int y_begin = clip_dy; // no clip set = 0 const int y_end = clip_dy + clip_dh; // no clip set = dh // scaling up both ways + if (isi->xup_yup == 3) { // go through every scanline in the output buffer - for (y = y_begin; y < y_end; ++y) + + for (y = y_begin ; y < y_end ; ++y) { // calculate the source line we'll scan from + dptr = dest + (y - y_begin) * dow; sptr = ypoints[dyy + y]; if (YAP > 0) { - for (x = x_begin; x < x_end; ++x) + for (x = x_begin ; x < x_end ; ++x) { llong r = 0, g = 0, b = 0; ullong* pix = nullptr; if (XAP > 0) { llong rr = 0, gg = 0, bb = 0; pix = ypoints[dyy + y] + xpoints[x]; r = R_VAL16(pix) * INV_XAP; g = G_VAL16(pix) * INV_XAP; b = B_VAL16(pix) * INV_XAP; ++pix; r += R_VAL16(pix) * XAP; g += G_VAL16(pix) * XAP; b += B_VAL16(pix) * XAP; pix += sow; rr = R_VAL16(pix) * XAP; gg = G_VAL16(pix) * XAP; bb = B_VAL16(pix) * XAP; pix--; rr += R_VAL16(pix) * INV_XAP; gg += G_VAL16(pix) * INV_XAP; bb += B_VAL16(pix) * INV_XAP; r = ((rr * YAP) + (r * INV_YAP)) >> 16; g = ((gg * YAP) + (g * INV_YAP)) >> 16; b = ((bb * YAP) + (b * INV_YAP)) >> 16; R_VAL16(dptr) = r; G_VAL16(dptr) = g; B_VAL16(dptr) = b; A_VAL16(dptr) = 0xFFFF; ++dptr; } else { pix = ypoints[dyy + y] + xpoints[x]; r = R_VAL16(pix) * INV_YAP; g = G_VAL16(pix) * INV_YAP; b = B_VAL16(pix) * INV_YAP; pix += sow; r += R_VAL16(pix) * YAP; g += G_VAL16(pix) * YAP; b += B_VAL16(pix) * YAP; r >>= 8; g >>= 8; b >>= 8; R_VAL16(dptr) = r; G_VAL16(dptr) = g; B_VAL16(dptr) = b; A_VAL16(dptr) = 0xFFFF; ++dptr; } } } else { - for (x = x_begin; x < x_end; ++x) + for (x = x_begin ; x < x_end ; ++x) { ullong* pix = nullptr; if (XAP > 0) { llong r = 0, g = 0, b = 0; pix = ypoints[dyy + y] + xpoints[x]; r = R_VAL16(pix) * INV_XAP; g = G_VAL16(pix) * INV_XAP; b = B_VAL16(pix) * INV_XAP; ++pix; r += R_VAL16(pix) * XAP; g += G_VAL16(pix) * XAP; b += B_VAL16(pix) * XAP; r >>= 8; g >>= 8; b >>= 8; R_VAL16(dptr) = r; G_VAL16(dptr) = g; B_VAL16(dptr) = b; A_VAL16(dptr) = 0xFFFF; ++dptr; } else { *dptr++ = sptr[xpoints[x] ]; } } } } } // if we're scaling down vertically else if (isi->xup_yup == 1) { // 'Correct' version, with math units prepared for MMXification + int Cy, j; ullong* pix = nullptr; llong r, g, b, rr, gg, bb; int yap; // go through every scanline in the output buffer - for (y = y_begin; y < y_end; ++y) + + for (y = y_begin ; y < y_end ; ++y) { Cy = YAP >> 16; yap = YAP & 0xffff; dptr = dest + (y - y_begin) * dow; - for (x = x_begin; x < x_end; ++x) + for (x = x_begin ; x < x_end ; ++x) { pix = ypoints[dyy + y] + xpoints[x]; r = (R_VAL16(pix) * yap) >> 10; g = (G_VAL16(pix) * yap) >> 10; b = (B_VAL16(pix) * yap) >> 10; pix += sow; - for (j = (1 << 14) - yap; j > Cy; j -= Cy) + for (j = (1 << 14) - yap ; j > Cy ; j -= Cy) { r += (R_VAL16(pix) * Cy) >> 10; g += (G_VAL16(pix) * Cy) >> 10; b += (B_VAL16(pix) * Cy) >> 10; pix += sow; } if (j > 0) { r += (R_VAL16(pix) * j) >> 10; g += (G_VAL16(pix) * j) >> 10; b += (B_VAL16(pix) * j) >> 10; } if (XAP > 0) { pix = ypoints[dyy + y] + xpoints[x] + 1; rr = (R_VAL16(pix) * yap) >> 10; gg = (G_VAL16(pix) * yap) >> 10; bb = (B_VAL16(pix) * yap) >> 10; pix += sow; - for (j = (1 << 14) - yap; j > Cy; j -= Cy) + for (j = (1 << 14) - yap ; j > Cy ; j -= Cy) { rr += (R_VAL16(pix) * Cy) >> 10; gg += (G_VAL16(pix) * Cy) >> 10; bb += (B_VAL16(pix) * Cy) >> 10; pix += sow; } if (j > 0) { rr += (R_VAL16(pix) * j) >> 10; gg += (G_VAL16(pix) * j) >> 10; bb += (B_VAL16(pix) * j) >> 10; } r = r * INV_XAP; g = g * INV_XAP; b = b * INV_XAP; r = (r + ((rr * XAP))) >> 12; g = (g + ((gg * XAP))) >> 12; b = (b + ((bb * XAP))) >> 12; } else { r >>= 4; g >>= 4; b >>= 4; } R_VAL16(dptr) = r; G_VAL16(dptr) = g; B_VAL16(dptr) = b; A_VAL16(dptr) = 0xFFFF; ++dptr; } } } // if we're scaling down horizontally else if (isi->xup_yup == 2) { // 'Correct' version, with math units prepared for MMXification + int Cx, j; ullong* pix = nullptr; llong r, g, b, rr, gg, bb; int xap; // go through every scanline in the output buffer - for (y = y_begin; y < y_end; ++y) + + for (y = y_begin ; y < y_end ; ++y) { dptr = dest + (y - y_begin) * dow; - for (x = x_begin; x < x_end; ++x) + for (x = x_begin ; x < x_end ; ++x) { Cx = XAP >> 16; xap = XAP & 0xffff; pix = ypoints[dyy + y] + xpoints[x]; r = (R_VAL16(pix) * xap) >> 10; g = (G_VAL16(pix) * xap) >> 10; b = (B_VAL16(pix) * xap) >> 10; ++pix; - for (j = (1 << 14) - xap; j > Cx; j -= Cx) + for (j = (1 << 14) - xap ; j > Cx ; j -= Cx) { r += (R_VAL16(pix) * Cx) >> 10; g += (G_VAL16(pix) * Cx) >> 10; b += (B_VAL16(pix) * Cx) >> 10; ++pix; } if (j > 0) { r += (R_VAL16(pix) * j) >> 10; g += (G_VAL16(pix) * j) >> 10; b += (B_VAL16(pix) * j) >> 10; } if (YAP > 0) { pix = ypoints[dyy + y] + xpoints[x] + sow; rr = (R_VAL16(pix) * xap) >> 10; gg = (G_VAL16(pix) * xap) >> 10; bb = (B_VAL16(pix) * xap) >> 10; ++pix; - for (j = (1 << 14) - xap; j > Cx; j -= Cx) + for (j = (1 << 14) - xap ; j > Cx ; j -= Cx) { rr += (R_VAL16(pix) * Cx) >> 10; gg += (G_VAL16(pix) * Cx) >> 10; bb += (B_VAL16(pix) * Cx) >> 10; ++pix; } if (j > 0) { rr += (R_VAL16(pix) * j) >> 10; gg += (G_VAL16(pix) * j) >> 10; bb += (B_VAL16(pix) * j) >> 10; } r = r * INV_YAP; g = g * INV_YAP; b = b * INV_YAP; r = (r + ((rr * YAP))) >> 12; g = (g + ((gg * YAP))) >> 12; b = (b + ((bb * YAP))) >> 12; } else { r >>= 4; g >>= 4; b >>= 4; } R_VAL16(dptr) = r; G_VAL16(dptr) = g; B_VAL16(dptr) = b; A_VAL16(dptr) = 0xFFFF; ++dptr; } } } // fully optimized (i think) - only change of algorithm can help // if we're scaling down horizontally & vertically else { // 'Correct' version, with math units prepared for MMXification + int Cx, Cy, i, j; ullong* pix = nullptr; llong r, g, b, rx, gx, bx; int xap, yap; - for (y = y_begin; y < y_end; ++y) + for (y = y_begin ; y < y_end ; ++y) { Cy = YAP >> 16; yap = YAP & 0xffff; dptr = dest + (y - y_begin) * dow; - for (x = x_begin; x < x_end; ++x) + for (x = x_begin ; x < x_end ; ++x) { Cx = XAP >> 16; xap = XAP & 0xffff; - + if (ypoints && xpoints) { sptr = ypoints[dyy + y] + xpoints[x]; pix = sptr; sptr += sow; rx = (R_VAL16(pix) * xap) >> 9; gx = (G_VAL16(pix) * xap) >> 9; bx = (B_VAL16(pix) * xap) >> 9; ++pix; - for (i = (1 << 14) - xap; i > Cx; i -= Cx) + for (i = (1 << 14) - xap ; i > Cx ; i -= Cx) { rx += (R_VAL16(pix) * Cx) >> 9; gx += (G_VAL16(pix) * Cx) >> 9; bx += (B_VAL16(pix) * Cx) >> 9; ++pix; } if (i > 0) { rx += (R_VAL16(pix) * i) >> 9; gx += (G_VAL16(pix) * i) >> 9; bx += (B_VAL16(pix) * i) >> 9; } r = (rx * yap) >> 14; g = (gx * yap) >> 14; b = (bx * yap) >> 14; - for (j = (1 << 14) - yap; j > Cy; j -= Cy) + for (j = (1 << 14) - yap ; j > Cy ; j -= Cy) { pix = sptr; sptr += sow; rx = (R_VAL16(pix) * xap) >> 9; gx = (G_VAL16(pix) * xap) >> 9; bx = (B_VAL16(pix) * xap) >> 9; ++pix; - for (i = (1 << 14) - xap; i > Cx; i -= Cx) + for (i = (1 << 14) - xap ; i > Cx ; i -= Cx) { rx += (R_VAL16(pix) * Cx) >> 9; gx += (G_VAL16(pix) * Cx) >> 9; bx += (B_VAL16(pix) * Cx) >> 9; ++pix; } if (i > 0) { rx += (R_VAL16(pix) * i) >> 9; gx += (G_VAL16(pix) * i) >> 9; bx += (B_VAL16(pix) * i) >> 9; } r += (rx * Cy) >> 14; g += (gx * Cy) >> 14; b += (bx * Cy) >> 14; } if (j > 0) { pix = sptr; sptr += sow; (void)sptr; // disable clang warning. rx = (R_VAL16(pix) * xap) >> 9; gx = (G_VAL16(pix) * xap) >> 9; bx = (B_VAL16(pix) * xap) >> 9; ++pix; - for (i = (1 << 14) - xap; i > Cx; i -= Cx) + for (i = (1 << 14) - xap ; i > Cx ; i -= Cx) { rx += (R_VAL16(pix) * Cx) >> 9; gx += (G_VAL16(pix) * Cx) >> 9; bx += (B_VAL16(pix) * Cx) >> 9; ++pix; } if (i > 0) { rx += (R_VAL16(pix) * i) >> 9; gx += (G_VAL16(pix) * i) >> 9; bx += (B_VAL16(pix) * i) >> 9; } r += (rx * j) >> 14; g += (gx * j) >> 14; b += (bx * j) >> 14; } R_VAL16(dptr) = r >> 5; G_VAL16(dptr) = g >> 5; B_VAL16(dptr) = b >> 5; A_VAL16(dptr) = 0xFFFF; ++dptr; } } } } } void DImgScale::dimgScaleAARGBA16(DImgScaleInfo* const isi, ullong* const dest, int dxx, int dyy, int dw, int dh, int dow, int sow ) { dimgScaleAARGBA16(isi, dest, dxx, dyy, dw, dh, dow, sow, 0, 0, dw, dh); } -/* scale by area sampling */ +/** + * scale by area sampling + */ void DImgScale::dimgScaleAARGBA16(DImgScaleInfo* const isi, ullong* const dest, int dxx, int dyy, int dw, int dh, int dow, int sow, int clip_dx, int clip_dy, int clip_dw, int clip_dh) { Q_UNUSED(dw); Q_UNUSED(dh); ullong* sptr = nullptr; ullong* dptr = nullptr; int x, y; ullong** ypoints = isi->ypoints16; int* xpoints = isi->xpoints; int* xapoints = isi->xapoints; int* yapoints = isi->yapoints; const int x_begin = dxx + clip_dx; // no clip set = dxx const int x_end = x_begin + clip_dw; // no clip set = dxx + dw const int y_begin = clip_dy; // no clip set = 0 const int y_end = clip_dy + clip_dh; // no clip set = dh - /* scaling up both ways */ + // scaling up both ways + if (isi->xup_yup == 3) { - /* go through every scanline in the output buffer */ - for (y = y_begin; y < y_end; ++y) + // go through every scanline in the output buffer + + for (y = y_begin ; y < y_end ; ++y) { /* calculate the source line we'll scan from */ dptr = dest + (y - y_begin) * dow; sptr = ypoints[dyy + y]; if (YAP > 0) { - for (x = x_begin; x < x_end; ++x) + for (x = x_begin ; x < x_end ; ++x) { llong r, g, b, a; llong rr, gg, bb, aa; ullong* pix = nullptr; if (XAP > 0) { pix = ypoints[dyy + y] + xpoints[x]; r = R_VAL16(pix) * INV_XAP; g = G_VAL16(pix) * INV_XAP; b = B_VAL16(pix) * INV_XAP; a = A_VAL16(pix) * INV_XAP; ++pix; r += R_VAL16(pix) * XAP; g += G_VAL16(pix) * XAP; b += B_VAL16(pix) * XAP; a += A_VAL16(pix) * XAP; pix += sow; rr = R_VAL16(pix) * XAP; gg = G_VAL16(pix) * XAP; bb = B_VAL16(pix) * XAP; aa = A_VAL16(pix) * XAP; --pix; rr += R_VAL16(pix) * INV_XAP; gg += G_VAL16(pix) * INV_XAP; bb += B_VAL16(pix) * INV_XAP; aa += A_VAL16(pix) * INV_XAP; r = ((rr * YAP) + (r * INV_YAP)) >> 16; g = ((gg * YAP) + (g * INV_YAP)) >> 16; b = ((bb * YAP) + (b * INV_YAP)) >> 16; a = ((aa * YAP) + (a * INV_YAP)) >> 16; R_VAL16(dptr) = r; G_VAL16(dptr) = g; B_VAL16(dptr) = b; A_VAL16(dptr) = a; ++dptr; } else { pix = ypoints[dyy + y] + xpoints[x]; r = R_VAL16(pix) * INV_YAP; g = G_VAL16(pix) * INV_YAP; b = B_VAL16(pix) * INV_YAP; a = A_VAL16(pix) * INV_YAP; pix += sow; r += R_VAL16(pix) * YAP; g += G_VAL16(pix) * YAP; b += B_VAL16(pix) * YAP; a += A_VAL16(pix) * YAP; r >>= 8; g >>= 8; b >>= 8; a >>= 8; R_VAL16(dptr) = r; G_VAL16(dptr) = g; B_VAL16(dptr) = b; A_VAL16(dptr) = a; ++dptr; } } } else { - for (x = x_begin; x < x_end; ++x) + for (x = x_begin ; x < x_end ; ++x) { llong r, g, b, a; ullong* pix = nullptr; if (XAP > 0) { pix = ypoints[dyy + y] + xpoints[x]; r = R_VAL16(pix) * INV_XAP; g = G_VAL16(pix) * INV_XAP; b = B_VAL16(pix) * INV_XAP; a = A_VAL16(pix) * INV_XAP; ++pix; r += R_VAL16(pix) * XAP; g += G_VAL16(pix) * XAP; b += B_VAL16(pix) * XAP; a += A_VAL16(pix) * XAP; r >>= 8; g >>= 8; b >>= 8; a >>= 8; R_VAL16(dptr) = r; G_VAL16(dptr) = g; B_VAL16(dptr) = b; A_VAL16(dptr) = a; ++dptr; } else { *dptr++ = sptr[xpoints[x] ]; } } } } } - /* if we're scaling down vertically */ + // if we're scaling down vertically else if (isi->xup_yup == 1) { - /*\ 'Correct' version, with math units prepared for MMXification \*/ + // 'Correct' version, with math units prepared for MMXification + int Cy, j; ullong* pix = nullptr; llong r, g, b, a, rr, gg, bb, aa; int yap; - /* go through every scanline in the output buffer */ - for (y = y_begin; y < y_end; ++y) + // go through every scanline in the output buffer + + for (y = y_begin ; y < y_end ; ++y) { Cy = YAP >> 16; yap = YAP & 0xffff; dptr = dest + (y - y_begin) * dow; - for (x = x_begin; x < x_end; ++x) + for (x = x_begin ; x < x_end ; ++x) { pix = ypoints[dyy + y] + xpoints[x]; r = (R_VAL16(pix) * yap) >> 10; g = (G_VAL16(pix) * yap) >> 10; b = (B_VAL16(pix) * yap) >> 10; a = (A_VAL16(pix) * yap) >> 10; - for (j = (1 << 14) - yap; j > Cy; j -= Cy) + for (j = (1 << 14) - yap ; j > Cy ; j -= Cy) { pix += sow; r += (R_VAL16(pix) * Cy) >> 10; g += (G_VAL16(pix) * Cy) >> 10; b += (B_VAL16(pix) * Cy) >> 10; a += (A_VAL16(pix) * Cy) >> 10; } if (j > 0) { pix += sow; r += (R_VAL16(pix) * j) >> 10; g += (G_VAL16(pix) * j) >> 10; b += (B_VAL16(pix) * j) >> 10; a += (A_VAL16(pix) * j) >> 10; } if (XAP > 0) { pix = ypoints[dyy + y] + xpoints[x] + 1; rr = (R_VAL16(pix) * yap) >> 10; gg = (G_VAL16(pix) * yap) >> 10; bb = (B_VAL16(pix) * yap) >> 10; aa = (A_VAL16(pix) * yap) >> 10; - for (j = (1 << 14) - yap; j > Cy; j -= Cy) + for (j = (1 << 14) - yap ; j > Cy ; j -= Cy) { pix += sow; rr += (R_VAL16(pix) * Cy) >> 10; gg += (G_VAL16(pix) * Cy) >> 10; bb += (B_VAL16(pix) * Cy) >> 10; aa += (A_VAL16(pix) * Cy) >> 10; } if (j > 0) { pix += sow; rr += (R_VAL16(pix) * j) >> 10; gg += (G_VAL16(pix) * j) >> 10; bb += (B_VAL16(pix) * j) >> 10; aa += (A_VAL16(pix) * j) >> 10; } r = r * INV_XAP; g = g * INV_XAP; b = b * INV_XAP; a = a * INV_XAP; r = (r + ((rr * XAP))) >> 12; g = (g + ((gg * XAP))) >> 12; b = (b + ((bb * XAP))) >> 12; a = (a + ((aa * XAP))) >> 12; } else { r >>= 4; g >>= 4; b >>= 4; a >>= 4; } R_VAL16(dptr) = r; G_VAL16(dptr) = g; B_VAL16(dptr) = b; A_VAL16(dptr) = a; ++dptr; } } } - /* if we're scaling down horizontally */ + // if we're scaling down horizontally else if (isi->xup_yup == 2) { - /*\ 'Correct' version, with math units prepared for MMXification \*/ + // 'Correct' version, with math units prepared for MMXification int Cx, j; ullong* pix = nullptr; llong r, g, b, a, rr, gg, bb, aa; int xap; - /* go through every scanline in the output buffer */ - for (y = y_begin; y < y_end; ++y) + // go through every scanline in the output buffer + + for (y = y_begin ; y < y_end ; ++y) { dptr = dest + (y - y_begin) * dow; - for (x = x_begin; x < x_end; ++x) + for (x = x_begin ; x < x_end ; ++x) { Cx = XAP >> 16; xap = XAP & 0xffff; pix = ypoints[dyy + y] + xpoints[x]; r = (R_VAL16(pix) * xap) >> 10; g = (G_VAL16(pix) * xap) >> 10; b = (B_VAL16(pix) * xap) >> 10; a = (A_VAL16(pix) * xap) >> 10; - for (j = (1 << 14) - xap; j > Cx; j -= Cx) + for (j = (1 << 14) - xap ; j > Cx ; j -= Cx) { ++pix; r += (R_VAL16(pix) * Cx) >> 10; g += (G_VAL16(pix) * Cx) >> 10; b += (B_VAL16(pix) * Cx) >> 10; a += (A_VAL16(pix) * Cx) >> 10; } if (j > 0) { ++pix; r += (R_VAL16(pix) * j) >> 10; g += (G_VAL16(pix) * j) >> 10; b += (B_VAL16(pix) * j) >> 10; a += (A_VAL16(pix) * j) >> 10; } if (YAP > 0) { pix = ypoints[dyy + y] + xpoints[x] + sow; rr = (R_VAL16(pix) * xap) >> 10; gg = (G_VAL16(pix) * xap) >> 10; bb = (B_VAL16(pix) * xap) >> 10; aa = (A_VAL16(pix) * xap) >> 10; - for (j = (1 << 14) - xap; j > Cx; j -= Cx) + for (j = (1 << 14) - xap ; j > Cx ; j -= Cx) { ++pix; rr += (R_VAL16(pix) * Cx) >> 10; gg += (G_VAL16(pix) * Cx) >> 10; bb += (B_VAL16(pix) * Cx) >> 10; aa += (A_VAL16(pix) * Cx) >> 10; } if (j > 0) { ++pix; rr += (R_VAL16(pix) * j) >> 10; gg += (G_VAL16(pix) * j) >> 10; bb += (B_VAL16(pix) * j) >> 10; aa += (A_VAL16(pix) * j) >> 10; } r = r * INV_YAP; g = g * INV_YAP; b = b * INV_YAP; a = a * INV_YAP; r = (r + ((rr * YAP))) >> 12; g = (g + ((gg * YAP))) >> 12; b = (b + ((bb * YAP))) >> 12; a = (a + ((aa * YAP))) >> 12; } else { r >>= 4; g >>= 4; b >>= 4; a >>= 4; } R_VAL16(dptr) = r; G_VAL16(dptr) = g; B_VAL16(dptr) = b; A_VAL16(dptr) = a; ++dptr; } } } - /* if we're scaling down horizontally & vertically */ + // if we're scaling down horizontally & vertically else { - /*\ 'Correct' version, with math units prepared for MMXification: - |*| The operation 'b = (b * c) >> 16' translates to pmulhw, - |*| so the operation 'b = (b * c) >> d' would translate to - |*| psllw (16 - d), %mmb; pmulh %mmc, %mmb - \*/ + /** + * 'Correct' version, with math units prepared for MMXification: + * The operation 'b = (b * c) >> 16' translates to pmulhw, + * so the operation 'b = (b * c) >> d' would translate to + * psllw (16 - d), %mmb; pmulh %mmc, %mmb + */ int Cx, Cy, i, j; ullong* pix = nullptr; llong a, r, g, b, ax, rx, gx, bx; int xap, yap; - for (y = y_begin; y < y_end; ++y) + for (y = y_begin ; y < y_end ; ++y) { Cy = YAP >> 16; yap = YAP & 0xffff; dptr = dest + (y - y_begin) * dow; - for (x = x_begin; x < x_end; ++x) + for (x = x_begin ; x < x_end ; ++x) { Cx = XAP >> 16; xap = XAP & 0xffff; if (ypoints && xpoints) { sptr = ypoints[dyy + y] + xpoints[x]; pix = sptr; sptr += sow; rx = (R_VAL16(pix) * xap) >> 9; gx = (G_VAL16(pix) * xap) >> 9; bx = (B_VAL16(pix) * xap) >> 9; ax = (A_VAL16(pix) * xap) >> 9; ++pix; for (i = (1 << 14) - xap; i > Cx; i -= Cx) { rx += (R_VAL16(pix) * Cx) >> 9; gx += (G_VAL16(pix) * Cx) >> 9; bx += (B_VAL16(pix) * Cx) >> 9; ax += (A_VAL16(pix) * Cx) >> 9; ++pix; } if (i > 0) { rx += (R_VAL16(pix) * i) >> 9; gx += (G_VAL16(pix) * i) >> 9; bx += (B_VAL16(pix) * i) >> 9; ax += (A_VAL16(pix) * i) >> 9; } r = (rx * yap) >> 14; g = (gx * yap) >> 14; b = (bx * yap) >> 14; a = (ax * yap) >> 14; - for (j = (1 << 14) - yap; j > Cy; j -= Cy) + for (j = (1 << 14) - yap ; j > Cy ; j -= Cy) { pix = sptr; sptr += sow; rx = (R_VAL16(pix) * xap) >> 9; gx = (G_VAL16(pix) * xap) >> 9; bx = (B_VAL16(pix) * xap) >> 9; ax = (A_VAL16(pix) * xap) >> 9; ++pix; - for (i = (1 << 14) - xap; i > Cx; i -= Cx) + for (i = (1 << 14) - xap ; i > Cx ; i -= Cx) { rx += (R_VAL16(pix) * Cx) >> 9; gx += (G_VAL16(pix) * Cx) >> 9; bx += (B_VAL16(pix) * Cx) >> 9; ax += (A_VAL16(pix) * Cx) >> 9; ++pix; } if (i > 0) { rx += (R_VAL16(pix) * i) >> 9; gx += (G_VAL16(pix) * i) >> 9; bx += (B_VAL16(pix) * i) >> 9; ax += (A_VAL16(pix) * i) >> 9; } r += (rx * Cy) >> 14; g += (gx * Cy) >> 14; b += (bx * Cy) >> 14; a += (ax * Cy) >> 14; } if (j > 0) { pix = sptr; sptr += sow; (void)sptr; // disable clang warning. rx = (R_VAL16(pix) * xap) >> 9; gx = (G_VAL16(pix) * xap) >> 9; bx = (B_VAL16(pix) * xap) >> 9; ax = (A_VAL16(pix) * xap) >> 9; ++pix; - for (i = (1 << 14) - xap; i > Cx; i -= Cx) + for (i = (1 << 14) - xap ; i > Cx ; i -= Cx) { rx += (R_VAL16(pix) * Cx) >> 9; gx += (G_VAL16(pix) * Cx) >> 9; bx += (B_VAL16(pix) * Cx) >> 9; ax += (A_VAL16(pix) * Cx) >> 9; ++pix; } if (i > 0) { rx += (R_VAL16(pix) * i) >> 9; gx += (G_VAL16(pix) * i) >> 9; bx += (B_VAL16(pix) * i) >> 9; ax += (A_VAL16(pix) * i) >> 9; } r += (rx * j) >> 14; g += (gx * j) >> 14; b += (bx * j) >> 14; a += (ax * j) >> 14; } R_VAL16(dptr) = r >> 5; G_VAL16(dptr) = g >> 5; B_VAL16(dptr) = b >> 5; A_VAL16(dptr) = a >> 5; ++dptr; } } } } } } // namespace Digikam diff --git a/core/libs/dimg/dimg_transform.cpp b/core/libs/dimg/dimg_transform.cpp index 919efd3ff5..68a276b607 100644 --- a/core/libs/dimg/dimg_transform.cpp +++ b/core/libs/dimg/dimg_transform.cpp @@ -1,579 +1,594 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2005-06-14 * Description : digiKam 8/16 bits image management API. * Transform operations. * * Copyright (C) 2005-2020 by Gilles Caulier * Copyright (C) 2006-2013 by Marcel Wiesweg * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "dimg_p.h" namespace Digikam { void DImg::crop(const QRect& rect) { crop(rect.x(), rect.y(), rect.width(), rect.height()); } void DImg::crop(int x, int y, int w, int h) { - if (isNull() || w <= 0 || h <= 0) + if (isNull() || (w <= 0) || (h <= 0)) { return; } uint oldw = width(); uint oldh = height(); QScopedArrayPointer old(stripImageData()); // set new image data, bits(), width(), height() change + setImageDimension(w, h); allocateData(); // copy image region (x|y), wxh, from old data to point (0|0) of new data + bitBlt(old.data(), bits(), x, y, w, h, 0, 0, oldw, oldh, width(), height(), sixteenBit(), bytesDepth(), bytesDepth()); } void DImg::resize(int w, int h) { - if (isNull() || w <= 0 || h <= 0) + if (isNull() || (w <= 0) || (h <= 0)) { return; } DImg image = smoothScale(w, h); delete [] m_priv->data; m_priv->data = image.stripImageData(); setImageDimension(w, h); } void DImg::rotate(ANGLE angle) { if (isNull()) { return; } bool switchDims = false; switch (angle) { case (ROT90): { uint w = height(); uint h = width(); if (sixteenBit()) { ullong* newData = DImgLoader::new_failureTolerant(w * h); ullong* from = reinterpret_cast(m_priv->data); ullong* to = nullptr; - for (int y = w - 1; y >= 0; --y) + for (int y = w - 1 ; y >= 0 ; --y) { to = newData + y; - for (uint x = 0; x < h; ++x) + for (uint x = 0 ; x < h ; ++x) { *to = *from++; to += w; } } switchDims = true; delete [] m_priv->data; m_priv->data = (uchar*)newData; } else { uint* newData = DImgLoader::new_failureTolerant(w * h); uint* from = reinterpret_cast(m_priv->data); uint* to = nullptr; - for (int y = w - 1; y >= 0; --y) + for (int y = w - 1 ; y >= 0 ; --y) { to = newData + y; - for (uint x = 0; x < h; ++x) + for (uint x = 0 ; x < h ; ++x) { *to = *from++; to += w; } } switchDims = true; delete [] m_priv->data; m_priv->data = (uchar*)newData; } break; } case (ROT180): { uint w = width(); uint h = height(); int middle_line = -1; if (h % 2) { middle_line = h / 2; } if (sixteenBit()) { ullong* line1 = nullptr; ullong* line2 = nullptr; ullong* data = reinterpret_cast(bits()); ullong tmp; // can be done inplace + uint ymax = (h + 1) / 2; - for (uint y = 0; y < ymax; ++y) + for (uint y = 0 ; y < ymax ; ++y) { line1 = data + y * w; line2 = data + (h - y) * w - 1; - for (uint x = 0; x < w; ++x) + for (uint x = 0 ; x < w ; ++x) { tmp = *line1; *line1 = *line2; *line2 = tmp; ++line1; --line2; - if ((int)y == middle_line && x * 2 >= w) + if (((int)y == middle_line) && ((x * 2) >= w)) { break; } } } } else { uint* line1 = nullptr; uint* line2 = nullptr; uint* data = reinterpret_cast(bits()); uint tmp; // can be done inplace + uint ymax = (h + 1) / 2; - for (uint y = 0; y < ymax; ++y) + for (uint y = 0 ; y < ymax ; ++y) { line1 = data + y * w; line2 = data + (h - y) * w - 1; - for (uint x = 0; x < w; ++x) + for (uint x = 0 ; x < w ; ++x) { tmp = *line1; *line1 = *line2; *line2 = tmp; ++line1; --line2; - if ((int)y == middle_line && x * 2 >= w) + if (((int)y == middle_line) && ((x * 2) >= w)) { break; } } } } break; } case (ROT270): { uint w = height(); uint h = width(); if (sixteenBit()) { ullong* newData = DImgLoader::new_failureTolerant(w * h); ullong* from = reinterpret_cast(m_priv->data); ullong* to = nullptr; - for (uint y = 0; y < w; ++y) + for (uint y = 0 ; y < w ; ++y) { to = newData + y + w * (h - 1); - for (uint x = 0; x < h; ++x) + for (uint x = 0 ; x < h ; ++x) { *to = *from++; to -= w; } } switchDims = true; delete [] m_priv->data; m_priv->data = (uchar*)newData; } else { uint* newData = DImgLoader::new_failureTolerant(w * h); uint* from = reinterpret_cast(m_priv->data); uint* to = nullptr; - for (uint y = 0; y < w; ++y) + for (uint y = 0 ; y < w ; ++y) { to = newData + y + w * (h - 1); - for (uint x = 0; x < h; ++x) + for (uint x = 0 ; x < h ; ++x) { *to = *from++; to -= w; } } switchDims = true; delete [] m_priv->data; m_priv->data = (uchar*)newData; } break; } default: break; } if (switchDims) { QMutexLocker lock(&m_priv->mutex); setImageDimension(height(), width()); QMap::iterator it = m_priv->attributes.find(QLatin1String("originalSize")); if (it != m_priv->attributes.end()) { QSize size = it.value().toSize(); it.value() = QSize(size.height(), size.width()); } } } // 15-11-2005: This method have been tested indeep with valgrind by Gilles. void DImg::flip(FLIP direction) { if (isNull()) { return; } switch (direction) { case (HORIZONTAL): { uint w = width(); uint h = height(); if (sixteenBit()) { unsigned short tmp[4]; unsigned short* beg = nullptr; unsigned short* end = nullptr; unsigned short* data = reinterpret_cast(bits()); // can be done inplace uint wHalf = (w / 2); for (uint y = 0 ; y < h ; ++y) { beg = data + y * w * 4; end = beg + (w - 1) * 4; for (uint x = 0 ; x < wHalf ; ++x) { - memcpy(&tmp, beg, 8); - memcpy(beg, end, 8); - memcpy(end, &tmp, 8); + memcpy(&tmp, beg, 8); + memcpy(beg, end, 8); + memcpy(end, &tmp, 8); beg += 4; end -= 4; } } } else { uchar tmp[4]; uchar* beg = nullptr; uchar* end = nullptr; uchar* data = bits(); // can be done inplace + uint wHalf = (w / 2); for (uint y = 0 ; y < h ; ++y) { beg = data + y * w * 4; end = beg + (w - 1) * 4; for (uint x = 0 ; x < wHalf ; ++x) { - memcpy(&tmp, beg, 4); - memcpy(beg, end, 4); - memcpy(end, &tmp, 4); + memcpy(&tmp, beg, 4); + memcpy(beg, end, 4); + memcpy(end, &tmp, 4); beg += 4; end -= 4; } } } break; } case (VERTICAL): { uint w = width(); uint h = height(); if (sixteenBit()) { unsigned short tmp[4]; unsigned short* line1 = nullptr; unsigned short* line2 = nullptr; unsigned short* data = reinterpret_cast(bits()); // can be done inplace + uint hHalf = (h / 2); for (uint y = 0 ; y < hHalf ; ++y) { line1 = data + y * w * 4; line2 = data + (h - y - 1) * w * 4; for (uint x = 0 ; x < w ; ++x) { - memcpy(&tmp, line1, 8); + memcpy(&tmp, line1, 8); memcpy(line1, line2, 8); - memcpy(line2, &tmp, 8); + memcpy(line2, &tmp, 8); line1 += 4; line2 += 4; } } } else { uchar tmp[4]; uchar* line1 = nullptr; uchar* line2 = nullptr; uchar* data = bits(); // can be done inplace + uint hHalf = (h / 2); for (uint y = 0 ; y < hHalf ; ++y) { line1 = data + y * w * 4; line2 = data + (h - y - 1) * w * 4; for (uint x = 0 ; x < w ; ++x) { - memcpy(&tmp, line1, 4); + memcpy(&tmp, line1, 4); memcpy(line1, line2, 4); - memcpy(line2, &tmp, 4); + memcpy(line2, &tmp, 4); line1 += 4; line2 += 4; } } } break; } default: break; } } bool DImg::rotateAndFlip(int orientation) { bool rotatedOrFlipped = false; m_priv->orientation = orientation; switch (orientation) { case DMetadata::ORIENTATION_NORMAL: case DMetadata::ORIENTATION_UNSPECIFIED: return false; case DMetadata::ORIENTATION_HFLIP: flip(DImg::HORIZONTAL); rotatedOrFlipped = true; break; case DMetadata::ORIENTATION_ROT_180: rotate(DImg::ROT180); rotatedOrFlipped = true; break; case DMetadata::ORIENTATION_VFLIP: flip(DImg::VERTICAL); rotatedOrFlipped = true; break; case DMetadata::ORIENTATION_ROT_90_HFLIP: rotate(DImg::ROT90); flip(DImg::HORIZONTAL); rotatedOrFlipped = true; break; case DMetadata::ORIENTATION_ROT_90: rotate(DImg::ROT90); rotatedOrFlipped = true; break; case DMetadata::ORIENTATION_ROT_90_VFLIP: rotate(DImg::ROT90); flip(DImg::VERTICAL); rotatedOrFlipped = true; break; case DMetadata::ORIENTATION_ROT_270: rotate(DImg::ROT270); rotatedOrFlipped = true; break; } return rotatedOrFlipped; } bool DImg::reverseRotateAndFlip(int orientation) { bool rotatedOrFlipped = false; m_priv->orientation = orientation; switch (orientation) { case DMetadata::ORIENTATION_NORMAL: case DMetadata::ORIENTATION_UNSPECIFIED: return false; case DMetadata::ORIENTATION_HFLIP: flip(DImg::HORIZONTAL); rotatedOrFlipped = true; break; case DMetadata::ORIENTATION_ROT_180: rotate(DImg::ROT180); rotatedOrFlipped = true; break; case DMetadata::ORIENTATION_VFLIP: flip(DImg::VERTICAL); rotatedOrFlipped = true; break; case DMetadata::ORIENTATION_ROT_90_HFLIP: flip(DImg::HORIZONTAL); rotate(DImg::ROT270); rotatedOrFlipped = true; break; case DMetadata::ORIENTATION_ROT_90: rotate(DImg::ROT270); rotatedOrFlipped = true; break; case DMetadata::ORIENTATION_ROT_90_VFLIP: flip(DImg::VERTICAL); rotate(DImg::ROT270); rotatedOrFlipped = true; break; case DMetadata::ORIENTATION_ROT_270: rotate(DImg::ROT90); rotatedOrFlipped = true; break; } return rotatedOrFlipped; } bool DImg::transform(int transformAction) { switch (transformAction) { case MetaEngineRotation::NoTransformation: default: return false; break; + case MetaEngineRotation::FlipHorizontal: flip(DImg::HORIZONTAL); break; + case MetaEngineRotation::FlipVertical: flip(DImg::VERTICAL); break; + case MetaEngineRotation::Rotate90: rotate(DImg::ROT90); break; + case MetaEngineRotation::Rotate180: rotate(DImg::ROT180); break; + case MetaEngineRotation::Rotate270: rotate(DImg::ROT270); break; } + return true; } bool DImg::wasExifRotated() { QVariant rotated(attribute(QLatin1String("exifRotated"))); return (rotated.isValid() && rotated.toBool()); } bool DImg::exifRotate(const QString& filePath) { if (wasExifRotated()) { return false; } // Rotate image based on metadata orientation information + setAttribute(QLatin1String("exifRotated"), true); + return rotateAndFlip(exifOrientation(filePath)); } bool DImg::reverseExifRotate(const QString& filePath) { return reverseRotateAndFlip(exifOrientation(filePath)); } int DImg::orientation() const { return m_priv->orientation; } } // namespace Digikam diff --git a/core/libs/dimg/dshareddata.h b/core/libs/dimg/dshareddata.h index 5730ca2b78..db19538ebe 100644 --- a/core/libs/dimg/dshareddata.h +++ b/core/libs/dimg/dshareddata.h @@ -1,289 +1,289 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2007-06-21 * Description : Shared data with reference counting and explicit sharing * * Copyright (C) 1992-2006 Trolltech ASA. * Copyright (C) 2007-2011 by Marcel Wiesweg * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_DSHARED_DATA_H #define DIGIKAM_DSHARED_DATA_H // Qt includes #include // Local includes #include "digikam_export.h" namespace Digikam { -class DIGIKAM_EXPORT DSharedData +class DIGIKAM_EXPORT Q_DECL_DEPRECATED DSharedData { /** * Classes that are used with a DSharedDataPointer shall inherit from * this class. */ public: QAtomicInt ref; inline DSharedData() : ref(0) { } inline DSharedData(const DSharedData&) : ref(0) { } /** * Returns true if the reference count is not 0. * For the normal use case, you do not need this method. */ inline bool isReferenced() const { return ((int)ref > 0); } inline bool hasMoreReferences() const { return ((int)ref != 1); } private: /// using the assignment operator would lead to corruption in the ref-counting DSharedData& operator=(const DSharedData&); }; // -------------------------------------------------------------------------------------- template class DSharedDataPointer { public: /** * Use this class to store pointers to a shared data object, which * inherits DSharedData. * This class is inspired by QSharedDataPointer, but differs in two points: * - it provides "explicit sharing": A change to the data affects all classes * keeping a pointer to the shared data. No automatic copying is done. * - no method "detach()" is provided, acknowledging the fact that the * copy constructor of class T may not be used. */ /** * Various operators for accessing the pointer const and non-const */ inline T& operator*() { return *d; } inline const T& operator*() const { return *d; } inline T* operator->() { return d; } inline const T* operator->() const { return d; } inline operator T* () { return d; } inline operator const T* () const { return d; } inline T* data() { return d; } inline const T* data() const { return d; } inline const T* constData() const { return d; } /** * This method carries out a const_cast, so it returns a non-const pointer * from a const DSharedDataPointer. * Typically, this should only be used if you know it should be used * (to implement a lazy loading caching technique or similar) */ inline T* constCastData() const { return const_cast(d); } inline bool operator==(const DSharedDataPointer& other) const { return (d == other.d); } inline bool operator!=(const DSharedDataPointer& other) const { return (d != other.d); } inline DSharedDataPointer() { d = nullptr; } explicit inline DSharedDataPointer(T* const data) : d(data) { if (d) { d->ref.ref(); } } inline ~DSharedDataPointer() { if (d && !d->ref.deref()) { delete d; } } inline DSharedDataPointer(const DSharedDataPointer& o) : d(o.d) { if (d) { d->ref.ref(); } } inline DSharedDataPointer& operator=(const DSharedDataPointer& o) { delete assign(o); return *this; } inline DSharedDataPointer& operator=(T* const o) { delete assign(o); return *this; } /** * The assign operator is like operator=, * with the difference that the old pointer is not deleted * if its reference count is 0, but returned. * Use this if you need to do your own deleting, if e.g. * the object need to be removed from a list or a cache. * @returns A T object with reference count 0, which may be deleted; * or 0 if no object need to be dropped. */ inline T* assign(const DSharedDataPointer& o) { if (o.d != d) { // reference new value if (o.d) { o.d->ref.ref(); } // store old value T* x = d; // assign new value d = o.d; // dereference old value, // return value and ownership if dereferenced if (x && !x->ref.deref()) { return x; } } return nullptr; } inline T* assign(T* const o) { if (o != d) { // reference new value if (o) { o->ref.ref(); } // store old value T* x = d; // assign new value d = o; // dereference old value, // return value and ownership if dereferenced if (x && !x->ref.deref()) { return x; } } return nullptr; } /** * Semantics like assign, but no new pointer is assigned to this. */ inline T* unassign() { return assign(nullptr); } inline bool operator!() const { return !d; } private: T* d; }; } // namespace Digikam #endif // DIGIKAM_DSHARED_DATA_H diff --git a/project/bundles/macports/01-build-macports.sh b/project/bundles/macports/01-build-macports.sh index f2225c9543..b028f0b79c 100755 --- a/project/bundles/macports/01-build-macports.sh +++ b/project/bundles/macports/01-build-macports.sh @@ -1,311 +1,313 @@ #! /bin/bash # Script to build a bundle Macports installation with all digiKam dependencies in a dedicated directory # This script must be run as sudo # # Copyright (c) 2015 by Shanti, # Copyright (c) 2015-2020 by Gilles Caulier # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # # Ask to run as root (( EUID != 0 )) && exec sudo -- "$0" "$@" # Halt and catch errors set -eE trap 'PREVIOUS_COMMAND=$THIS_COMMAND; THIS_COMMAND=$BASH_COMMAND' DEBUG trap 'echo "FAILED COMMAND: $PREVIOUS_COMMAND"' ERR ################################################################################################# # Manage script traces to log file mkdir -p ./logs exec > >(tee ./logs/build-macports.full.log) 2>&1 ################################################################################################# echo "01-build-macports.sh : build a bundle Macports install with digiKam dependencies." echo "---------------------------------------------------------------------------------" ################################################################################################# # Pre-processing checks . ./config.sh . ./common.sh StartScript ChecksRunAsRoot ChecksXCodeCLI ChecksCPUCores OsxCodeName #RegisterRemoteServers ################################################################################################# # Pathes rules ORIG_PATH="$PATH" ORIG_WD="`pwd`" export PATH=$INSTALL_PREFIX/bin:/$INSTALL_PREFIX/sbin:/$INSTALL_PREFIX/libexec/qt5/bin:$ORIG_PATH ################################################################################################# # Check if /opt exists and standard Macports install path if [ -d "/opt" ] ; then if [ -d "/opt/local" ] ; then echo "---------- A standard Macports install exists on /opt/local." echo " To prevent wrong links from this bundle to this repository" echo " this one must be disabled (moving to /opt/local.back for ex)." echo "---------- Aborting..." exit; fi else echo "---------- /opt do not exist, creating" mkdir "/opt" if [ $? -ne 0 ] ; then echo "---------- Cannot create /opt directory." echo "---------- Aborting..." exit; fi fi ################################################################################################# # Check if a previous bundle already exist CONTINUE_INSTALL=0 if [ -d "$INSTALL_PREFIX" ] ; then read -p "$INSTALL_PREFIX already exist. Do you want to remove it or to continue an aborted previous installation ? [(r)emove/(c)ontinue/(s)top] " answer if echo "$answer" | grep -iq "^r" ;then echo "---------- Removing existing $INSTALL_PREFIX" mv $INSTALL_PREFIX $INSTALL_PREFIX.old rm -rf $INSTALL_PREFIX.old elif echo "$answer" | grep -iq "^c" ;then echo "---------- Continue aborted previous installation in $INSTALL_PREFIX" CONTINUE_INSTALL=1 else echo "---------- Aborting..." exit; fi fi if [[ $CONTINUE_INSTALL == 0 ]]; then ################################################################################################# # Target directory creation echo "---------- Creating $INSTALL_PREFIX" mkdir "$INSTALL_PREFIX" if [ $? -ne 0 ] ; then echo "---------- Cannot create target install directory $INSTALL_PREFIX" echo "---------- Aborting..." exit; fi ################################################################################################# # Check latest Macports version available if necessary if [ -z $MP_VERSION ] ; then MP_LASTEST_VER=$(curl $MP_URL | \ egrep -o 'href="MacPorts-[0-9]+\.[0-9]+\.[0-9]+' | \ sed 's/^href="MacPorts-//' | \ sort -t. -rn -k1,1 -k2,2 -k3,3 | head -1) if [ -z $MP_LASTEST_VER ] ; then echo "---------- Cannot check the lastest Macports verion from $MP_URL" echo "---------- Aborting..." exit; fi echo "---------- Detected lastest Macports version : $MP_LASTEST_VER" MP_VERSION=$MP_LASTEST_VER fi ################################################################################################# # Build Macports in temporary directory and installation if [ -d "$MP_BUILDTEMP" ] ; then echo "---------- Removing existing $MP_BUILDTEMP" rm -rf "$MP_BUILDTEMP" fi echo "---------- Creating $MP_BUILDTEMP" mkdir "$MP_BUILDTEMP" if [ $? -ne 0 ] ; then echo "---------- Cannot create temporary directory $MP_BUILDTEMP to compile Macports" echo "---------- Aborting..." exit; fi cd "$MP_BUILDTEMP" echo -e "\n\n" echo "---------- Downloading MacPorts $MP_VERSION" curl -o "MacPorts-$MP_VERSION.tar.bz2" "$MP_URL/MacPorts-$MP_VERSION.tar.bz2" tar jxvf MacPorts-$MP_VERSION.tar.bz2 cd MacPorts-$MP_VERSION echo -e "\n\n" echo "---------- Configuring MacPorts" ./configure --prefix="$INSTALL_PREFIX" \ --with-applications-dir="$INSTALL_PREFIX/Applications" \ --with-no-root-privileges \ --with-install-user="$(id -n -u)" \ --with-install-group="$(id -n -g)" echo -e "\n\n" echo "---------- Building MacPorts" make -j$CPU_CORES echo -e "\n\n" echo "---------- Installing MacPorts" echo -e "\n\n" make install && cd "$ORIG_WD" && rm -rf "$MP_BUILDTEMP" cat << EOF >> "$INSTALL_PREFIX/etc/macports/macports.conf" +no_root -startupitem startupitem_type none startupitem_install no macosx_deployment_target $OSX_MIN_TARGET EOF fi ################################################################################################# # Macports update echo -e "\n" echo "---------- Updating MacPorts" port -v selfupdate if [[ $CONTINUE_INSTALL == 0 ]]; then # port -v upgrade outdated echo -e "\n" #echo "---------- Modifying net-snmp portfile to install when not root" #sed -e "/install.asroot/ s|yes|no|" -i ".orig" "`port file net-snmp`" fi ################################################################################################# # Dependencies build and installation echo -e "\n" echo "---------- Building digiKam dependencies with Macports" # With OSX less than El Capitan, we need a more recent Clang compiler than one provided by XCode. if [[ $MAJOR_OSX_VERSION -lt 10 ]]; then echo "---------- Install more recent Clang compiler from Macports for specific ports" port install clang_select port install clang-3.4 port select --set clang mp-clang-3.4 fi echo -e "\n" port install \ ld64 +ld64_xcode \ cmake \ libpng \ jpeg \ tiff \ boost \ eigen3 \ gettext \ libusb \ libgphoto2 \ jasper \ lcms2 \ expat \ libxml2 \ libxslt \ libical \ lensfun \ bison \ x265 \ ffmpeg \ qt5-qtbase \ qt5-qtdeclarative \ qt5-qtmacextras \ qt5-qtquickcontrols \ qt5-qtxmlpatterns \ qt5-qtsvg \ qt5-qttools \ qt5-qttranslations \ qt5-qtimageformats \ qt5-sqlite-plugin \ qt5-mysql-plugin \ wget +ssl \ ImageMagick +if [[ $DK_QTWEBENGINE = 1 ]] ; then + port install qt5-qtwebengine +fi + # sane-backends echo -e "\n" echo -e "---------- Compilation logs of Macports packages with suspicious installation\n" find $INSTALL_PREFIX/var/macports/logs/ -name main.log echo -e "\n----------" echo -e "\n" ################################################################################################# # Create the build dir for the 3rdparty deps if [ ! -d $BUILDING_DIR ] ; then mkdir $BUILDING_DIR fi if [ ! -d $DOWNLOAD_DIR ] ; then mkdir $DOWNLOAD_DIR fi cd $BUILDING_DIR rm -rf $BUILDING_DIR/* || true cmake $ORIG_WD/../3rdparty \ -DCMAKE_INSTALL_PREFIX:PATH=$INSTALL_PREFIX \ -DINSTALL_ROOT=$INSTALL_PREFIX \ -DEXTERNALS_DOWNLOAD_DIR=$DOWNLOAD_DIR \ + -DENABLE_QTWEBENGINE=$DK_QTWEBENGINE \ -Wno-dev -cmake --build . --config RelWithDebInfo --target ext_qtwebkit -- -j$CPU_CORES +if [[ $DK_QTWEBENGINE = 0 ]] ; then + cmake --build . --config RelWithDebInfo --target ext_qtwebkit -- -j$CPU_CORES +fi + cmake --build . --config RelWithDebInfo --target ext_opencv -- -j$CPU_CORES cmake --build . --config RelWithDebInfo --target ext_exiv2 -- -j$CPU_CORES cmake --build . --config RelWithDebInfo --target ext_qtav -- -j$CPU_CORES ################################################################################################# -#ln -s $INSTALL_PREFIX/lib/cmake/Qt5WebKitWidgets $INSTALL_PREFIX/libexec/qt5/lib/cmake/ -#ln -s $INSTALL_PREFIX/lib/QtWebKitWidgets.framework $INSTALL_PREFIX/libexec/qt5/lib/ -#ln -s $INSTALL_PREFIX/lib/QtWebKit.framework $INSTALL_PREFIX/libexec/qt5/lib/ -#ln -s $INSTALL_PREFIX/include/QtWebKitWidgets $INSTALL_PREFIX/libexec/qt5/include/ -#ln -s $INSTALL_PREFIX/include/QtWebKit $INSTALL_PREFIX/libexec/qt5/include/ - export PATH=$ORIG_PATH TerminateScript diff --git a/project/bundles/macports/02-build-extralibs.sh b/project/bundles/macports/02-build-extralibs.sh index a5d380cd81..9f5c284541 100755 --- a/project/bundles/macports/02-build-extralibs.sh +++ b/project/bundles/macports/02-build-extralibs.sh @@ -1,116 +1,117 @@ #! /bin/bash # Script to build extra libraries using MacPorts env. # This script must be run as sudo # # Copyright (c) 2015-2020 by Gilles Caulier # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # # Ask to run as root (( EUID != 0 )) && exec sudo -- "$0" "$@" # Halt and catch errors set -eE trap 'PREVIOUS_COMMAND=$THIS_COMMAND; THIS_COMMAND=$BASH_COMMAND' DEBUG trap 'echo "FAILED COMMAND: $PREVIOUS_COMMAND"' ERR ################################################################################################# # Manage script traces to log file mkdir -p ./logs exec > >(tee ./logs/build-extralibs.full.log) 2>&1 ################################################################################################# echo "02-build-extralibs.sh : build extra libraries using MacPorts." echo "-------------------------------------------------------------" ################################################################################################# # Pre-processing checks . ./config.sh . ./common.sh StartScript ChecksRunAsRoot ChecksXCodeCLI ChecksCPUCores OsxCodeName #RegisterRemoteServers ################################################################################################# # Pathes rules ORIG_PATH="$PATH" ORIG_WD="`pwd`" export PATH=$INSTALL_PREFIX/bin:/$INSTALL_PREFIX/sbin:/$INSTALL_PREFIX/libexec/qt5/bin:$ORIG_PATH ################################################################################################# # Create the build dir for the 3rdparty deps if [ ! -d $BUILDING_DIR ] ; then mkdir $BUILDING_DIR fi if [ ! -d $DOWNLOAD_DIR ] ; then mkdir $DOWNLOAD_DIR fi cd $BUILDING_DIR rm -rf $BUILDING_DIR/* || true cmake $ORIG_WD/../3rdparty \ -DCMAKE_INSTALL_PREFIX:PATH=$INSTALL_PREFIX \ -DINSTALL_ROOT=$INSTALL_PREFIX \ -DEXTERNALS_DOWNLOAD_DIR=$DOWNLOAD_DIR \ + -DENABLE_QTWEBENGINE=$DK_QTWEBENGINE \ -Wno-dev # NOTE: The order to compile each component here is very important. # core KF5 frameworks dependencies cmake --build . --config RelWithDebInfo --target ext_extra-cmake-modules -- -j$CPU_CORES cmake --build . --config RelWithDebInfo --target ext_kconfig -- -j$CPU_CORES cmake --build . --config RelWithDebInfo --target ext_breeze-icons -- -j$CPU_CORES cmake --build . --config RelWithDebInfo --target ext_kcoreaddons -- -j$CPU_CORES cmake --build . --config RelWithDebInfo --target ext_kwindowsystem -- -j$CPU_CORES cmake --build . --config RelWithDebInfo --target ext_solid -- -j$CPU_CORES cmake --build . --config RelWithDebInfo --target ext_threadweaver -- -j$CPU_CORES cmake --build . --config RelWithDebInfo --target ext_karchive -- -j$CPU_CORES cmake --build . --config RelWithDebInfo --target ext_kdbusaddons -- -j$CPU_CORES cmake --build . --config RelWithDebInfo --target ext_ki18n -- -j$CPU_CORES cmake --build . --config RelWithDebInfo --target ext_kcrash -- -j$CPU_CORES cmake --build . --config RelWithDebInfo --target ext_kcodecs -- -j$CPU_CORES cmake --build . --config RelWithDebInfo --target ext_kauth -- -j$CPU_CORES cmake --build . --config RelWithDebInfo --target ext_kguiaddons -- -j$CPU_CORES cmake --build . --config RelWithDebInfo --target ext_kwidgetsaddons -- -j$CPU_CORES cmake --build . --config RelWithDebInfo --target ext_kitemviews -- -j$CPU_CORES cmake --build . --config RelWithDebInfo --target ext_kcompletion -- -j$CPU_CORES cmake --build . --config RelWithDebInfo --target ext_kconfigwidgets -- -j$CPU_CORES cmake --build . --config RelWithDebInfo --target ext_kiconthemes -- -j$CPU_CORES cmake --build . --config RelWithDebInfo --target ext_kservice -- -j$CPU_CORES cmake --build . --config RelWithDebInfo --target ext_kglobalaccel -- -j$CPU_CORES cmake --build . --config RelWithDebInfo --target ext_kxmlgui -- -j$CPU_CORES cmake --build . --config RelWithDebInfo --target ext_kbookmarks -- -j$CPU_CORES cmake --build . --config RelWithDebInfo --target ext_kimageformats -- -j$CPU_CORES # libksane support #cmake --build . --config RelWithDebInfo --target ext_libksane -- -j$CPU_CORES # Geolocation support cmake --build . --config RelWithDebInfo --target ext_marble -- -j$CPU_CORES # Calendar support cmake --build . --config RelWithDebInfo --target ext_kcalcore -- -j$CPU_CORES # Marble install shared lib at wrong place. mv $INSTALL_PREFIX/Marble.app/Contents/MacOS/lib/libastro* $INSTALL_PREFIX/lib mv $INSTALL_PREFIX/Marble.app/Contents/MacOS/lib/libmarble* $INSTALL_PREFIX/lib ################################################################################################# export PATH=$ORIG_PATH TerminateScript diff --git a/project/bundles/macports/03-build-digikam.sh b/project/bundles/macports/03-build-digikam.sh index 830262b9f4..b6a6cbd42a 100755 --- a/project/bundles/macports/03-build-digikam.sh +++ b/project/bundles/macports/03-build-digikam.sh @@ -1,179 +1,188 @@ #! /bin/bash # Script to build digiKam using MacPorts # This script must be run as sudo # # Copyright (c) 2015-2020 by Gilles Caulier # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # # Ask to run as root (( EUID != 0 )) && exec sudo -- "$0" "$@" # Halt and catch errors set -eE trap 'PREVIOUS_COMMAND=$THIS_COMMAND; THIS_COMMAND=$BASH_COMMAND' DEBUG trap 'echo "FAILED COMMAND: $PREVIOUS_COMMAND"' ERR ################################################################################################# # Manage script traces to log file mkdir -p ./logs exec > >(tee ./logs/build-digikam.full.log) 2>&1 ################################################################################################# echo "03-build-digikam.sh : build digiKam using MacPorts." echo "---------------------------------------------------" ################################################################################################# # Pre-processing checks . ./config.sh . ./common.sh StartScript ChecksRunAsRoot ChecksXCodeCLI ChecksCPUCores OsxCodeName #RegisterRemoteServers ################################################################################################# # Pathes rules ORIG_PATH="$PATH" ORIG_WD="`pwd`" export PATH=$INSTALL_PREFIX/bin:/$INSTALL_PREFIX/sbin:$ORIG_PATH ################################################################################################# # Install out-dated dependencies cd $BUILDING_DIR rm -rf $BUILDING_DIR/* || true cmake $ORIG_WD/../3rdparty \ -DCMAKE_INSTALL_PREFIX:PATH=$INSTALL_PREFIX \ -DINSTALL_ROOT=$INSTALL_PREFIX \ -DEXTERNALS_DOWNLOAD_DIR=$DOWNLOAD_DIR \ + -DENABLE_QTWEBENGINE=$DK_QTWEBENGINE \ -Wno-dev cmake --build . --config RelWithDebInfo --target ext_lensfun -- -j$CPU_CORES ################################################################################################# # Build digiKam in temporary directory and installation if [ -d "$DK_BUILDTEMP/digikam-$DK_VERSION" ] ; then echo "---------- Updating existing $DK_BUILDTEMP" cd "$DK_BUILDTEMP" cd digikam-$DK_VERSION git reset --hard git pull mkdir -p build else echo "---------- Creating $DK_BUILDTEMP" mkdir -p "$DK_BUILDTEMP" if [ $? -ne 0 ] ; then echo "---------- Cannot create $DK_BUILDTEMP directory." echo "---------- Aborting..." exit; fi cd "$DK_BUILDTEMP" echo -e "\n\n" echo "---------- Downloading digiKam $DK_VERSION" git clone --progress --verbose $DK_GITURL digikam-$DK_VERSION cd digikam-$DK_VERSION if [ $? -ne 0 ] ; then echo "---------- Cannot clone repositories." echo "---------- Aborting..." exit; fi git checkout $DK_VERSION mkdir build fi echo -e "\n\n" echo "---------- Configure digiKam $DK_VERSION" sed -e "s/DIGIKAMSC_CHECKOUT_PO=OFF/DIGIKAMSC_CHECKOUT_PO=ON/g" ./bootstrap.macports > ./tmp.macports ; mv -f ./tmp.macports ./bootstrap.macports sed -e "s/DIGIKAMSC_COMPILE_PO=OFF/DIGIKAMSC_COMPILE_PO=ON/g" ./bootstrap.macports > ./tmp.macports ; mv -f ./tmp.macports ./bootstrap.macports sed -e "s/DBUILD_TESTING=ON/DBUILD_TESTING=OFF/g" ./bootstrap.macports > ./tmp.macports ; mv -f ./tmp.macports ./bootstrap.macports sed -e "s/DENABLE_DBUS=ON/DENABLE_DBUS=OFF/g" ./bootstrap.macports > ./tmp.macports ; mv -f ./tmp.macports ./bootstrap.macports + +if [[ $DK_QTWEBENGINE = 1 ]] ; then + + sed -e "s/DENABLE_QWEBENGINE=OFF/DENABLE_QWEBENGINE=ON/g" ./bootstrap.macports > ./tmp.macports ; mv -f ./tmp.macports ./bootstrap.macports + +fi + chmod +x ./bootstrap.macports cp -f $ORIG_WD/fixbundledatapath.sh $DK_BUILDTEMP/digikam-$DK_VERSION ./fixbundledatapath.sh ./bootstrap.macports "$INSTALL_PREFIX" "Debug" "x86_64" "-Wno-dev" if [ $? -ne 0 ]; then echo "---------- Cannot configure digiKam $DK_VERSION." echo "---------- Aborting..." exit; fi cat ./build/core/app/utils/digikam_version.h | grep "digikam_version\[\]" | awk '{print $6}' | tr -d '";' > $ORIG_WD/data/RELEASEID.txt echo -e "\n\n" echo "---------- Building digiKam $DK_VERSION" cd build make -j$CPU_CORES if [ $? -ne 0 ]; then echo "---------- Cannot compile digiKam $DK_VERSION." echo "---------- Aborting..." exit; fi echo -e "\n\n" echo "---------- Installing digiKam $DK_VERSION" echo -e "\n\n" make install/fast && cd "$ORIG_WD" && rm -rf "$DK_BUILDTEMP" if [ $? -ne 0 ]; then echo "---------- Cannot install digiKam $DK_VERSION." echo "---------- Aborting..." exit; fi ################################################################################################# # Install Extra Plugins cd $BUILDING_DIR rm -rf $BUILDING_DIR/* || true cmake $ORIG_WD/../3rdparty \ -DCMAKE_INSTALL_PREFIX:PATH=$INSTALL_PREFIX \ -DINSTALL_ROOT=$INSTALL_PREFIX \ -DEXTERNALS_DOWNLOAD_DIR=$DOWNLOAD_DIR \ + -DENABLE_QTWEBENGINE=$DK_QTWEBENGINE \ -Wno-dev cmake --build . --config RelWithDebInfo --target ext_gmic_qt -- -j$CPU_CORES mv -f $INSTALL_PREFIX/libexec/qt5/plugins/digikam/editor/*.so $INSTALL_PREFIX/lib/plugins/digikam/editor/ ################################################################################################# export PATH=$ORIG_PATH TerminateScript diff --git a/project/bundles/macports/04-build-installer.sh b/project/bundles/macports/04-build-installer.sh index f7c57265ca..6cd259ff67 100755 --- a/project/bundles/macports/04-build-installer.sh +++ b/project/bundles/macports/04-build-installer.sh @@ -1,562 +1,586 @@ #! /bin/bash # Script to bundle data using previously-built digiKam installation. # and create a PKG file with Packages application (http://s.sudre.free.fr/Software/Packages/about.html) # This script must be run as sudo # # Copyright (c) 2015 by Shanti, # Copyright (c) 2015-2020 by Gilles Caulier # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # # Ask to run as root (( EUID != 0 )) && exec sudo -- "$0" "$@" # Halt and catch errors set -eE trap 'PREVIOUS_COMMAND=$THIS_COMMAND; THIS_COMMAND=$BASH_COMMAND' DEBUG trap 'echo "FAILED COMMAND: $PREVIOUS_COMMAND"' ERR ################################################################################################# # Manage script traces to log file mkdir -p ./logs exec > >(tee ./logs/build-installer.full.log) 2>&1 ################################################################################################# echo "04-build-installer.sh : build digiKam bundle PKG." echo "-------------------------------------------------" ################################################################################################# # Pre-processing checks . ./config.sh . ./common.sh StartScript ChecksRunAsRoot ChecksXCodeCLI ChecksCPUCores OsxCodeName #RegisterRemoteServers ################################################################################################# # Pathes rules ORIG_PATH="$PATH" ORIG_WD="`pwd`" export PATH=$INSTALL_PREFIX/bin:/$INSTALL_PREFIX/sbin:$ORIG_PATH DKRELEASEID=`cat $ORIG_WD/data/RELEASEID.txt` ################################################################################################# # Build icons-set ressource echo -e "\n---------- Build icons-set ressource\n" cd $ORIG_WD/icon-rcc rm -f CMakeCache.txt > /dev/null cp -f $ORIG_WD/../../../bootstrap.macports . cmake -DCMAKE_INSTALL_PREFIX="$INSTALL_PREFIX" \ -DCMAKE_BUILD_TYPE=debug \ -DCMAKE_COLOR_MAKEFILE=ON \ -Wno-dev \ . make -j$CPU_CORES cd $ORIG_WD ################################################################################################# # Configurations # Directory where this script is located (default - current directory) BUILDDIR="$PWD" # Directory where Packages project files are located PROJECTDIR="$BUILDDIR/installer" # Staging area where files to be packaged will be copied TEMPROOT="$BUILDDIR/$INSTALL_PREFIX" # Applications to be launched directly by user (create launch scripts) KDE_MENU_APPS="\ digikam \ showfoto \ " # Paths to search for applications above KDE_APP_PATHS="\ Applications/KF5 \ " # Other apps - non-MacOS binaries & libraries to be included with required dylibs OTHER_APPS="\ Applications/KF5/digikam.app/Contents/MacOS/digikam \ Applications/KF5/showfoto.app/Contents/MacOS/showfoto \ lib/plugins/imageformats/*.so \ lib/plugins/digikam/bqm/*.so \ lib/plugins/digikam/generic/*.so \ lib/plugins/digikam/editor/*.so \ lib/plugins/digikam/dimg/*.so \ lib/mariadb/bin/mysql \ lib/mariadb/bin/mysqld \ lib/mariadb/bin/my_print_defaults \ lib/mariadb/bin/mysqladmin \ lib/mariadb/bin/mysqltest \ lib/mariadb/mysql/*.dylib \ lib/mariadb/plugin/*.so \ lib/ImageMagick*/modules-Q16/coders/*.so \ lib/ImageMagick*/modules-Q16/filters/*.so \ bin/kbuildsycoca5 \ libexec/qt5/plugins/imageformats/*.dylib \ libexec/qt5/plugins/sqldrivers/*.dylib \ libexec/qt5/plugins/printsupport/*.dylib \ libexec/qt5/plugins/platforms/*.dylib \ libexec/qt5/plugins/platformthemes/*.dylib \ libexec/qt5/plugins/iconengines/*.dylib \ libexec/qt5/plugins/generic/*.dylib \ libexec/qt5/plugins/styles/*.dylib \ libexec/qt5/plugins/bearer/*.dylib \ " #lib/sane/*.so \ binaries="$OTHER_APPS" # Additional Files/Directories - to be copied recursively but not checked for dependencies OTHER_DIRS="\ lib/plugins \ lib/libgphoto2 \ lib/libgphoto2_port \ lib/mariadb \ lib/ImageMagick* \ share/mariadb \ share/ImageMagick* \ etc/xdg \ etc/ImageMagick* \ " #etc/sane.d \ # Additional Data Directories - to be copied recursively OTHER_DATA="\ share/applications \ share/OpenCV \ share/k* \ share/lensfun \ share/mime \ Library/Application/ \ Marble.app/Contents/Resources/ \ Marble.app/Contents/MacOS/resources/ \ " # Packaging tool paths PACKAGESBUILD="/usr/local/bin/packagesbuild" RECURSIVE_LIBRARY_LISTER="$BUILDDIR/rll.py" echo "digiKam version: $DKRELEASEID" # ./installer sub-dir must be writable by root chmod 777 ${PROJECTDIR} ################################################################################################# # Check if Packages CLI tools are installed if [[ (! -f "$PACKAGESBUILD") ]] ; then echo "Packages CLI tool is not installed" echo "See http://s.sudre.free.fr/Software/Packages/about.html for details." exit 1 else echo "Check Packages CLI tool passed..." fi ################################################################################################# # Create temporary dir to build package contents if [ -d "$TEMPROOT" ] ; then echo "---------- Removing temporary packaging directory $TEMPROOT" rm -rf "$TEMPROOT" fi echo "Creating $TEMPROOT" mkdir -p "$TEMPROOT/Applications/digiKam" ################################################################################################# # Prepare applications for MacOS echo "---------- Preparing Applications for MacOS" for app in $KDE_MENU_APPS ; do echo " $app" # Look for application for searchpath in $KDE_APP_PATHS ; do # Copy the application if it is found (create directory if necessary) if [ -d "$INSTALL_PREFIX/$searchpath/$app.app" ] ; then echo " Found $app in $INSTALL_PATH/$searchpath" # Create destination directory if necessary and copy app if [ ! -d "$TEMPROOT/$searchpath" ] ; then echo " Creating $TEMPROOT/$searchpath" mkdir -p "$TEMPROOT/$searchpath" fi echo " Copying $app" cp -pr "$INSTALL_PREFIX/$searchpath/$app.app" "$TEMPROOT/$searchpath/" # Add executable to list of binaries for which we need to collect dependencies for binaries="$binaries $searchpath/$app.app/Contents/MacOS/$app" # If application is to be run by user, create Applescript launcher to # load kbuildsycoca5. Set DYLD_IMAGE_SUFFIX if built with debug variant if [[ $KDE_MENU_APPS == *"$app"* ]] ; then echo " Creating launcher script for $app" # Debug variant needs DYLD_IMAGE_SUFFIX="_debug set at runtime if [[ $DK_DEBUG = 1 ]] ; then DYLD_ENV_CMD="DYLD_IMAGE_SUFFIX=_debug " else DYLD_ENV_CMD="" fi # ------ Create application launcher script # Partially derived from https://discussions.apple.com/thread/3934912 and # http://stackoverflow.com/questions/16064957/how-to-check-in-applescript-if-an-app-is-running-without-launching-it-via-osa # and https://discussions.apple.com/thread/4059113 cat << EOF | osacompile -o "$TEMPROOT/Applications/digiKam/$app.app" #!/usr/bin/osascript log "Running $DYLD_ENV_CMD $INSTALL_PREFIX/bin/kbuildsycoca5" do shell script "$DYLD_ENV_CMD $INSTALL_PREFIX/bin/kbuildsycoca5" do shell script "$DYLD_ENV_CMD open $INSTALL_PREFIX/$searchpath/$app.app" EOF # ------ End application launcher script # Get application icon for launcher. If no icon file matches pattern app_SRCS.icns, grab the first icon if [ -f "$INSTALL_PREFIX/$searchpath/$app.app/Contents/Resources/${app}_SRCS.icns" ] ; then echo " Found icon for $app launcher" cp -p "$INSTALL_PREFIX/$searchpath/$app.app/Contents/Resources/${app}_SRCS.icns" "$TEMPROOT/Applications/digiKam/$app.app/Contents/Resources/applet.icns" else for icon in "$INSTALL_PREFIX/$searchpath/$app.app/"Contents/Resources/*.icns ; do echo " Using icon for $app launcher: $icon" cp -p "$icon" "$TEMPROOT/Applications/digiKam/$app.app/Contents/Resources/applet.icns" break done fi chmod 755 "$TEMPROOT/Applications/digiKam/$app.app" fi # Don't keep looking through search paths once we've found the app break fi done done ################################################################################################# # Collect dylib dependencies for all binaries, # then copy them to the staging area (creating directories as required) echo "---------- Collecting dependencies for applications, binaries, and libraries:" cd "$INSTALL_PREFIX" "$RECURSIVE_LIBRARY_LISTER" $binaries | sort -u | \ while read lib ; do lib="`echo $lib | sed "s:$INSTALL_PREFIX/::"`" if [ ! -e "$TEMPROOT/$lib" ] ; then dir="${lib%/*}" if [ ! -d "$TEMPROOT/$dir" ] ; then echo " Creating $TEMPROOT/$dir" mkdir -p "$TEMPROOT/$dir" fi echo " $lib" cp -aH "$INSTALL_PREFIX/$lib" "$TEMPROOT/$dir/" fi done ################################################################################################# # Copy non-binary files and directories, creating parent directories if needed echo "---------- Copying binary files..." for path in $OTHER_APPS ; do dir="${path%/*}" if [ ! -d "$TEMPROOT/$dir" ] ; then echo " Creating $TEMPROOT/$dir" mkdir -p "$TEMPROOT/$dir" fi echo " Copying $path" cp -a "$INSTALL_PREFIX/$path" "$TEMPROOT/$dir/" done echo "---------- Copying directory contents..." for path in $OTHER_DIRS ; do dir="${path%/*}" if [ ! -d "$TEMPROOT/$dir" ] ; then echo " Creating $TEMPROOT/$dir" mkdir -p "$TEMPROOT/$dir" fi echo " Copying $path" cp -a "$INSTALL_PREFIX/$path" "$TEMPROOT/$dir/" done echo "---------- Copying data files..." # Special case with data dirs. QStandardPaths::GenericDataLocation was patched everywhere # in source code by QStandardPaths::AppDataLocation for path in $OTHER_DATA ; do echo " Copying $path" cp -a "$INSTALL_PREFIX/$path" "$TEMPROOT/Applications/KF5/digikam.app/Contents/Resources/" done +echo "---------- Copying Qt Web Backend files..." + +# QWebEngine bin data files. +# NOTE: no ressources data are provided with QtWebKit +if [[ $DK_QTWEBENGINE = 1 ]] ; then + + cp -a "$INSTALL_PREFIX/ressources" "$TEMPROOT" + +fi + +if [[ $DK_QTWEBENGINE = 1 ]] ; then + + # QtWebEngine runtime process + [[ -e $INSTALL_PREFIX/libexec/qt5/libexec/QtWebEngineProcess ]] && cp -a "$INSTALL_PREFIX/libexec/qt5/libexec/QtWebEngineProcess" "$TEMPROOT/libexec/qt5/libexec/" + +else + + # QtWebKit runtime process + [[ -e $INSTALL_PREFIX/libexec/qt5/libexec/QtWebNetworkProcess ]] && cp -a "$INSTALL_PREFIX/libexec/qt5/libexec/QtWebNetworkProcess" "$TEMPROOT/libexec/qt5/libexec/" + [[ -e $INSTALL_PREFIX/libexec/qt5/libexec/QtWebProcess ]] && cp -a "$INSTALL_PREFIX/libexec/qt5/libexec/QtWebProcess" "$TEMPROOT/libexec/qt5/libexec/" + [[ -e $INSTALL_PREFIX/libexec/qt5/libexec/QtWebStorageProcess ]] && cp -a "$INSTALL_PREFIX/libexec/qt5/libexec/QtWebStorageProcess" "$TEMPROOT/libexec/qt5/libexec/" + +fi + echo "---------- Copying i18n..." i18nprefix=$INSTALL_PREFIX/share/ cd $i18nprefix FILES=$(cat $ORIG_WD/logs/build-extralibs.full.log | grep "$INSTALL_PREFIX/share/locale/" | cut -d' ' -f3 | awk '{sub("'"$i18nprefix"'","")}1') for FILE in $FILES ; do rsync -R "./$FILE" "$TEMPROOT/Applications/KF5/digikam.app/Contents/Resources/" done FILES=$(cat $ORIG_WD/logs/build-digikam.full.log | grep "$INSTALL_PREFIX/share/locale/" | cut -d' ' -f3 | awk '{sub("'"$i18nprefix"'","")}1') for FILE in $FILES ; do rsync -R "./$FILE" "$TEMPROOT/Applications/KF5/digikam.app/Contents/Resources/" done # Showfoto resources dir must be merged with digiKam. cp -a "$TEMPROOT/Applications/KF5/showfoto.app/Contents/Resources/" "$TEMPROOT/Applications/KF5/digikam.app/Contents/Resources/" rm -rf "$TEMPROOT/Applications/KF5/showfoto.app/Contents/Resources" # A symbolic link to install path where is installed digiKam resources will be used for Showfoto. ln -s "$INSTALL_PREFIX/Applications/KF5/digikam.app/Contents/Resources" "$TEMPROOT/Applications/KF5/showfoto.app/Contents/Resources" cd "$ORIG_WD" ################################################################################################# # Move digiKam and KF5 run-time plugins to the right place cp -a $TEMPROOT/lib/plugins $TEMPROOT/libexec/qt5/ rm -rf $TEMPROOT/lib/plugins ################################################################################################# # Create package pre-install script echo "---------- Create package pre-install script" # Delete /Applications entries, delete existing installation cat << EOF > "$PROJECTDIR/preinstall" #!/bin/bash if [ -d /Applications/digiKam ] ; then echo "Removing digikam from Applications folder" rm -r /Applications/digiKam fi if [ -d "$INSTALL_PREFIX" ] ; then echo "Removing $INSTALL_PREFIX" rm -rf "$INSTALL_PREFIX" fi EOF # Pre-install script need to be executable chmod 755 "$PROJECTDIR/preinstall" ################################################################################################# # Create package post-install script echo "---------- Create package post-install script" # Creates Applications menu icons cat << EOF > "$PROJECTDIR/postinstall" #!/bin/bash [[ ! -d /Applications/digiKam ]] && mkdir "/Applications/digiKam" for app in $INSTALL_PREFIX/Applications/digiKam/*.app ; do ln -s "\$app" /Applications/digiKam/\${app##*/} done EOF # Post-install script need to be executable chmod 755 "$PROJECTDIR/postinstall" ################################################################################################# # Copy icons-set resource files. cp $ORIG_WD/icon-rcc/breeze.rcc $TEMPROOT/Applications/KF5/digikam.app/Contents/Resources/ cp $ORIG_WD/icon-rcc/breeze-dark.rcc $TEMPROOT/Applications/KF5/digikam.app/Contents/Resources/ ################################################################################################# # Cleanup symbols in binary files to free space. #echo -e "\n---------- Strip symbols in binary files\n" # #if [[ $DK_DEBUG = 1 ]] ; then # find $TEMPROOT -name "*.so" | grep -Ev '(digikam|showfoto|exiv2)' | xargs strip -SXx # find $TEMPROOT -name "*.dylib" | grep -Ev '(digikam|showfoto|exiv2)' | xargs strip -SXx #else # find $TEMPROOT -name "*.so" | xargs strip -SXx # find $TEMPROOT -name "*.dylib" | xargs strip -SXx #fi ################################################################################################# # Relocate binary files # For details, see these urls: # https://stackoverflow.com/questions/9263256/can-you-please-help-me-understand-how-mach-o-libraries-work-in-mac-os-x # https://matthew-brett.github.io/docosx/mac_runtime_link.html # Not yet finalized ! if [ ]; then echo -e "\n---------- Relocate binary files" # relocate dynamic libraries with rpath DYLIBFILES=(`find $TEMPROOT/lib -name "*.dylib"`) RelocateBinaries DYLIBFILES[@] # relocate library executables and system objects files with rpath. # This include all binary files with extension as all Qt libraries. LIBEXECFILES=(`find $TEMPROOT/libexec -type f -perm +ugo+x`) RelocateBinaries LIBEXECFILES[@] # relocate main executable with rpath. MAINFILES="\ $TEMPROOT/Applications/KF5/digikam.app/Contents/MacOS/digikam \ $TEMPROOT/Applications/KF5/showfoto.app/Contents/MacOS/showfoto \ $TEMPROOT/bin/kbuildsycoca5 \ " RelocateBinaries MAINFILES[@] for APP in $MAINFILES ; do install_name_tool -add_rpath @executable_path/.. $APP install_name_tool -add_rpath @executable_path/../.. $APP install_name_tool -add_rpath @executable_path/../../.. $APP install_name_tool -add_rpath @executable_path/../../../.. $APP install_name_tool -add_rpath @executable_path/../../../../.. $APP install_name_tool -add_rpath @executable_path/../../../../../.. $APP done fi ################################################################################################# # Build PKG file echo "---------- Create MacOS package for digiKam $DKRELEASEID" mkdir -p $ORIG_WD/bundle rm -f $ORIG_WD/bundle/* || true TARGET_INSTALLER=digiKam-$DKRELEASEID$DK_EPOCH-MacOS-x86-64$DEBUG_SUF.pkg TARGET_PKG_FILE=$BUILDDIR/bundle/$TARGET_INSTALLER echo -e "Target PKG file : $TARGET_PKG_FILE" $PACKAGESBUILD -v "$PROJECTDIR/digikam.pkgproj" --package-version "$DKRELEASEID" mv "$PROJECTDIR/build/digikam.pkg" "$TARGET_PKG_FILE" ################################################################################################# # Show resume information and future instructions to host PKG file to remote server echo -e "\n---------- Compute package checksums for digiKam $DKRELEASEID\n" > $TARGET_PKG_FILE.sum echo "File : $TARGET_PKG_FILE" >> $TARGET_PKG_FILE.sum echo -n "Size : " >> $TARGET_PKG_FILE.sum du -h "$TARGET_PKG_FILE" | { read first rest ; echo $first ; } >> $TARGET_PKG_FILE.sum echo -n "MD5 sum : " >> $TARGET_PKG_FILE.sum md5 -q "$TARGET_PKG_FILE" >> $TARGET_PKG_FILE.sum echo -n "SHA1 sum : " >> $TARGET_PKG_FILE.sum shasum -a1 "$TARGET_PKG_FILE" | { read first rest ; echo $first ; } >> $TARGET_PKG_FILE.sum echo -n "SHA256 sum : " >> $TARGET_PKG_FILE.sum shasum -a256 "$TARGET_PKG_FILE" | { read first rest ; echo $first ; } >> $TARGET_PKG_FILE.sum # Checksums to post on Phabricator at release time. shasum -a256 "$TARGET_PKG_FILE" > $BUILDDIR/bundle/sha256_release.sum if [[ $DK_SIGN = 1 ]] ; then cat ~/.gnupg/dkorg-gpg-pwd.txt | gpg --batch --yes --passphrase-fd 0 -sabv "$TARGET_PKG_FILE" mv -f $TARGET_PKG_FILE.asc $TARGET_PKG_FILE.sig echo "File : $TARGET_PKG_FILE.sig" >> $TARGET_PKG_FILE.sum echo -n "Size : " >> $TARGET_PKG_FILE.sum du -h "$TARGET_PKG_FILE.sig" | { read first rest ; echo $first ; } >> $TARGET_PKG_FILE.sum echo -n "MD5 sum : " >> $TARGET_PKG_FILE.sum md5 -q "$TARGET_PKG_FILE.sig" >> $TARGET_PKG_FILE.sum echo -n "SHA1 sum : " >> $TARGET_PKG_FILE.sum shasum -a1 "$TARGET_PKG_FILE.sig" | { read first rest ; echo $first ; } >> $TARGET_PKG_FILE.sum echo -n "SHA256 sum : " >> $TARGET_PKG_FILE.sum shasum -a256 "$TARGET_PKG_FILE.sig" | { read first rest ; echo $first ; } >> $TARGET_PKG_FILE.sum # Checksums to post on Phabricator at release time. shasum -a256 "$TARGET_PKG_FILE.sig" >> $BUILDDIR/bundle/sha256_release.sum fi cat $TARGET_PKG_FILE.sum if [[ $DK_UPLOAD = 1 ]] ; then echo -e "---------- Cleanup older bundle Package files from files.kde.org repository \n" ssh $DK_UPLOADURL rm -f $DK_UPLOADDIR*-MacOS-x86-64*.pkg* echo -e "---------- Upload new bundle Package files to files.kde.org repository \n" rsync -r -v --progress -e ssh $BUILDDIR/bundle/$TARGET_INSTALLER $DK_UPLOADURL:$DK_UPLOADDIR scp $BUILDDIR/bundle/$TARGET_INSTALLER.sum $DK_UPLOADURL:$DK_UPLOADDIR if [[ $DK_SIGN = 1 ]] ; then scp $BUILDDIR/bundle/$TARGET_INSTALLER.sig $DK_UPLOADURL:$DK_UPLOADDIR fi else echo -e "\n------------------------------------------------------------------" curl https://download.kde.org/README_UPLOAD echo -e "------------------------------------------------------------------\n" fi ################################################################################################# export PATH=$ORIG_PATH TerminateScript diff --git a/project/bundles/macports/config.sh b/project/bundles/macports/config.sh index f2797a4fc1..40366a608d 100644 --- a/project/bundles/macports/config.sh +++ b/project/bundles/macports/config.sh @@ -1,84 +1,87 @@ #!/bin/bash # Copyright (c) 2013-2020 by Gilles Caulier # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. ######################################################################## # Absolute path where are downloaded all tarballs to compile. DOWNLOAD_DIR="`pwd`/temp.dwnld" # Absolute path where are compiled all tarballs BUILDING_DIR="`pwd`/temp.build" ######################################################################## # Minimum MacOS target for backward binary compatibility # This require to install older MacOS SDKs with Xcode. # See this url to download a older SDK archive : # # https://github.com/phracker/MacOSX-SDKs/releases # # Uncompress the archive to /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ # and adjust the property "MinimumSDKVersion" from /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Info.plist # sudo /usr/libexec/PlistBuddy -c "Set MinimumSDKVersion 10.12" /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Info.plist # # Possible values: # 10.15 : Catalina : : Qt ????, ????, ???? # 10.14 : Mojave : tested : Qt 5.9, 5.10, 5.11, 5.12, 5.13 # 10.13 : High Sierra : tested : Qt 5.9, 5.10, 5.11, 5.12, 5.13 # 10.12 : Sierra : tested : Qt 5.8, 5.9, 5.10, 5.11, 5.12, 5.13 # 10.11 : El Capitan : tested : Qt 5.5, 5.6, 5.7, 5.8, 5.9, 5.10, 5.11 # 10.10 : Yosemite : tested : Qt 5.5, 5.6, 5.7, 5.8, 5.9 # 10.9 : Mavericks : tested : Qt 5.5, 5.6, 5.7, 5.8 # 10.8 : MountainLion : tested : Qt 5.5, 5.6, 5.7 # 10.7 : Lion : untested : Qt 5.5, 5.6 # 10.6 : SnowLeopard : untested : ??? # Older values cannot be set as it do no support x86_64. OSX_MIN_TARGET="10.12" # Directory where not relocable bundle will be built, and where it will be installed by packaging script INSTALL_PREFIX="/opt/digikam" # Macports configuration MP_URL="https://distfiles.macports.org/MacPorts/" MP_BUILDTEMP=~/mptemp # Uncomment this line to force a specific version of Macports to use, else lastest will be used. #MP_VERSION="2.3.3" ######################################################################## # URL to git repository to checkout digiKam source code DK_GITURL="git@invent.kde.org:kde/digikam.git" # digiKam tarball information DK_URL="http://download.kde.org/stable/digikam" # Location to build source code. DK_BUILDTEMP=~/dktemp # digiKam tag version from git. Official tarball do not include extra shared libraries. # The list of tags can be listed with this url: https://quickgit.kde.org/?p=digikam.git&a=tags # If you want to package current implementation from git, use "master" as tag. #DK_VERSION=v6.0.0 DK_VERSION=master #DK_VERSION=development/dplugins # Installer sub version to differentiates newer updates of the installer itself, even if the underlying application hasn’t changed. #DK_EPOCH="-01" # Epoch with time-stamp for pre-release bundle in ISO format DK_EPOCH="-`date "+%Y%m%dT%H%M%S"`" # Installer will include or not digiKam debug symbols DK_DEBUG=1 +# Option to use QtWebEngine instead QtWebkit +DK_QTWEBENGINE=0 + # Sign bundles with GPG. Passphrase must be hosted in ~/.gnupg/dkorg-gpg-pwd.txt DK_SIGN=0 # Upload automatically bundle to files.kde.org (pre-release only). DK_UPLOAD=1 DK_UPLOADURL="digikam@milonia.kde.org" DK_UPLOADDIR="/srv/archives/files/digikam/" diff --git a/project/bundles/mxe/config.sh b/project/bundles/mxe/config.sh index 7b7a7087c3..4662cd3f5e 100644 --- a/project/bundles/mxe/config.sh +++ b/project/bundles/mxe/config.sh @@ -1,77 +1,77 @@ #!/bin/bash # Copyright (c) 2013-2020 by Gilles Caulier # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. ######################################################################## # Absolute path where are downloaded all tarballs to compile. DOWNLOAD_DIR="`pwd`/temp.dwnld" # Absolute path where are compiled all tarballs BUILDING_DIR="`pwd`/temp.build" #------------------------------------------------------------------------------------------- # MXE configuration #------------ # IMPORTANT: Target Windows architecture to build installer. Possible values: 32 or 64 bits. -MXE_ARCHBITS=32 +MXE_ARCHBITS=64 #------------ if [[ $MXE_ARCHBITS == 32 ]]; then # Windows 32 bits shared MXE_BUILD_TARGETS="i686-w64-mingw32.shared" MXE_BUILDROOT="`pwd`/build.win32" elif [[ $MXE_ARCHBITS == 64 ]]; then # Windows 64 bits shared MXE_BUILD_TARGETS="x86_64-w64-mingw32.shared" MXE_BUILDROOT="`pwd`/build.win64" else echo "Unsupported or wrong target Windows architecture: $MXE_ARCHBITS bits." exit -1 fi echo "Target Windows architecture: $MXE_ARCHBITS bits." MXE_GIT_URL="https://github.com/mxe/mxe.git" MXE_GIT_REVISION=master MXE_INSTALL_PREFIX=${MXE_BUILDROOT}/usr/${MXE_BUILD_TARGETS}/ MXE_TOOLCHAIN=${MXE_INSTALL_PREFIX}/share/cmake/mxe-conf.cmake #------------------------------------------------------------------------------------------- # URL to git repository to checkout digiKam source code DK_GITURL="git@invent.kde.org:kde/digikam.git" # digiKam tarball information. DK_URL="http://download.kde.org/stable/digikam" # Location to build source code. DK_BUILDTEMP=~/dktemp # digiKam tag version from git. Official tarball do not include extra shared libraries. # The list of tags can be listed with this url: https://quickgit.kde.org/?p=digikam.git&a=tags # If you want to package current implemntation from git, use "master" as tag. #DK_VERSION=v6.4.0 DK_VERSION=master #DK_VERSION=development/dplugins # Installer sub version to differentiates newer updates of the installer itself, even if the underlying application hasn’t changed. #DK_EPOCH="-01" # Epoch with time-stamp for pre-release bundle in ISO format DK_EPOCH="-`date "+%Y%m%dT%H%M%S"`" # Installer will include or not digiKam debug symbols DK_DEBUG=1 # Sign bundles with GPG. Passphrase must be hosted in ~/.gnupg/dkorg-gpg-pwd.txt DK_SIGN=0 # Upload automatically bundle to files.kde.org (pre-release only). DK_UPLOAD=1 DK_UPLOADURL="digikam@milonia.kde.org" DK_UPLOADDIR="/srv/archives/files/digikam/"