Compare commits

...

10 Commits

Author SHA1 Message Date
bf1c7e8508 GIT_SILENT Upgrade ECM and KF version requirements for 5.108.0 release. 2023-07-01 09:58:24 +00:00
3cb6519dcc jxl: add support for libjxl v0.9, drop support for old 0.6.1 2023-06-27 23:05:15 +00:00
6cbf7529ee Remove qt6 CI builds
The Qt6 builds for kf5 are no longer needed
2023-06-27 18:33:03 +02:00
55227815d5 GIT_SILENT Upgrade ECM and KF version requirements for 5.107.0 release. 2023-06-03 09:46:49 +00:00
64d51ed610 pcx: multiple fixes (2)
- 1-bit writer: checks where is black and use NOT operator only if needed
- Fix images with witdh == 65536(*)
- Checks result of disk writes and reads on all formats

(*) PCX formats support images with with of 65536 but only if the header field bytesPerLine is valid (no overflow). This means that the width 65536 is supported on 1bpp images only.
The previous version of the plugins wrote an image with width of 65536px in the wrong way and it was unable to read it (wrong image returned). I verified that Photoshop and Gimp weren't able to read the image either.

(cherry picked from commit d57ff91f8b)
2023-05-25 23:58:42 +02:00
2ca57c9c59 Avoid unnecessary conversions
(cherry picked from commit edd6adcbac)
2023-05-25 23:58:42 +02:00
f7fd14d418 RGB/SGI writer: fix alpha detection and image limit size
(cherry picked from commit d787c12727)
2023-05-25 23:58:42 +02:00
c9aa1ff629 TGA writer: fix alpha detection and performance improvements
(cherry picked from commit c9fec5e408)
2023-05-25 23:58:42 +02:00
91d3bd5227 pcx: multiple fixes
- Fix wrong RGB channel order if image format is other than (A)RGB32
- Write right resolution
- Set right resolution on image load
- Return false on write error
- Save images with depth greater than 24-bits

(cherry picked from commit e60dfd4968)
2023-05-25 23:58:42 +02:00
bb66367bc8 PCX: Fix reading of the extended palette
The VGA palette starts 769 bytes before the end of the file. There may be PADs between the end of the image and the start of the palette.

BUG: 463951
(cherry picked from commit 14742cb502)
2023-05-25 23:58:42 +02:00
13 changed files with 176 additions and 122 deletions

View File

@ -6,9 +6,5 @@ include:
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux-static.yml
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/android.yml
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/freebsd.yml
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux-qt6.yml
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/android-qt6.yml
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/windows.yml
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/windows-static.yml
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/freebsd-qt6.yml
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/windows-qt6.yml

View File

@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.16)
project(KImageFormats)
include(FeatureSummary)
find_package(ECM 5.106.0 NO_MODULE)
find_package(ECM 5.108.0 NO_MODULE)
set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://commits.kde.org/extra-cmake-modules")
feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES)
@ -65,8 +65,8 @@ add_feature_info(LibHeif LibHeif_FOUND "required for the QImage plugin for HEIF/
option(KIMAGEFORMATS_JXL "Enable plugin for JPEG XL format" ON)
if(KIMAGEFORMATS_JXL)
pkg_check_modules(LibJXL IMPORTED_TARGET libjxl>=0.6.1)
pkg_check_modules(LibJXLThreads IMPORTED_TARGET libjxl_threads>=0.6.1)
pkg_check_modules(LibJXL IMPORTED_TARGET libjxl>=0.7.0)
pkg_check_modules(LibJXLThreads IMPORTED_TARGET libjxl_threads>=0.7.0)
endif()
add_feature_info(LibJXL LibJXL_FOUND "required for the QImage plugin for JPEG XL images")

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

BIN
autotests/read/pcx/mono.pcx Normal file

Binary file not shown.

BIN
autotests/read/pcx/mono.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Binary file not shown.

View File

@ -104,9 +104,6 @@ endif()
if (LibJXL_FOUND AND LibJXLThreads_FOUND)
kimageformats_add_plugin(kimg_jxl SOURCES jxl.cpp)
target_link_libraries(kimg_jxl PkgConfig::LibJXL PkgConfig::LibJXLThreads)
if (LibJXL_VERSION VERSION_GREATER_EQUAL "0.7.0")
target_compile_definitions(kimg_jxl PRIVATE KIMG_JXL_API_VERSION=70)
endif()
if (QT_MAJOR_VERSION STREQUAL "5")
install(FILES jxl.desktop DESTINATION ${KDE_INSTALL_KSERVICESDIR}/qimageioplugins/)

View File

@ -150,9 +150,7 @@ bool QJpegXLHandler::ensureDecoder()
return false;
}
#ifdef KIMG_JXL_API_VERSION
JxlDecoderCloseInput(m_decoder);
#endif
JxlDecoderStatus status = JxlDecoderSubscribeEvents(m_decoder, JXL_DEC_BASIC_INFO | JXL_DEC_COLOR_ENCODING | JXL_DEC_FRAME);
if (status == JXL_DEC_ERROR) {
@ -269,18 +267,31 @@ bool QJpegXLHandler::countALLFrames()
}
}
status = JxlDecoderGetColorAsEncodedProfile(m_decoder, &m_input_pixel_format, JXL_COLOR_PROFILE_TARGET_DATA, &color_encoding);
status = JxlDecoderGetColorAsEncodedProfile(m_decoder,
#if JPEGXL_NUMERIC_VERSION < JPEGXL_COMPUTE_NUMERIC_VERSION(0, 9, 0)
&m_input_pixel_format,
#endif
JXL_COLOR_PROFILE_TARGET_DATA,
&color_encoding);
if (status == JXL_DEC_SUCCESS && color_encoding.color_space == JXL_COLOR_SPACE_RGB && color_encoding.white_point == JXL_WHITE_POINT_D65
&& color_encoding.primaries == JXL_PRIMARIES_SRGB && color_encoding.transfer_function == JXL_TRANSFER_FUNCTION_SRGB) {
m_colorspace = QColorSpace(QColorSpace::SRgb);
} else {
size_t icc_size = 0;
if (JxlDecoderGetICCProfileSize(m_decoder, &m_input_pixel_format, JXL_COLOR_PROFILE_TARGET_DATA, &icc_size) == JXL_DEC_SUCCESS) {
if (JxlDecoderGetICCProfileSize(m_decoder,
#if JPEGXL_NUMERIC_VERSION < JPEGXL_COMPUTE_NUMERIC_VERSION(0, 9, 0)
&m_input_pixel_format,
#endif
JXL_COLOR_PROFILE_TARGET_DATA,
&icc_size)
== JXL_DEC_SUCCESS) {
if (icc_size > 0) {
QByteArray icc_data(icc_size, 0);
if (JxlDecoderGetColorAsICCProfile(m_decoder,
#if JPEGXL_NUMERIC_VERSION < JPEGXL_COMPUTE_NUMERIC_VERSION(0, 9, 0)
&m_input_pixel_format,
#endif
JXL_COLOR_PROFILE_TARGET_DATA,
reinterpret_cast<uint8_t *>(icc_data.data()),
icc_data.size())
@ -534,9 +545,7 @@ bool QJpegXLHandler::write(const QImage &image)
if (save_depth == 16 && (image.hasAlphaChannel() || output_info.uses_original_profile)) {
output_info.have_container = JXL_TRUE;
JxlEncoderUseContainer(encoder, JXL_TRUE);
#ifdef KIMG_JXL_API_VERSION
JxlEncoderSetCodestreamLevel(encoder, 10);
#endif
}
void *runner = nullptr;
@ -650,19 +659,11 @@ bool QJpegXLHandler::write(const QImage &image)
}
}
#ifdef KIMG_JXL_API_VERSION
JxlEncoderFrameSettings *encoder_options = JxlEncoderFrameSettingsCreate(encoder, nullptr);
JxlEncoderSetFrameDistance(encoder_options, (100.0f - m_quality) / 10.0f);
JxlEncoderSetFrameLossless(encoder_options, (m_quality == 100) ? JXL_TRUE : JXL_FALSE);
#else
JxlEncoderOptions *encoder_options = JxlEncoderOptionsCreate(encoder, nullptr);
JxlEncoderOptionsSetDistance(encoder_options, (100.0f - m_quality) / 10.0f);
JxlEncoderOptionsSetLossless(encoder_options, (m_quality == 100) ? JXL_TRUE : JXL_FALSE);
#endif
if (image.hasAlphaChannel() || ((save_depth == 8) && (xsize % 4 == 0))) {
status = JxlEncoderAddImageFrame(encoder_options, &pixel_format, static_cast<const void *>(tmpimage.constBits()), buffer_size);
@ -957,9 +958,7 @@ bool QJpegXLHandler::rewind()
return false;
}
#ifdef KIMG_JXL_API_VERSION
JxlDecoderCloseInput(m_decoder);
#endif
if (m_basicinfo.uses_original_profile) {
if (JxlDecoderSubscribeEvents(m_decoder, JXL_DEC_FULL_IMAGE) != JXL_DEC_SUCCESS) {

View File

@ -230,7 +230,7 @@ PCXHEADER::PCXHEADER()
s >> *this;
}
static void readLine(QDataStream &s, QByteArray &buf, const PCXHEADER &header)
static bool readLine(QDataStream &s, QByteArray &buf, const PCXHEADER &header)
{
quint32 i = 0;
quint32 size = buf.size();
@ -257,9 +257,11 @@ static void readLine(QDataStream &s, QByteArray &buf, const PCXHEADER &header)
buf[i++] = byte;
}
}
return (s.status() == QDataStream::Ok);
}
static void readImage1(QImage &img, QDataStream &s, const PCXHEADER &header)
static bool readImage1(QImage &img, QDataStream &s, const PCXHEADER &header)
{
QByteArray buf(header.BytesPerLine, 0);
@ -268,16 +270,18 @@ static void readImage1(QImage &img, QDataStream &s, const PCXHEADER &header)
if (img.isNull()) {
qWarning() << "Failed to allocate image, invalid dimensions?" << QSize(header.width(), header.height());
return;
return false;
}
for (int y = 0; y < header.height(); ++y) {
if (s.atEnd()) {
img = QImage();
return;
return false;
}
if (!readLine(s, buf, header)) {
return false;
}
readLine(s, buf, header);
uchar *p = img.scanLine(y);
unsigned int bpl = qMin((quint16)((header.width() + 7) / 8), header.BytesPerLine);
for (unsigned int x = 0; x < bpl; ++x) {
@ -288,9 +292,11 @@ static void readImage1(QImage &img, QDataStream &s, const PCXHEADER &header)
// Set the color palette
img.setColor(0, qRgb(0, 0, 0));
img.setColor(1, qRgb(255, 255, 255));
return true;
}
static void readImage4(QImage &img, QDataStream &s, const PCXHEADER &header)
static bool readImage4(QImage &img, QDataStream &s, const PCXHEADER &header)
{
QByteArray buf(header.BytesPerLine * 4, 0);
QByteArray pixbuf(header.width(), 0);
@ -299,17 +305,18 @@ static void readImage4(QImage &img, QDataStream &s, const PCXHEADER &header)
img.setColorCount(16);
if (img.isNull()) {
qWarning() << "Failed to allocate image, invalid dimensions?" << QSize(header.width(), header.height());
return;
return false;
}
for (int y = 0; y < header.height(); ++y) {
if (s.atEnd()) {
img = QImage();
return;
return false;
}
pixbuf.fill(0);
readLine(s, buf, header);
if (!readLine(s, buf, header)) {
return false;
}
for (int i = 0; i < 4; i++) {
quint32 offset = i * header.BytesPerLine;
@ -333,9 +340,11 @@ static void readImage4(QImage &img, QDataStream &s, const PCXHEADER &header)
for (int i = 0; i < 16; ++i) {
img.setColor(i, header.ColorMap.color(i));
}
return true;
}
static void readImage8(QImage &img, QDataStream &s, const PCXHEADER &header)
static bool readImage8(QImage &img, QDataStream &s, const PCXHEADER &header)
{
QByteArray buf(header.BytesPerLine, 0);
@ -344,21 +353,21 @@ static void readImage8(QImage &img, QDataStream &s, const PCXHEADER &header)
if (img.isNull()) {
qWarning() << "Failed to allocate image, invalid dimensions?" << QSize(header.width(), header.height());
return;
return false;
}
for (int y = 0; y < header.height(); ++y) {
if (s.atEnd()) {
img = QImage();
return;
return false;
}
readLine(s, buf, header);
if (!readLine(s, buf, header)) {
return false;
}
uchar *p = img.scanLine(y);
if (!p) {
return;
return false;
}
unsigned int bpl = qMin(header.BytesPerLine, (quint16)header.width());
@ -367,10 +376,21 @@ static void readImage8(QImage &img, QDataStream &s, const PCXHEADER &header)
}
}
quint8 flag;
s >> flag;
// qDebug() << "Palette Flag: " << flag;
// by specification, the extended palette starts at file.size() - 769
quint8 flag = 0;
if (auto device = s.device()) {
if (device->isSequential()) {
while (flag != 12 && s.status() == QDataStream::Ok) {
s >> flag;
}
}
else {
device->seek(device->size() - 769);
s >> flag;
}
}
// qDebug() << "Palette Flag: " << flag;
if (flag == 12 && (header.Version == 5 || header.Version == 2)) {
// Read the palette
quint8 r;
@ -381,9 +401,11 @@ static void readImage8(QImage &img, QDataStream &s, const PCXHEADER &header)
img.setColor(i, qRgb(r, g, b));
}
}
return (s.status() == QDataStream::Ok);
}
static void readImage24(QImage &img, QDataStream &s, const PCXHEADER &header)
static bool readImage24(QImage &img, QDataStream &s, const PCXHEADER &header)
{
QByteArray r_buf(header.BytesPerLine, 0);
QByteArray g_buf(header.BytesPerLine, 0);
@ -393,27 +415,34 @@ static void readImage24(QImage &img, QDataStream &s, const PCXHEADER &header)
if (img.isNull()) {
qWarning() << "Failed to allocate image, invalid dimensions?" << QSize(header.width(), header.height());
return;
return false;
}
for (int y = 0; y < header.height(); ++y) {
if (s.atEnd()) {
img = QImage();
return;
return false;
}
readLine(s, r_buf, header);
readLine(s, g_buf, header);
readLine(s, b_buf, header);
if (!readLine(s, r_buf, header)) {
return false;
}
if (!readLine(s, g_buf, header)) {
return false;
}
if (!readLine(s, b_buf, header)) {
return false;
}
uint *p = (uint *)img.scanLine(y);
for (int x = 0; x < header.width(); ++x) {
p[x] = qRgb(r_buf[x], g_buf[x], b_buf[x]);
}
}
return true;
}
static void writeLine(QDataStream &s, QByteArray &buf)
static bool writeLine(QDataStream &s, QByteArray &buf)
{
quint32 i = 0;
quint32 size = buf.size();
@ -439,15 +468,26 @@ static void writeLine(QDataStream &s, QByteArray &buf)
s << data;
}
return (s.status() == QDataStream::Ok);
}
static void writeImage1(QImage &img, QDataStream &s, PCXHEADER &header)
static bool writeImage1(QImage &img, QDataStream &s, PCXHEADER &header)
{
img = img.convertToFormat(QImage::Format_Mono);
if (img.format() != QImage::Format_Mono) {
img = img.convertToFormat(QImage::Format_Mono);
}
if (img.isNull() || img.colorCount() < 1) {
return false;
}
auto rgb = img.color(0);
auto minIsBlack = (qRed(rgb) + qGreen(rgb) + qBlue(rgb)) / 3 < 127;
header.Bpp = 1;
header.NPlanes = 1;
header.BytesPerLine = img.bytesPerLine();
if (header.BytesPerLine == 0) {
return false;
}
s << header;
@ -458,18 +498,24 @@ static void writeImage1(QImage &img, QDataStream &s, PCXHEADER &header)
// Invert as QImage uses reverse palette for monochrome images?
for (int i = 0; i < header.BytesPerLine; ++i) {
buf[i] = ~p[i];
buf[i] = minIsBlack ? p[i] : ~p[i];
}
writeLine(s, buf);
if (!writeLine(s, buf)) {
return false;
}
}
return true;
}
static void writeImage4(QImage &img, QDataStream &s, PCXHEADER &header)
static bool writeImage4(QImage &img, QDataStream &s, PCXHEADER &header)
{
header.Bpp = 1;
header.NPlanes = 4;
header.BytesPerLine = header.width() / 8;
if (header.BytesPerLine == 0) {
return false;
}
for (int i = 0; i < 16; ++i) {
header.ColorMap.setColor(i, img.color(i));
@ -499,16 +545,22 @@ static void writeImage4(QImage &img, QDataStream &s, PCXHEADER &header)
}
for (int i = 0; i < 4; ++i) {
writeLine(s, buf[i]);
if (!writeLine(s, buf[i])) {
return false;
}
}
}
return true;
}
static void writeImage8(QImage &img, QDataStream &s, PCXHEADER &header)
static bool writeImage8(QImage &img, QDataStream &s, PCXHEADER &header)
{
header.Bpp = 8;
header.NPlanes = 1;
header.BytesPerLine = img.bytesPerLine();
if (header.BytesPerLine == 0) {
return false;
}
s << header;
@ -521,7 +573,9 @@ static void writeImage8(QImage &img, QDataStream &s, PCXHEADER &header)
buf[i] = p[i];
}
writeLine(s, buf);
if (!writeLine(s, buf)) {
return false;
}
}
// Write palette flag
@ -532,13 +586,25 @@ static void writeImage8(QImage &img, QDataStream &s, PCXHEADER &header)
for (int i = 0; i < 256; ++i) {
s << RGB::from(img.color(i));
}
return (s.status() == QDataStream::Ok);
}
static void writeImage24(QImage &img, QDataStream &s, PCXHEADER &header)
static bool writeImage24(QImage &img, QDataStream &s, PCXHEADER &header)
{
header.Bpp = 8;
header.NPlanes = 3;
header.BytesPerLine = header.width();
if (header.BytesPerLine == 0) {
return false;
}
if (img.format() != QImage::Format_ARGB32 && img.format() != QImage::Format_RGB32) {
img = img.convertToFormat(QImage::Format_RGB32);
}
if (img.isNull()) {
return false;
}
s << header;
@ -547,7 +613,7 @@ static void writeImage24(QImage &img, QDataStream &s, PCXHEADER &header)
QByteArray b_buf(header.width(), 0);
for (int y = 0; y < header.height(); ++y) {
uint *p = (uint *)img.scanLine(y);
auto p = (QRgb*)img.scanLine(y);
for (int x = 0; x < header.width(); ++x) {
QRgb rgb = *p++;
@ -556,10 +622,18 @@ static void writeImage24(QImage &img, QDataStream &s, PCXHEADER &header)
b_buf[x] = qBlue(rgb);
}
writeLine(s, r_buf);
writeLine(s, g_buf);
writeLine(s, b_buf);
if (!writeLine(s, r_buf)) {
return false;
}
if (!writeLine(s, g_buf)) {
return false;
}
if (!writeLine(s, b_buf)) {
return false;
}
}
return true;
}
PCXHandler::PCXHandler()
@ -588,46 +662,30 @@ bool PCXHandler::read(QImage *outImage)
s >> header;
if (header.Manufacturer != 10 || s.atEnd()) {
if (header.Manufacturer != 10 || header.BytesPerLine == 0 || s.atEnd()) {
return false;
}
// int w = header.width();
// int h = header.height();
// qDebug() << "Manufacturer: " << header.Manufacturer;
// qDebug() << "Version: " << header.Version;
// qDebug() << "Encoding: " << header.Encoding;
// qDebug() << "Bpp: " << header.Bpp;
// qDebug() << "Width: " << w;
// qDebug() << "Height: " << h;
// qDebug() << "Window: " << header.XMin << "," << header.XMax << ","
// << header.YMin << "," << header.YMax << endl;
// qDebug() << "BytesPerLine: " << header.BytesPerLine;
// qDebug() << "NPlanes: " << header.NPlanes;
auto ok = false;
QImage img;
if (header.Bpp == 1 && header.NPlanes == 1) {
readImage1(img, s, header);
ok = readImage1(img, s, header);
} else if (header.Bpp == 1 && header.NPlanes == 4) {
readImage4(img, s, header);
ok = readImage4(img, s, header);
} else if (header.Bpp == 8 && header.NPlanes == 1) {
readImage8(img, s, header);
ok = readImage8(img, s, header);
} else if (header.Bpp == 8 && header.NPlanes == 3) {
readImage24(img, s, header);
ok = readImage24(img, s, header);
}
// qDebug() << "Image Bytes: " << img.numBytes();
// qDebug() << "Image Bytes Per Line: " << img.bytesPerLine();
// qDebug() << "Image Depth: " << img.depth();
if (!img.isNull()) {
*outImage = img;
return true;
} else {
if (img.isNull() || !ok) {
return false;
}
img.setDotsPerMeterX(qRound(header.HDpi / 25.4 * 1000));
img.setDotsPerMeterY(qRound(header.YDpi / 25.4 * 1000));
*outImage = img;
return true;
}
bool PCXHandler::write(const QImage &image)
@ -644,12 +702,6 @@ bool PCXHandler::write(const QImage &image)
return false;
}
// qDebug() << "Width: " << w;
// qDebug() << "Height: " << h;
// qDebug() << "Depth: " << img.depth();
// qDebug() << "BytesPerLine: " << img.bytesPerLine();
// qDebug() << "Color Count: " << img.colorCount();
PCXHEADER header;
header.Manufacturer = 10;
@ -659,22 +711,23 @@ bool PCXHandler::write(const QImage &image)
header.YMin = 0;
header.XMax = w - 1;
header.YMax = h - 1;
header.HDpi = 300;
header.YDpi = 300;
header.HDpi = qRound(image.dotsPerMeterX() * 25.4 / 1000);
header.YDpi = qRound(image.dotsPerMeterY() * 25.4 / 1000);
header.Reserved = 0;
header.PaletteInfo = 1;
auto ok = false;
if (img.depth() == 1) {
writeImage1(img, s, header);
ok = writeImage1(img, s, header);
} else if (img.depth() == 8 && img.colorCount() <= 16) {
writeImage4(img, s, header);
ok = writeImage4(img, s, header);
} else if (img.depth() == 8) {
writeImage8(img, s, header);
} else if (img.depth() == 32) {
writeImage24(img, s, header);
ok = writeImage8(img, s, header);
} else if (img.depth() >= 24) {
ok = writeImage24(img, s, header);
}
return true;
return ok;
}
bool PCXHandler::canRead(QIODevice *device)

View File

@ -672,11 +672,16 @@ bool SGIImage::writeImage(const QImage &image)
_dim = 3, _zsize = 3;
}
if (img.format() == QImage::Format_ARGB32) {
auto hasAlpha = img.hasAlphaChannel();
if (hasAlpha) {
_dim = 3, _zsize++;
}
img = img.convertToFormat(QImage::Format_RGB32);
if (hasAlpha && img.format() != QImage::Format_ARGB32) {
img = img.convertToFormat(QImage::Format_ARGB32);
} else if (!hasAlpha && img.format() != QImage::Format_RGB32) {
img = img.convertToFormat(QImage::Format_RGB32);
}
if (img.isNull()) {
// qDebug() << "can't convert image to depth 32";
return false;
@ -685,7 +690,7 @@ bool SGIImage::writeImage(const QImage &image)
const int w = img.width();
const int h = img.height();
if (w > 65536 || h > 65536) {
if (w > 65535 || h > 65535) {
return false;
}
@ -712,12 +717,6 @@ bool SGIImage::writeImage(const QImage &image)
rle_size += _rlevector[i]->size();
}
// qDebug() << "minimum intensity: " << _pixmin;
// qDebug() << "maximum intensity: " << _pixmax;
// qDebug() << "saved scanlines: " << _numrows - _rlemap.size();
// qDebug() << "total savings: " << (verbatim_size - rle_size) << " bytes";
// qDebug() << "compression: " << (rle_size * 100.0 / verbatim_size) << '%';
if (verbatim_size <= rle_size) {
writeVerbatim(img);
} else {

View File

@ -428,8 +428,17 @@ bool TGAHandler::write(const QImage &image)
QDataStream s(device());
s.setByteOrder(QDataStream::LittleEndian);
const QImage &img = image;
const bool hasAlpha = (img.format() == QImage::Format_ARGB32);
QImage img(image);
const bool hasAlpha = img.hasAlphaChannel();
if (hasAlpha && img.format() != QImage::Format_ARGB32) {
img = img.convertToFormat(QImage::Format_ARGB32);
} else if (!hasAlpha && img.format() != QImage::Format_RGB32) {
img = img.convertToFormat(QImage::Format_RGB32);
}
if (img.isNull()) {
qDebug() << "TGAHandler::write: image conversion to 32 bits failed!";
return false;
}
static constexpr quint8 originTopLeft = TGA_ORIGIN_UPPER + TGA_ORIGIN_LEFT; // 0x20
static constexpr quint8 alphaChannel8Bits = 0x08;
@ -444,8 +453,9 @@ bool TGAHandler::write(const QImage &image)
s << quint8(hasAlpha ? originTopLeft + alphaChannel8Bits : originTopLeft); // top left image (0x20) + 8 bit alpha (0x8)
for (int y = 0; y < img.height(); y++) {
auto ptr = reinterpret_cast<QRgb *>(img.scanLine(y));
for (int x = 0; x < img.width(); x++) {
const QRgb color = img.pixel(x, y);
auto color = *(ptr + x);
s << quint8(qBlue(color));
s << quint8(qGreen(color));
s << quint8(qRed(color));