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 }