File indexing completed on 2024-06-09 04:27:45

0001 /*
0002  *   SPDX-FileCopyrightText: 2011 Siddharth Sharma <siddharth.kde@gmail.com>
0003  *   SPDX-FileCopyrightText: 2021 L. E. Segovia <amy@amyspark.me>
0004  *
0005  *   SPDX-License-Identifier: GPL-2.0-or-later
0006  */
0007 
0008 #include <psd_image_data.h>
0009 
0010 #include <QtEndian>
0011 
0012 #include <QFile>
0013 #include <kis_debug.h>
0014 #include <QVector>
0015 #include <QByteArray>
0016 #include <QBuffer>
0017 
0018 #include <KoChannelInfo.h>
0019 #include <KoColorSpace.h>
0020 #include <KoColorSpaceMaths.h>
0021 #include <KoColorSpaceTraits.h>
0022 #include <kis_iterator_ng.h>
0023 #include <kis_paint_device.h>
0024 
0025 #include <asl/kis_asl_reader_utils.h>
0026 #include <compression.h>
0027 #include <psd_pixel_utils.h>
0028 #include <psd_utils.h>
0029 
0030 PSDImageData::PSDImageData(PSDHeader *header)
0031 {
0032     m_header = header;
0033 }
0034 
0035 PSDImageData::~PSDImageData() {
0036 
0037 }
0038 
0039 bool PSDImageData::read(QIODevice &io, KisPaintDeviceSP dev)
0040 {
0041     psdread(io, m_compression);
0042     quint64 start = io.pos();
0043     m_channelSize = m_header->channelDepth/8;
0044     m_channelDataLength = quint64(m_header->height) * m_header->width * m_channelSize;
0045 
0046     dbgFile << "Reading Image Data Block: compression" << m_compression << "channelsize" << m_channelSize << "number of channels" << m_header->nChannels;
0047 
0048     switch (m_compression) {
0049 
0050     case 0: // Uncompressed
0051 
0052         for (int channel = 0; channel < m_header->nChannels; channel++) {
0053             m_channelOffsets << 0;
0054             ChannelInfo channelInfo;
0055             channelInfo.channelId = channel;
0056             channelInfo.compressionType = psd_compression_type::Uncompressed;
0057             channelInfo.channelDataStart = start;
0058             channelInfo.channelDataLength = quint64(m_header->width) * m_header->height * m_channelSize;
0059             start += channelInfo.channelDataLength;
0060             m_channelInfoRecords.append(channelInfo);
0061 
0062         }
0063 
0064         break;
0065 
0066     case 1: // RLE
0067     {
0068         quint32 rlelength = 0;
0069 
0070         // The start of the actual channel data is _after_ the RLE rowlengths block
0071         if (m_header->version == 1) {
0072             start += quint64(m_header->nChannels) * m_header->height * 2;
0073         }
0074         else if (m_header->version == 2) {
0075             start += quint64(m_header->nChannels) * m_header->height * 4;
0076         }
0077 
0078         for (int channel = 0; channel < m_header->nChannels; channel++) {
0079             m_channelOffsets << 0;
0080             quint64 sumrlelength = 0;
0081             ChannelInfo channelInfo;
0082             channelInfo.channelId = channel;
0083             channelInfo.channelDataStart = start;
0084             channelInfo.compressionType = psd_compression_type::RLE;
0085             for (quint32 row = 0; row < m_header->height; row++ ) {
0086                 if (m_header->version == 1) {
0087                     quint16 rlelength16 = 0; // use temporary variable to not cast pointers and not rely on endianness
0088                     psdread(io, rlelength16);
0089                     rlelength = rlelength16;
0090                 }
0091                 else if (m_header->version == 2) {
0092                     psdread(io, rlelength);
0093                 }
0094                 channelInfo.rleRowLengths.append(rlelength);
0095                 sumrlelength += rlelength;
0096             }
0097             channelInfo.channelDataLength = sumrlelength;
0098             start += channelInfo.channelDataLength;
0099             m_channelInfoRecords.append(channelInfo);
0100         }
0101 
0102         break;
0103     }
0104     case 2: // ZIP without prediction
0105     case 3: // ZIP with prediction
0106     default:
0107         break;
0108     }
0109 
0110     if (!m_channelInfoRecords.isEmpty()) {
0111         QVector<ChannelInfo*> infoRecords;
0112 
0113         QVector<ChannelInfo>::iterator it = m_channelInfoRecords.begin();
0114         QVector<ChannelInfo>::iterator end = m_channelInfoRecords.end();
0115 
0116         for (; it != end; ++it) {
0117             infoRecords << &(*it);
0118         }
0119 
0120         const QRect imageRect(0, 0, m_header->width, m_header->height);
0121 
0122         try {
0123             PsdPixelUtils::readChannels(io, dev,
0124                                         m_header->colormode,
0125                                         m_channelSize,
0126                                         imageRect,
0127                                         infoRecords);
0128         } catch (KisAslReaderUtils::ASLParseException &) {
0129             dev->clear();
0130             return true;
0131         }
0132     }
0133 
0134     return true;
0135 }
0136 
0137 bool PSDImageData::write(QIODevice &io, KisPaintDeviceSP dev, bool hasAlpha, psd_compression_type compressionType)
0138 {
0139     psdwrite(io, static_cast<quint16>(compressionType));
0140 
0141     // now write all the channels in display order
0142     // fill in the channel chooser, in the display order, but store the pixel index as well.
0143     QRect rc(0, 0, m_header->width, m_header->height);
0144 
0145     const int channelSize = m_header->channelDepth / 8;
0146     const psd_color_mode colorMode = m_header->colormode;
0147 
0148     QVector<PsdPixelUtils::ChannelWritingInfo> writingInfoList;
0149 
0150     bool writeAlpha = hasAlpha &&
0151         dev->colorSpace()->channelCount() != dev->colorSpace()->colorChannelCount();
0152 
0153     const int numChannels =
0154         writeAlpha ?
0155         dev->colorSpace()->channelCount() :
0156         dev->colorSpace()->colorChannelCount();
0157 
0158     for (int i = 0; i < numChannels; i++) {
0159         const int rleOffset = io.pos();
0160 
0161         int channelId = writeAlpha && i == numChannels - 1 ? -1 : i;
0162 
0163         writingInfoList <<
0164             PsdPixelUtils::ChannelWritingInfo(channelId, -1, rleOffset);
0165 
0166         io.seek(io.pos() + rc.height() * sizeof(quint16));
0167     }
0168 
0169     PsdPixelUtils::writePixelDataCommon(io, dev, rc, colorMode, channelSize, false, false, writingInfoList, compressionType);
0170     return true;
0171 }