mirror of
https://invent.kde.org/frameworks/kimageformats.git
synced 2025-06-03 17:08:08 -04:00
Add support for RLE-compressed, 16 bits per channel PSD files.
This commit is contained in:
parent
b742cb7cc7
commit
5825c83235
@ -165,6 +165,14 @@ static bool LoadPSD(QDataStream &stream, const PSDHeader &header, QImage &img)
|
|||||||
// Ignore the other channels.
|
// Ignore the other channels.
|
||||||
channel_num = 4;
|
channel_num = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (compression == 1 && header.depth == 16) {
|
||||||
|
fmt = QImage::Format_RGBX64;
|
||||||
|
if (channel_num >= 4) {
|
||||||
|
fmt = QImage::Format_RGBA64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
img = QImage(header.width, header.height, fmt);
|
img = QImage(header.width, header.height, fmt);
|
||||||
if (img.isNull()) {
|
if (img.isNull()) {
|
||||||
qWarning() << "Failed to allocate image, invalid dimensions?" << QSize(header.width, header.height);
|
qWarning() << "Failed to allocate image, invalid dimensions?" << QSize(header.width, header.height);
|
||||||
@ -193,11 +201,15 @@ static bool LoadPSD(QDataStream &stream, const PSDHeader &header, QImage &img)
|
|||||||
updateAlpha
|
updateAlpha
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef QRgba64(*channelUpdater16)(QRgba64, quint16);
|
||||||
|
static const channelUpdater16 updaters64[4] = {
|
||||||
|
[](QRgba64 oldPixel, quint16 redPixel) {return qRgba64((oldPixel & ~(0xFFFFull << 0)) | (quint64( redPixel) << 0));},
|
||||||
|
[](QRgba64 oldPixel, quint16 greenPixel){return qRgba64((oldPixel & ~(0xFFFFull << 16)) | (quint64(greenPixel) << 16));},
|
||||||
|
[](QRgba64 oldPixel, quint16 bluePixel) {return qRgba64((oldPixel & ~(0xFFFFull << 32)) | (quint64( bluePixel) << 32));},
|
||||||
|
[](QRgba64 oldPixel, quint16 alphaPixel){return qRgba64((oldPixel & ~(0xFFFFull << 48)) | (quint64(alphaPixel) << 48));}
|
||||||
|
};
|
||||||
|
|
||||||
if (compression) {
|
if (compression) {
|
||||||
if (header.depth != 8) {
|
|
||||||
qWarning() << "RLE compressed PSD image with depth != 8 is not supported.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Skip row lengths.
|
// Skip row lengths.
|
||||||
int skip_count = header.height * header.channel_count * sizeof(quint16);
|
int skip_count = header.height * header.channel_count * sizeof(quint16);
|
||||||
if (stream.skipRawData(skip_count) != skip_count) {
|
if (stream.skipRawData(skip_count) != skip_count) {
|
||||||
@ -205,9 +217,18 @@ static bool LoadPSD(QDataStream &stream, const PSDHeader &header, QImage &img)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned short channel = 0; channel < channel_num; channel++) {
|
for (unsigned short channel = 0; channel < channel_num; channel++) {
|
||||||
bool success = decodeRLEData(RLEVariant::PackBits, stream,
|
bool success = false;
|
||||||
|
if (header.depth == 8) {
|
||||||
|
success = decodeRLEData(RLEVariant::PackBits, stream,
|
||||||
image_data, pixel_count,
|
image_data, pixel_count,
|
||||||
&readPixel_u8, updaters[channel]);
|
&readPixel_u8, updaters[channel]);
|
||||||
|
} else if (header.depth == 16) {
|
||||||
|
QRgba64 *image_data = reinterpret_cast<QRgba64*>(img.bits());
|
||||||
|
success = decodeRLEData(RLEVariant::PackBits16, stream,
|
||||||
|
image_data, pixel_count * 2,
|
||||||
|
&readPixel_u8, updaters64[channel]);
|
||||||
|
}
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
qDebug() << "decodeRLEData on channel" << channel << "failed";
|
qDebug() << "decodeRLEData on channel" << channel << "failed";
|
||||||
return false;
|
return false;
|
||||||
|
@ -24,6 +24,11 @@ enum class RLEVariant {
|
|||||||
* of size 2, 130 of size 3, up to 255 of size 128.
|
* of size 2, 130 of size 3, up to 255 of size 128.
|
||||||
*/
|
*/
|
||||||
PackBits,
|
PackBits,
|
||||||
|
/**
|
||||||
|
* Same as PackBits, but treat unpacked data as
|
||||||
|
* 16-bit integers.
|
||||||
|
*/
|
||||||
|
PackBits16,
|
||||||
/**
|
/**
|
||||||
* PIC-style RLE
|
* PIC-style RLE
|
||||||
*
|
*
|
||||||
@ -67,6 +72,8 @@ static inline bool decodeRLEData(RLEVariant variant,
|
|||||||
Func2 updateItem)
|
Func2 updateItem)
|
||||||
{
|
{
|
||||||
unsigned offset = 0; // in dest
|
unsigned offset = 0; // in dest
|
||||||
|
bool is_msb = true; // only used for 16-bit PackBits, data is big-endian
|
||||||
|
quint16 temp_data = 0;
|
||||||
while (offset < length) {
|
while (offset < length) {
|
||||||
unsigned remaining = length - offset;
|
unsigned remaining = length - offset;
|
||||||
quint8 count1;
|
quint8 count1;
|
||||||
@ -85,7 +92,7 @@ static inline bool decodeRLEData(RLEVariant variant,
|
|||||||
// 2 to 128 repetitions
|
// 2 to 128 repetitions
|
||||||
length = count1 - 127u;
|
length = count1 - 127u;
|
||||||
}
|
}
|
||||||
} else if (variant == RLEVariant::PackBits) {
|
} else if (variant == RLEVariant::PackBits || variant == RLEVariant::PackBits16) {
|
||||||
if (count1 == 128u) {
|
if (count1 == 128u) {
|
||||||
// Ignore value 128
|
// Ignore value 128
|
||||||
continue;
|
continue;
|
||||||
@ -102,7 +109,18 @@ static inline bool decodeRLEData(RLEVariant variant,
|
|||||||
}
|
}
|
||||||
auto datum = readData(stream);
|
auto datum = readData(stream);
|
||||||
for (unsigned i = offset; i < offset + length; ++i) {
|
for (unsigned i = offset; i < offset + length; ++i) {
|
||||||
dest[i] = updateItem(dest[i], datum);
|
if (variant == RLEVariant::PackBits16) {
|
||||||
|
if (is_msb) {
|
||||||
|
temp_data = datum << 8;
|
||||||
|
is_msb = false;
|
||||||
|
} else {
|
||||||
|
temp_data |= datum;
|
||||||
|
dest[i >> 1] = updateItem(dest[i >> 1], temp_data);
|
||||||
|
is_msb = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dest[i] = updateItem(dest[i], datum);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
offset += length;
|
offset += length;
|
||||||
} else {
|
} else {
|
||||||
@ -114,7 +132,18 @@ static inline bool decodeRLEData(RLEVariant variant,
|
|||||||
}
|
}
|
||||||
for (unsigned i = offset; i < offset + length; ++i) {
|
for (unsigned i = offset; i < offset + length; ++i) {
|
||||||
auto datum = readData(stream);
|
auto datum = readData(stream);
|
||||||
dest[i] = updateItem(dest[i], datum);
|
if (variant == RLEVariant::PackBits16) {
|
||||||
|
if (is_msb) {
|
||||||
|
temp_data = datum << 8;
|
||||||
|
is_msb = false;
|
||||||
|
} else {
|
||||||
|
temp_data |= datum;
|
||||||
|
dest[i >> 1] = updateItem(dest[i >> 1], temp_data);
|
||||||
|
is_msb = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dest[i] = updateItem(dest[i], datum);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
offset += length;
|
offset += length;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user