File indexing completed on 2024-05-12 15:56:11

0001 /*
0002  *  SPDX-FileCopyrightText: 2010 Cyrille Berger <cberger@cberger.net>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_png_brush.h"
0008 
0009 #include <QDomElement>
0010 #include <QFileInfo>
0011 #include <QImageReader>
0012 #include <QByteArray>
0013 #include <QBuffer>
0014 #include <QPainter>
0015 
0016 #include <kis_dom_utils.h>
0017 
0018 KisPngBrush::KisPngBrush(const QString& filename)
0019     : KisColorfulBrush(filename)
0020 {
0021     setBrushType(INVALID);
0022     setSpacing(0.25);
0023 }
0024 
0025 KisPngBrush::KisPngBrush(const KisPngBrush &rhs)
0026     : KisColorfulBrush(rhs)
0027 {
0028 }
0029 
0030 KoResourceSP KisPngBrush::clone() const
0031 {
0032     return KoResourceSP(new KisPngBrush(*this));
0033 }
0034 
0035 bool KisPngBrush::loadFromDevice(QIODevice *dev, KisResourcesInterfaceSP resourcesInterface)
0036 {
0037     Q_UNUSED(resourcesInterface);
0038 
0039     // Workaround for some OS (Debian, Ubuntu), where loading directly from the QIODevice
0040     // fails with "libpng error: IDAT: CRC error"
0041     QByteArray data = dev->readAll();
0042     QBuffer buf(&data);
0043     buf.open(QIODevice::ReadOnly);
0044     QImageReader reader(&buf, "PNG");
0045 
0046     if (!reader.canRead()) {
0047         dbgKrita << "Could not read brush" << filename() << ". Error:" << reader.errorString();
0048         setValid(false);
0049         return false;
0050     }
0051 
0052     if (reader.textKeys().contains("brush_spacing")) {
0053         setSpacing(KisDomUtils::toDouble(reader.text("brush_spacing")));
0054     }
0055 
0056     if (reader.textKeys().contains("brush_name")) {
0057         setName(reader.text("brush_name"));
0058     }
0059     else {
0060         QFileInfo info(filename());
0061         setName(info.completeBaseName());
0062     }
0063 
0064     QImage image = reader.read();
0065 
0066     if (image.isNull()) {
0067         dbgKrita << "Could not create image for" << filename() << ". Error:" << reader.errorString();
0068         setValid(false);
0069         return false;
0070     }
0071 
0072     setValid(true);
0073 
0074     bool hasAlpha = false;
0075     for (int y = 0; y < image.height(); y++) {
0076         for (int x = 0; x < image.width(); x++) {
0077             if (qAlpha(image.pixel(x, y)) != 255) {
0078                 hasAlpha = true;
0079                 break;
0080             }
0081         }
0082     }
0083 
0084     const bool isAllGray = image.allGray();
0085 
0086     if (isAllGray && !hasAlpha) {
0087         // Make sure brush tips all have a white background
0088         // NOTE: drawing it over white background can probably be skipped now...
0089         //       Any images with an Alpha channel should be loaded as RGBA so
0090         //       they can have the lightness and gradient options available
0091         QImage base(image.size(), image.format());
0092         if ((int)base.format() < (int)QImage::Format_RGB32) {
0093             base = base.convertToFormat(QImage::Format_ARGB32);
0094         }
0095         QPainter gc(&base);
0096         gc.fillRect(base.rect(), Qt::white);
0097         gc.drawImage(0, 0, image);
0098         gc.end();
0099         QImage converted = base.convertToFormat(QImage::Format_Grayscale8);
0100         setBrushTipImage(converted);
0101         setBrushType(MASK);
0102         setBrushApplication(ALPHAMASK);
0103         setHasColorAndTransparency(false);
0104     }
0105     else {
0106         if ((int)image.format() < (int)QImage::Format_RGB32) {
0107             image = image.convertToFormat(QImage::Format_ARGB32);
0108         }
0109 
0110         setBrushTipImage(image);
0111         setBrushType(IMAGE);
0112         setBrushApplication(isAllGray ? ALPHAMASK : LIGHTNESSMAP);
0113         setHasColorAndTransparency(!isAllGray);
0114     }
0115 
0116     setWidth(brushTipImage().width());
0117     setHeight(brushTipImage().height());
0118 
0119     return valid();
0120 }
0121 
0122 bool KisPngBrush::saveToDevice(QIODevice *dev) const
0123 {
0124     return brushTipImage().save(dev, "PNG");
0125 }
0126 
0127 QString KisPngBrush::defaultFileExtension() const
0128 {
0129     return QString(".png");
0130 }
0131 
0132 void KisPngBrush::toXML(QDomDocument& d, QDomElement& e) const
0133 {
0134     predefinedBrushToXML("png_brush", e);
0135     KisColorfulBrush::toXML(d, e);
0136 }