Krita Source Code Documentation
Loading...
Searching...
No Matches
psd_image_data.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2011 Siddharth Sharma <siddharth.kde@gmail.com>
3 * SPDX-FileCopyrightText: 2021 L. E. Segovia <amy@amyspark.me>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8#include <psd_image_data.h>
9
10#include <QtEndian>
11
12#include <QFile>
13#include <kis_debug.h>
14#include <QVector>
15#include <QBuffer>
16
17#include <KoChannelInfo.h>
18#include <KoColorSpace.h>
19#include <kis_iterator_ng.h>
20#include <kis_paint_device.h>
21
23#include <compression.h>
24#include <psd_pixel_utils.h>
25#include <psd_utils.h>
26
28{
29 m_header = header;
30}
31
35
36bool PSDImageData::read(QIODevice &io, KisPaintDeviceSP dev)
37{
39 quint64 start = io.pos();
42
43 dbgFile << "Reading Image Data Block: compression" << m_compression << "channelsize" << m_channelSize << "number of channels" << m_header->nChannels;
44
45 switch (m_compression) {
46
47 case 0: // Uncompressed
48
49 for (int channel = 0; channel < m_header->nChannels; channel++) {
51 ChannelInfo channelInfo;
52 channelInfo.channelId = channel;
54 channelInfo.channelDataStart = start;
55 channelInfo.channelDataLength = quint64(m_header->width) * m_header->height * m_channelSize;
56 start += channelInfo.channelDataLength;
57 m_channelInfoRecords.append(channelInfo);
58
59 }
60
61 break;
62
63 case 1: // RLE
64 {
65 quint32 rlelength = 0;
66
67 // The start of the actual channel data is _after_ the RLE rowlengths block
68 if (m_header->version == 1) {
69 start += quint64(m_header->nChannels) * m_header->height * 2;
70 }
71 else if (m_header->version == 2) {
72 start += quint64(m_header->nChannels) * m_header->height * 4;
73 }
74
75 for (int channel = 0; channel < m_header->nChannels; channel++) {
77 quint64 sumrlelength = 0;
78 ChannelInfo channelInfo;
79 channelInfo.channelId = channel;
80 channelInfo.channelDataStart = start;
82 for (quint32 row = 0; row < m_header->height; row++ ) {
83 if (m_header->version == 1) {
84 quint16 rlelength16 = 0; // use temporary variable to not cast pointers and not rely on endianness
85 psdread(io, rlelength16);
86 rlelength = rlelength16;
87 }
88 else if (m_header->version == 2) {
89 psdread(io, rlelength);
90 }
91 channelInfo.rleRowLengths.append(rlelength);
92 sumrlelength += rlelength;
93 }
94 channelInfo.channelDataLength = sumrlelength;
95 start += channelInfo.channelDataLength;
96 m_channelInfoRecords.append(channelInfo);
97 }
98
99 break;
100 }
101 case 2: // ZIP without prediction
102 case 3: // ZIP with prediction
103 default:
104 break;
105 }
106
107 if (!m_channelInfoRecords.isEmpty()) {
108 QVector<ChannelInfo*> infoRecords;
109
112
113 for (; it != end; ++it) {
114 infoRecords << &(*it);
115 }
116
117 const QRect imageRect(0, 0, m_header->width, m_header->height);
118
119 try {
123 imageRect,
124 infoRecords);
126 dev->clear();
127 return true;
128 }
129 }
130
131 return true;
132}
133
134bool PSDImageData::write(QIODevice &io, KisPaintDeviceSP dev, bool hasAlpha, psd_compression_type compressionType)
135{
136 psdwrite(io, static_cast<quint16>(compressionType));
137
138 // now write all the channels in display order
139 // fill in the channel chooser, in the display order, but store the pixel index as well.
140 QRect rc(0, 0, m_header->width, m_header->height);
141
142 const int channelSize = m_header->channelDepth / 8;
143 const psd_color_mode colorMode = m_header->colormode;
144
146
147 bool writeAlpha = hasAlpha &&
149
150 const int numChannels =
151 writeAlpha ?
152 dev->colorSpace()->channelCount() :
154
155 for (int i = 0; i < numChannels; i++) {
156 const int rleOffset = io.pos();
157
158 int channelId = writeAlpha && i == numChannels - 1 ? -1 : i;
159
160 writingInfoList <<
161 PsdPixelUtils::ChannelWritingInfo(channelId, -1, rleOffset);
162
163 io.seek(io.pos() + rc.height() * sizeof(quint16));
164 }
165
166 PsdPixelUtils::writePixelDataCommon(io, dev, rc, colorMode, channelSize, false, false, writingInfoList, compressionType);
167 return true;
168}
virtual void clear()
const KoColorSpace * colorSpace() const
virtual quint32 channelCount() const =0
virtual quint32 colorChannelCount() const =0
psd_color_mode colormode
Definition psd_header.h:48
quint16 channelDepth
Definition psd_header.h:47
quint16 version
Definition psd_header.h:43
quint16 nChannels
Definition psd_header.h:44
quint32 height
Definition psd_header.h:45
quint32 width
Definition psd_header.h:46
quint32 m_channelSize
quint64 m_channelDataLength
quint16 m_compression
bool write(QIODevice &io, KisPaintDeviceSP dev, bool hasAlpha, psd_compression_type compressionType)
bool read(QIODevice &io, KisPaintDeviceSP dev)
virtual ~PSDImageData()
PSDHeader * m_header
PSDImageData(PSDHeader *header)
QVector< ChannelInfo > m_channelInfoRecords
QVector< int > m_channelOffsets
#define dbgFile
Definition kis_debug.h:53
void writePixelDataCommon(QIODevice &io, KisPaintDeviceSP dev, const QRect &rc, psd_color_mode colorMode, int channelSize, bool alphaFirst, const bool writeCompressionType, QVector< ChannelWritingInfo > &writingInfoList, psd_compression_type compressionType, psd_byte_order byteOrder)
void readChannels(QIODevice &io, KisPaintDeviceSP device, psd_color_mode colorMode, int channelSize, const QRect &layerRect, QVector< ChannelInfo * > infoRecords, psd_byte_order byteOrder)
psd_compression_type
Definition psd.h:39
@ RLE
Definition psd.h:41
@ Uncompressed
Definition psd.h:40
psd_color_mode
Definition psd.h:50
std::enable_if_t< std::is_arithmetic< T >::value, bool > psdread(QIODevice &io, T &v)
Definition psd_utils.h:397
std::enable_if_t< std::is_arithmetic< T >::value, bool > psdwrite(QIODevice &io, T v)
Definition psd_utils.h:170
QVector< quint32 > rleRowLengths
psd_compression_type compressionType
quint64 channelDataLength
quint64 channelDataStart