mirror of
https://invent.kde.org/frameworks/kimageformats.git
synced 2025-07-15 11:14:18 -04:00
Compare commits
36 Commits
Author | SHA1 | Date | |
---|---|---|---|
e9b52df1d3 | |||
dd98b2b717 | |||
dd76f41c38 | |||
940ca2b081 | |||
b14ef357e5 | |||
bf5502403e | |||
5c4c05257c | |||
7afaacb093 | |||
68bb1a0ee7 | |||
9a9ac6e8fe | |||
4bf2894bde | |||
40353da5db | |||
068e711847 | |||
90ba55d982 | |||
e3603bc748 | |||
75ef81a109 | |||
bff22e2a76 | |||
0196444a99 | |||
90f340df24 | |||
1a9b5d6cb6 | |||
96b1d7e7bc | |||
bcce48012e | |||
0db5c89c5f | |||
6fea48c4ee | |||
645daec1ef | |||
aaa285a3b9 | |||
35e64c44d8 | |||
26b796f67d | |||
4692a34a1c | |||
c0656c5181 | |||
83d1ca90d9 | |||
fd4fb6f596 | |||
a24ece396a | |||
9fc6967f4f | |||
bd704045e6 | |||
af7a89fea7 |
21
.gitignore
vendored
Normal file
21
.gitignore
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
# Ignore the following files
|
||||
*~
|
||||
*.[oa]
|
||||
*.diff
|
||||
*.kate-swp
|
||||
*.kdev4
|
||||
.kdev_include_paths
|
||||
*.kdevelop.pcs
|
||||
*.moc
|
||||
*.moc.cpp
|
||||
*.orig
|
||||
*.user
|
||||
.*.swp
|
||||
.swp.*
|
||||
Doxyfile
|
||||
Makefile
|
||||
avail
|
||||
random_seed
|
||||
/build*/
|
||||
CMakeLists.txt.user*
|
||||
*.unc-backup*
|
@ -3,12 +3,12 @@ cmake_minimum_required(VERSION 3.5)
|
||||
project(KImageFormats)
|
||||
|
||||
include(FeatureSummary)
|
||||
find_package(ECM 5.56.0 NO_MODULE)
|
||||
find_package(ECM 5.64.0 NO_MODULE)
|
||||
set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://projects.kde.org/projects/kdesupport/extra-cmake-modules")
|
||||
feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES)
|
||||
|
||||
|
||||
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR})
|
||||
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH})
|
||||
|
||||
include(KDEInstallDirs)
|
||||
include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE)
|
||||
@ -17,7 +17,7 @@ include(KDECMakeSettings)
|
||||
|
||||
include(CheckIncludeFiles)
|
||||
|
||||
set(REQUIRED_QT_VERSION 5.10.0)
|
||||
set(REQUIRED_QT_VERSION 5.11.0)
|
||||
find_package(Qt5Gui ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE)
|
||||
|
||||
find_package(KF5Archive)
|
||||
@ -46,6 +46,11 @@ set_package_properties(OpenEXR PROPERTIES
|
||||
PURPOSE "Required for the QImage plugin for OpenEXR images"
|
||||
)
|
||||
add_definitions(-DQT_NO_FOREACH)
|
||||
# 050d00 (5.13) triggers a BIC in qimageiohandler.h, in Qt 5.13, so do not enable that until we can require 5.14
|
||||
# https://codereview.qt-project.org/c/qt/qtbase/+/279215
|
||||
add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050c00)
|
||||
add_definitions(-DQT_DEPRECATED_WARNINGS_SINCE=0x060000)
|
||||
add_definitions(-DKF_DISABLE_DEPRECATED_BEFORE_AND_AT=0x053f00)
|
||||
add_subdirectory(src)
|
||||
if (BUILD_TESTING)
|
||||
add_subdirectory(autotests)
|
||||
|
@ -55,6 +55,7 @@ endmacro()
|
||||
# Loads each <format> image in read/<format>/, and compares the
|
||||
# result against the data read from the corresponding png file
|
||||
kimageformats_read_tests(
|
||||
hdr
|
||||
pcx
|
||||
psd
|
||||
ras
|
||||
|
@ -210,11 +210,11 @@ private Q_SLOTS:
|
||||
QFile picDumpFile(fileNameBase + QStringLiteral("-expected.data"));
|
||||
QVERIFY2(picDumpFile.open(QIODevice::WriteOnly), qPrintable(picDumpFile.errorString()));
|
||||
picDumpFile.write(reinterpret_cast<const char *>(inputImage.bits()),
|
||||
inputImage.byteCount());
|
||||
inputImage.sizeInBytes());
|
||||
QFile pngDumpFile(fileNameBase + QStringLiteral("-actual.data"));
|
||||
QVERIFY2(pngDumpFile.open(QIODevice::WriteOnly), qPrintable(pngDumpFile.errorString()));
|
||||
pngDumpFile.write(reinterpret_cast<const char *>(expImage.bits()),
|
||||
expImage.byteCount());
|
||||
expImage.sizeInBytes());
|
||||
QString msg = QStringLiteral("Read image (")
|
||||
+ picDumpFile.fileName()
|
||||
+ QStringLiteral(") differed from expected image (")
|
||||
|
BIN
autotests/read/hdr/rgb.hdr
Normal file
BIN
autotests/read/hdr/rgb.hdr
Normal file
Binary file not shown.
BIN
autotests/read/hdr/rgb.png
Normal file
BIN
autotests/read/hdr/rgb.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
BIN
autotests/read/xcf/bug411327.png
Normal file
BIN
autotests/read/xcf/bug411327.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
BIN
autotests/read/xcf/bug411327.xcf
Normal file
BIN
autotests/read/xcf/bug411327.xcf
Normal file
Binary file not shown.
@ -35,8 +35,8 @@ static void writeImageData(const char *name, const QString &filename, const QIma
|
||||
{
|
||||
QFile file(filename);
|
||||
if (file.open(QIODevice::WriteOnly)) {
|
||||
qint64 written = file.write(reinterpret_cast<const char *>(image.bits()), image.byteCount());
|
||||
if (written == image.byteCount()) {
|
||||
qint64 written = file.write(reinterpret_cast<const char *>(image.bits()), image.sizeInBytes());
|
||||
if (written == image.sizeInBytes()) {
|
||||
QTextStream(stdout) << " " << name
|
||||
<< " written to " << filename << "\n";
|
||||
} else {
|
||||
@ -148,6 +148,14 @@ int main(int argc, char ** argv)
|
||||
++failed;
|
||||
continue;
|
||||
}
|
||||
if (!inputReader.canRead()) {
|
||||
QTextStream(stdout) << "FAIL : " << fi.fileName()
|
||||
<< ": failed can read: "
|
||||
<< inputReader.errorString()
|
||||
<< "\n";
|
||||
++failed;
|
||||
continue;
|
||||
}
|
||||
if (!inputReader.read(&inputImage)) {
|
||||
QTextStream(stdout) << "FAIL : " << fi.fileName()
|
||||
<< ": failed to load: "
|
||||
|
@ -53,6 +53,11 @@ endif()
|
||||
|
||||
##################################
|
||||
|
||||
kimageformats_add_plugin(kimg_hdr JSON "hdr.json" SOURCES hdr.cpp)
|
||||
install(FILES hdr.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}/qimageioplugins/)
|
||||
|
||||
##################################
|
||||
|
||||
kimageformats_add_plugin(kimg_pcx JSON "pcx.json" SOURCES pcx.cpp)
|
||||
install(FILES pcx.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}/qimageioplugins/)
|
||||
|
||||
|
@ -82,7 +82,7 @@ void K_IStream::clear()
|
||||
* format into the normal 32 bit pixel format. Process is from the
|
||||
* ILM code.
|
||||
*/
|
||||
QRgb RgbaToQrgba(struct Imf::Rgba imagePixel)
|
||||
QRgb RgbaToQrgba(struct Imf::Rgba &imagePixel)
|
||||
{
|
||||
float r, g, b, a;
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
typedef Q_UINT8 uchar;
|
||||
typedef unsigned char uchar;
|
||||
|
||||
namespace // Private.
|
||||
{
|
||||
@ -93,19 +93,22 @@ static bool LoadHDR(QDataStream &s, const int width, const int height, QImage &i
|
||||
uchar val, code;
|
||||
|
||||
// Create dst image.
|
||||
if (!img.create(width, height, 32)) {
|
||||
img = QImage(width, height, QImage::Format_RGB32);
|
||||
if (img.isNull()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QMemArray<uchar> image(width * 4);
|
||||
QByteArray lineArray;
|
||||
lineArray.resize(4 * width);
|
||||
uchar *image = (uchar *) lineArray.data();
|
||||
|
||||
for (int cline = 0; cline < height; cline++) {
|
||||
QRgb *scanline = (QRgb *) img.scanLine(cline);
|
||||
|
||||
// determine scanline type
|
||||
if ((width < MINELEN) || (MAXELEN < width)) {
|
||||
Read_Old_Line(image.data(), width, s);
|
||||
RGBE_To_QRgbLine(image.data(), scanline, width);
|
||||
Read_Old_Line(image, width, s);
|
||||
RGBE_To_QRgbLine(image, scanline, width);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -116,9 +119,9 @@ static bool LoadHDR(QDataStream &s, const int width, const int height, QImage &i
|
||||
}
|
||||
|
||||
if (val != 2) {
|
||||
s.device()->at(s.device()->at() - 1);
|
||||
Read_Old_Line(image.data(), width, s);
|
||||
RGBE_To_QRgbLine(image.data(), scanline, width);
|
||||
s.device()->ungetChar(val);
|
||||
Read_Old_Line(image, width, s);
|
||||
RGBE_To_QRgbLine(image, scanline, width);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -132,8 +135,8 @@ static bool LoadHDR(QDataStream &s, const int width, const int height, QImage &i
|
||||
|
||||
if ((image[1] != 2) || (image[2] & 128)) {
|
||||
image[0] = 2;
|
||||
Read_Old_Line(image.data() + 4, width - 1, s);
|
||||
RGBE_To_QRgbLine(image.data(), scanline, width);
|
||||
Read_Old_Line(image + 4, width - 1, s);
|
||||
RGBE_To_QRgbLine(image, scanline, width);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -168,7 +171,7 @@ static bool LoadHDR(QDataStream &s, const int width, const int height, QImage &i
|
||||
}
|
||||
}
|
||||
|
||||
RGBE_To_QRgbLine(image.data(), scanline, width);
|
||||
RGBE_To_QRgbLine(image, scanline, width);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -176,7 +179,7 @@ static bool LoadHDR(QDataStream &s, const int width, const int height, QImage &i
|
||||
|
||||
} // namespace
|
||||
|
||||
Q_DECL_EXPORT void kimgio_hdr_read(QImageIO *io)
|
||||
bool HDRHandler::read(QImage *outImage)
|
||||
{
|
||||
int len;
|
||||
char line[MAXLINE];
|
||||
@ -185,7 +188,7 @@ Q_DECL_EXPORT void kimgio_hdr_read(QImageIO *io)
|
||||
|
||||
// Parse header
|
||||
do {
|
||||
len = io->ioDevice()->readLine(line, MAXLINE);
|
||||
len = device()->readLine(line, MAXLINE);
|
||||
|
||||
/*if (strcmp(line, "#?RADIANCE\n") == 0 || strcmp(line, "#?RGBE\n") == 0)
|
||||
{
|
||||
@ -199,12 +202,10 @@ Q_DECL_EXPORT void kimgio_hdr_read(QImageIO *io)
|
||||
|
||||
if (/*!validHeader ||*/ !validFormat) {
|
||||
// qDebug() << "Unknown HDR format.";
|
||||
io->setImage(0);
|
||||
io->setStatus(-1);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
io->ioDevice()->readLine(line, MAXLINE);
|
||||
device()->readLine(line, MAXLINE);
|
||||
|
||||
char s1[3], s2[3];
|
||||
int width, height;
|
||||
@ -212,27 +213,67 @@ Q_DECL_EXPORT void kimgio_hdr_read(QImageIO *io)
|
||||
//if( sscanf(line, "-Y %d +X %d", &height, &width) < 2 )
|
||||
{
|
||||
// qDebug() << "Invalid HDR file.";
|
||||
io->setImage(0);
|
||||
io->setStatus(-1);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
QDataStream s(io->ioDevice());
|
||||
QDataStream s(device());
|
||||
|
||||
QImage img;
|
||||
if (!LoadHDR(s, width, height, img)) {
|
||||
// qDebug() << "Error loading HDR file.";
|
||||
io->setImage(0);
|
||||
io->setStatus(-1);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
io->setImage(img);
|
||||
io->setStatus(0);
|
||||
*outImage = img;
|
||||
return true;
|
||||
}
|
||||
|
||||
Q_DECL_EXPORT void kimgio_hdr_write(QImageIO *)
|
||||
HDRHandler::HDRHandler()
|
||||
{
|
||||
// intentionally not implemented (since writing low dynamic range data to a HDR file is nonsense.)
|
||||
}
|
||||
|
||||
bool HDRHandler::canRead() const
|
||||
{
|
||||
if (canRead(device())) {
|
||||
setFormat("hdr");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HDRHandler::canRead(QIODevice *device)
|
||||
{
|
||||
if (!device) {
|
||||
qWarning("HDRHandler::canRead() called with no device");
|
||||
return false;
|
||||
}
|
||||
|
||||
return device->peek(11) == "#?RADIANCE\n" || device->peek(7) == "#?RGBE\n";
|
||||
}
|
||||
|
||||
QImageIOPlugin::Capabilities HDRPlugin::capabilities(QIODevice *device, const QByteArray &format) const
|
||||
{
|
||||
if (format == "hdr") {
|
||||
return Capabilities(CanRead);
|
||||
}
|
||||
if (!format.isEmpty()) {
|
||||
return {};
|
||||
}
|
||||
if (!device->isOpen()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
Capabilities cap;
|
||||
if (device->isReadable() && HDRHandler::canRead(device)) {
|
||||
cap |= CanRead;
|
||||
}
|
||||
return cap;
|
||||
}
|
||||
|
||||
QImageIOHandler *HDRPlugin::create(QIODevice *device, const QByteArray &format) const
|
||||
{
|
||||
QImageIOHandler *handler = new HDRHandler;
|
||||
handler->setDevice(device);
|
||||
handler->setFormat(format);
|
||||
return handler;
|
||||
}
|
||||
|
4
src/imageformats/hdr.json
Normal file
4
src/imageformats/hdr.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"Keys": [ "hdr" ],
|
||||
"MimeTypes": [ "image/x-hdr", "image/vnd.radiance" ]
|
||||
}
|
@ -10,12 +10,27 @@
|
||||
#ifndef KIMG_HDR_P_H
|
||||
#define KIMG_HDR_P_H
|
||||
|
||||
class QImageIO;
|
||||
#include <QImageIOPlugin>
|
||||
|
||||
extern "C" {
|
||||
void kimgio_hdr_read(QImageIO *);
|
||||
void kimgio_hdr_write(QImageIO *);
|
||||
}
|
||||
class HDRHandler : public QImageIOHandler
|
||||
{
|
||||
public:
|
||||
HDRHandler();
|
||||
|
||||
#endif
|
||||
bool canRead() const override;
|
||||
bool read(QImage *outImage) override;
|
||||
|
||||
static bool canRead(QIODevice *device);
|
||||
};
|
||||
|
||||
class HDRPlugin : public QImageIOPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "hdr.json")
|
||||
|
||||
public:
|
||||
Capabilities capabilities(QIODevice *device, const QByteArray &format) const override;
|
||||
QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const override;
|
||||
};
|
||||
|
||||
#endif // KIMG_HDR_P_H
|
||||
|
@ -18,6 +18,9 @@
|
||||
#include <QIODevice>
|
||||
#include <QFile>
|
||||
|
||||
static constexpr char s_magic[] = "application/x-krita";
|
||||
static constexpr int s_magic_size = sizeof(s_magic) - 1; // -1 to remove the last \0
|
||||
|
||||
KraHandler::KraHandler()
|
||||
{
|
||||
}
|
||||
@ -36,7 +39,7 @@ bool KraHandler::read(QImage *image)
|
||||
KZip zip(device());
|
||||
if (!zip.open(QIODevice::ReadOnly)) return false;
|
||||
|
||||
const KArchiveEntry *entry = zip.directory()->entry(QLatin1String("mergedimage.png"));
|
||||
const KArchiveEntry *entry = zip.directory()->entry(QStringLiteral("mergedimage.png"));
|
||||
if (!entry || !entry->isFile()) return false;
|
||||
|
||||
const KZipFileEntry* fileZipEntry = static_cast<const KZipFileEntry*>(entry);
|
||||
@ -55,7 +58,7 @@ bool KraHandler::canRead(QIODevice *device)
|
||||
|
||||
char buff[57];
|
||||
if (device->peek(buff, sizeof(buff)) == sizeof(buff))
|
||||
return qstrcmp(buff + 0x26, "application/x-krita") == 0;
|
||||
return memcmp(buff + 0x26, s_magic, s_magic_size) == 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -17,6 +17,9 @@
|
||||
|
||||
#include <kzip.h>
|
||||
|
||||
static constexpr char s_magic[] = "image/openraster";
|
||||
static constexpr int s_magic_size = sizeof(s_magic) - 1; // -1 to remove the last \0
|
||||
|
||||
OraHandler::OraHandler()
|
||||
{
|
||||
}
|
||||
@ -35,7 +38,7 @@ bool OraHandler::read(QImage *image)
|
||||
KZip zip(device());
|
||||
if (!zip.open(QIODevice::ReadOnly)) return false;
|
||||
|
||||
const KArchiveEntry *entry = zip.directory()->entry(QLatin1String("mergedimage.png"));
|
||||
const KArchiveEntry *entry = zip.directory()->entry(QStringLiteral("mergedimage.png"));
|
||||
if (!entry || !entry->isFile()) return false;
|
||||
|
||||
const KZipFileEntry* fileZipEntry = static_cast<const KZipFileEntry*>(entry);
|
||||
@ -54,7 +57,7 @@ bool OraHandler::canRead(QIODevice *device)
|
||||
|
||||
char buff[54];
|
||||
if (device->peek(buff, sizeof(buff)) == sizeof(buff))
|
||||
return qstrcmp(buff + 0x26, "image/openraster") == 0;
|
||||
return memcmp(buff + 0x26, s_magic, s_magic_size) == 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ public:
|
||||
quint8 g;
|
||||
quint8 b;
|
||||
|
||||
static RGB from(const QRgb &color)
|
||||
static RGB from(const QRgb color)
|
||||
{
|
||||
RGB c;
|
||||
c.r = qRed(color);
|
||||
@ -169,7 +169,7 @@ static QDataStream &operator>>(QDataStream &s, PCXHEADER &ph)
|
||||
return s;
|
||||
}
|
||||
|
||||
static QDataStream &operator<<(QDataStream &s, const RGB &rgb)
|
||||
static QDataStream &operator<<(QDataStream &s, const RGB rgb)
|
||||
{
|
||||
s << rgb.r << rgb.g << rgb.b;
|
||||
|
||||
|
@ -1,7 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=QImageIOPlugins
|
||||
X-KDE-ImageFormat=pnm
|
||||
X-KDE-MimeType=image/x-portable-anymap
|
||||
X-KDE-Read=true
|
||||
X-KDE-Write=false
|
@ -143,7 +143,7 @@ static bool LoadRAS(QDataStream &s, const RasHeader &ras, QImage &img)
|
||||
QVector<quint8> input(ras.Length);
|
||||
|
||||
int i = 0;
|
||||
while (! s.atEnd()) {
|
||||
while (! s.atEnd() && i < input.size()) {
|
||||
s >> input[i];
|
||||
// I guess we need to find out if we're at the end of a line
|
||||
if (paddingrequired && i != 0 && !(i % (ras.Width * bpp))) {
|
||||
|
@ -336,6 +336,9 @@ bool SGIImage::readImage(QImage &img)
|
||||
_stream >> _starttab[l];
|
||||
_starttab[l] -= 512 + _numrows * 2 * sizeof(quint32);
|
||||
}
|
||||
for (; l < _numrows; l++) {
|
||||
_starttab[l] = 0;
|
||||
}
|
||||
|
||||
_lengthtab = new quint32[_numrows];
|
||||
for (l = 0; l < _numrows; l++) {
|
||||
@ -709,7 +712,7 @@ bool RGBHandler::canRead(QIODevice *device)
|
||||
device->seek(oldPos);
|
||||
}
|
||||
|
||||
return head.size() >= 4 && head.startsWith("\x01\xda\x01") && (head[3] == 1 || head[3] == 2);
|
||||
return head.size() >= 4 && head.startsWith("\x01\xda") && (head[2] == 0 || head[2] == 1) && (head[3] == 1 || head[3] == 2);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -201,16 +201,20 @@ static bool LoadTGA(QDataStream &s, const TgaHeader &tga, QImage &img)
|
||||
}
|
||||
|
||||
// Read palette.
|
||||
char palette[768];
|
||||
static const int max_palette_size = 768;
|
||||
char palette[max_palette_size];
|
||||
if (info.pal) {
|
||||
// @todo Support palettes in other formats!
|
||||
const int size = 3 * tga.colormap_length;
|
||||
const int dataRead = s.readRawData(palette, size);
|
||||
const int palette_size = 3 * tga.colormap_length;
|
||||
if (palette_size > max_palette_size) {
|
||||
return false;
|
||||
}
|
||||
const int dataRead = s.readRawData(palette, palette_size);
|
||||
if (dataRead < 0) {
|
||||
return false;
|
||||
}
|
||||
if (dataRead < size) {
|
||||
memset(&palette[dataRead], 0, size - dataRead);
|
||||
if (dataRead < max_palette_size) {
|
||||
memset(&palette[dataRead], 0, max_palette_size - dataRead);
|
||||
}
|
||||
}
|
||||
|
||||
@ -248,7 +252,10 @@ static bool LoadTGA(QDataStream &s, const TgaHeader &tga, QImage &img)
|
||||
// RLE pixels.
|
||||
assert(pixel_size <= 8);
|
||||
char pixel[8];
|
||||
s.readRawData(pixel, pixel_size);
|
||||
const int dataRead = s.readRawData(pixel, pixel_size);
|
||||
if (dataRead < (int)pixel_size) {
|
||||
memset(&pixel[dataRead], 0, pixel_size - dataRead);
|
||||
}
|
||||
do {
|
||||
memcpy(dst, pixel, pixel_size);
|
||||
dst += pixel_size;
|
||||
@ -256,7 +263,14 @@ static bool LoadTGA(QDataStream &s, const TgaHeader &tga, QImage &img)
|
||||
} else {
|
||||
// Raw pixels.
|
||||
count *= pixel_size;
|
||||
s.readRawData(dst, count);
|
||||
const int dataRead = s.readRawData(dst, count);
|
||||
if (dataRead < 0) {
|
||||
free(image);
|
||||
return false;
|
||||
}
|
||||
if ((uint)dataRead < count) {
|
||||
memset(&dst[dataRead], 0, count - dataRead);
|
||||
}
|
||||
dst += count;
|
||||
}
|
||||
}
|
||||
|
@ -167,11 +167,11 @@ private:
|
||||
|
||||
//! The bottom-most layer is copied into the final QImage by this
|
||||
//! routine.
|
||||
typedef void (*PixelCopyOperation)(Layer &layer, uint i, uint j, int k, int l,
|
||||
typedef void (*PixelCopyOperation)(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n);
|
||||
|
||||
//! Higher layers are merged into the final QImage by this routine.
|
||||
typedef void (*PixelMergeOperation)(Layer &layer, uint i, uint j, int k, int l,
|
||||
typedef void (*PixelMergeOperation)(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n);
|
||||
|
||||
//! Layer mode static data.
|
||||
@ -201,37 +201,37 @@ private:
|
||||
int data_length, qint32 bpp);
|
||||
|
||||
static void copyLayerToImage(XCFImage &xcf_image);
|
||||
static void copyRGBToRGB(Layer &layer, uint i, uint j, int k, int l,
|
||||
static void copyRGBToRGB(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n);
|
||||
static void copyGrayToGray(Layer &layer, uint i, uint j, int k, int l,
|
||||
static void copyGrayToGray(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n);
|
||||
static void copyGrayToRGB(Layer &layer, uint i, uint j, int k, int l,
|
||||
static void copyGrayToRGB(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n);
|
||||
static void copyGrayAToRGB(Layer &layer, uint i, uint j, int k, int l,
|
||||
static void copyGrayAToRGB(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n);
|
||||
static void copyIndexedToIndexed(Layer &layer, uint i, uint j, int k, int l,
|
||||
static void copyIndexedToIndexed(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n);
|
||||
static void copyIndexedAToIndexed(Layer &layer, uint i, uint j, int k, int l,
|
||||
static void copyIndexedAToIndexed(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n);
|
||||
static void copyIndexedAToRGB(Layer &layer, uint i, uint j, int k, int l,
|
||||
static void copyIndexedAToRGB(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n);
|
||||
|
||||
static void mergeLayerIntoImage(XCFImage &xcf_image);
|
||||
static void mergeRGBToRGB(Layer &layer, uint i, uint j, int k, int l,
|
||||
static void mergeRGBToRGB(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n);
|
||||
static void mergeGrayToGray(Layer &layer, uint i, uint j, int k, int l,
|
||||
static void mergeGrayToGray(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n);
|
||||
static void mergeGrayAToGray(Layer &layer, uint i, uint j, int k, int l,
|
||||
static void mergeGrayAToGray(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n);
|
||||
static void mergeGrayToRGB(Layer &layer, uint i, uint j, int k, int l,
|
||||
static void mergeGrayToRGB(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n);
|
||||
static void mergeGrayAToRGB(Layer &layer, uint i, uint j, int k, int l,
|
||||
static void mergeGrayAToRGB(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n);
|
||||
static void mergeIndexedToIndexed(Layer &layer, uint i, uint j, int k, int l,
|
||||
static void mergeIndexedToIndexed(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n);
|
||||
static void mergeIndexedAToIndexed(Layer &layer, uint i, uint j, int k, int l,
|
||||
static void mergeIndexedAToIndexed(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n);
|
||||
static void mergeIndexedAToRGB(Layer &layer, uint i, uint j, int k, int l,
|
||||
static void mergeIndexedAToRGB(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n);
|
||||
|
||||
static void initializeRandomTable();
|
||||
@ -244,6 +244,12 @@ bool XCFImageFormat::random_table_initialized;
|
||||
|
||||
QVector<QRgb> XCFImageFormat::grayTable;
|
||||
|
||||
template <typename T, size_t N>
|
||||
constexpr size_t countof(T(&)[N])
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
const XCFImageFormat::LayerModes XCFImageFormat::layer_modes[] = {
|
||||
{true}, // NORMAL_MODE
|
||||
{true}, // DISSOLVE_MODE
|
||||
@ -270,7 +276,7 @@ const XCFImageFormat::LayerModes XCFImageFormat::layer_modes[] = {
|
||||
};
|
||||
|
||||
//! Change a QRgb value's alpha only.
|
||||
inline QRgb qRgba(const QRgb &rgb, int a)
|
||||
inline QRgb qRgba(const QRgb rgb, int a)
|
||||
{
|
||||
return ((a & 0xff) << 24 | (rgb & RGB_MASK));
|
||||
}
|
||||
@ -408,6 +414,7 @@ bool XCFImageFormat::loadImageProperties(QDataStream &xcf_io, XCFImage &xcf_imag
|
||||
break;
|
||||
|
||||
case PROP_RESOLUTION:
|
||||
property.setFloatingPointPrecision(QDataStream::SinglePrecision);
|
||||
property >> xcf_image.x_resolution >> xcf_image.y_resolution;
|
||||
break;
|
||||
|
||||
@ -478,9 +485,15 @@ bool XCFImageFormat::loadImageProperties(QDataStream &xcf_io, XCFImage &xcf_imag
|
||||
* \return true if there were no IO errors. */
|
||||
bool XCFImageFormat::loadProperty(QDataStream &xcf_io, PropType &type, QByteArray &bytes, quint32 &rawType)
|
||||
{
|
||||
quint32 size;
|
||||
|
||||
xcf_io >> rawType;
|
||||
if (rawType >= MAX_SUPPORTED_PROPTYPE) {
|
||||
type = MAX_SUPPORTED_PROPTYPE;
|
||||
// we don't support the property, but we still need to read from the device, assume it's like all the
|
||||
// non custom properties that is data_length + data
|
||||
xcf_io >> size;
|
||||
xcf_io.skipRawData(size);
|
||||
// return true because we don't really want to totally fail on an unsupported property since it may not be fatal
|
||||
return true;
|
||||
}
|
||||
@ -488,7 +501,6 @@ bool XCFImageFormat::loadProperty(QDataStream &xcf_io, PropType &type, QByteArra
|
||||
type = PropType(rawType);
|
||||
|
||||
char *data = nullptr;
|
||||
quint32 size;
|
||||
|
||||
// The colormap property size is not the correct number of bytes:
|
||||
// The GIMP source xcf.c has size = 4 + ncolors, but it should be
|
||||
@ -709,6 +721,10 @@ bool XCFImageFormat::loadLayerProperties(QDataStream &xcf_io, Layer &layer)
|
||||
|
||||
case PROP_MODE:
|
||||
property >> layer.mode;
|
||||
if (layer.mode >= countof(layer_modes)) {
|
||||
qWarning() << "Found layer with unsupported mode" << layer.mode << "Defaulting to mode 0";
|
||||
layer.mode = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_TATTOO:
|
||||
@ -1068,6 +1084,9 @@ bool XCFImageFormat::loadLevel(QDataStream &xcf_io, Layer &layer, qint32 bpp)
|
||||
for (uint j = 0; j < layer.nrows; j++) {
|
||||
for (uint i = 0; i < layer.ncols; i++) {
|
||||
layer.image_tiles[j][i].fill(Qt::transparent);
|
||||
if (layer.type == GRAYA_GIMAGE || layer.type == INDEXEDA_GIMAGE) {
|
||||
layer.alpha_tiles[j][i].fill(Qt::transparent);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -1630,7 +1649,7 @@ void XCFImageFormat::copyLayerToImage(XCFImage &xcf_image)
|
||||
* \param m x pixel of destination image.
|
||||
* \param n y pixel of destination image.
|
||||
*/
|
||||
void XCFImageFormat::copyRGBToRGB(Layer &layer, uint i, uint j, int k, int l,
|
||||
void XCFImageFormat::copyRGBToRGB(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n)
|
||||
{
|
||||
QRgb src = layer.image_tiles[j][i].pixel(k, l);
|
||||
@ -1661,7 +1680,7 @@ void XCFImageFormat::copyRGBToRGB(Layer &layer, uint i, uint j, int k, int l,
|
||||
* \param m x pixel of destination image.
|
||||
* \param n y pixel of destination image.
|
||||
*/
|
||||
void XCFImageFormat::copyGrayToGray(Layer &layer, uint i, uint j, int k, int l,
|
||||
void XCFImageFormat::copyGrayToGray(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n)
|
||||
{
|
||||
int src = layer.image_tiles[j][i].pixelIndex(k, l);
|
||||
@ -1681,7 +1700,7 @@ void XCFImageFormat::copyGrayToGray(Layer &layer, uint i, uint j, int k, int l,
|
||||
* \param m x pixel of destination image.
|
||||
* \param n y pixel of destination image.
|
||||
*/
|
||||
void XCFImageFormat::copyGrayToRGB(Layer &layer, uint i, uint j, int k, int l,
|
||||
void XCFImageFormat::copyGrayToRGB(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n)
|
||||
{
|
||||
QRgb src = layer.image_tiles[j][i].pixel(k, l);
|
||||
@ -1702,7 +1721,7 @@ void XCFImageFormat::copyGrayToRGB(Layer &layer, uint i, uint j, int k, int l,
|
||||
* \param m x pixel of destination image.
|
||||
* \param n y pixel of destination image.
|
||||
*/
|
||||
void XCFImageFormat::copyGrayAToRGB(Layer &layer, uint i, uint j, int k, int l,
|
||||
void XCFImageFormat::copyGrayAToRGB(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n)
|
||||
{
|
||||
QRgb src = layer.image_tiles[j][i].pixel(k, l);
|
||||
@ -1730,7 +1749,7 @@ void XCFImageFormat::copyGrayAToRGB(Layer &layer, uint i, uint j, int k, int l,
|
||||
* \param m x pixel of destination image.
|
||||
* \param n y pixel of destination image.
|
||||
*/
|
||||
void XCFImageFormat::copyIndexedToIndexed(Layer &layer, uint i, uint j, int k, int l,
|
||||
void XCFImageFormat::copyIndexedToIndexed(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n)
|
||||
{
|
||||
int src = layer.image_tiles[j][i].pixelIndex(k, l);
|
||||
@ -1748,7 +1767,7 @@ void XCFImageFormat::copyIndexedToIndexed(Layer &layer, uint i, uint j, int k, i
|
||||
* \param m x pixel of destination image.
|
||||
* \param n y pixel of destination image.
|
||||
*/
|
||||
void XCFImageFormat::copyIndexedAToIndexed(Layer &layer, uint i, uint j, int k, int l,
|
||||
void XCFImageFormat::copyIndexedAToIndexed(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n)
|
||||
{
|
||||
uchar src = layer.image_tiles[j][i].pixelIndex(k, l);
|
||||
@ -1783,7 +1802,7 @@ void XCFImageFormat::copyIndexedAToIndexed(Layer &layer, uint i, uint j, int k,
|
||||
* \param m x pixel of destination image.
|
||||
* \param n y pixel of destination image.
|
||||
*/
|
||||
void XCFImageFormat::copyIndexedAToRGB(Layer &layer, uint i, uint j, int k, int l,
|
||||
void XCFImageFormat::copyIndexedAToRGB(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n)
|
||||
{
|
||||
QRgb src = layer.image_tiles[j][i].pixel(k, l);
|
||||
@ -1920,7 +1939,7 @@ void XCFImageFormat::mergeLayerIntoImage(XCFImage &xcf_image)
|
||||
* \param m x pixel of destination image.
|
||||
* \param n y pixel of destination image.
|
||||
*/
|
||||
void XCFImageFormat::mergeRGBToRGB(Layer &layer, uint i, uint j, int k, int l,
|
||||
void XCFImageFormat::mergeRGBToRGB(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n)
|
||||
{
|
||||
QRgb src = layer.image_tiles[j][i].pixel(k, l);
|
||||
@ -2246,7 +2265,7 @@ void XCFImageFormat::mergeRGBToRGB(Layer &layer, uint i, uint j, int k, int l,
|
||||
* \param m x pixel of destination image.
|
||||
* \param n y pixel of destination image.
|
||||
*/
|
||||
void XCFImageFormat::mergeGrayToGray(Layer &layer, uint i, uint j, int k, int l,
|
||||
void XCFImageFormat::mergeGrayToGray(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n)
|
||||
{
|
||||
int src = layer.image_tiles[j][i].pixelIndex(k, l);
|
||||
@ -2264,7 +2283,7 @@ void XCFImageFormat::mergeGrayToGray(Layer &layer, uint i, uint j, int k, int l,
|
||||
* \param m x pixel of destination image.
|
||||
* \param n y pixel of destination image.
|
||||
*/
|
||||
void XCFImageFormat::mergeGrayAToGray(Layer &layer, uint i, uint j, int k, int l,
|
||||
void XCFImageFormat::mergeGrayAToGray(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n)
|
||||
{
|
||||
int src = qGray(layer.image_tiles[j][i].pixel(k, l));
|
||||
@ -2401,7 +2420,7 @@ void XCFImageFormat::mergeGrayAToGray(Layer &layer, uint i, uint j, int k, int l
|
||||
* \param m x pixel of destination image.
|
||||
* \param n y pixel of destination image.
|
||||
*/
|
||||
void XCFImageFormat::mergeGrayToRGB(Layer &layer, uint i, uint j, int k, int l,
|
||||
void XCFImageFormat::mergeGrayToRGB(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n)
|
||||
{
|
||||
QRgb src = layer.image_tiles[j][i].pixel(k, l);
|
||||
@ -2422,7 +2441,7 @@ void XCFImageFormat::mergeGrayToRGB(Layer &layer, uint i, uint j, int k, int l,
|
||||
* \param m x pixel of destination image.
|
||||
* \param n y pixel of destination image.
|
||||
*/
|
||||
void XCFImageFormat::mergeGrayAToRGB(Layer &layer, uint i, uint j, int k, int l,
|
||||
void XCFImageFormat::mergeGrayAToRGB(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n)
|
||||
{
|
||||
int src = qGray(layer.image_tiles[j][i].pixel(k, l));
|
||||
@ -2576,7 +2595,7 @@ void XCFImageFormat::mergeGrayAToRGB(Layer &layer, uint i, uint j, int k, int l,
|
||||
* \param m x pixel of destination image.
|
||||
* \param n y pixel of destination image.
|
||||
*/
|
||||
void XCFImageFormat::mergeIndexedToIndexed(Layer &layer, uint i, uint j, int k, int l,
|
||||
void XCFImageFormat::mergeIndexedToIndexed(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n)
|
||||
{
|
||||
int src = layer.image_tiles[j][i].pixelIndex(k, l);
|
||||
@ -2594,7 +2613,7 @@ void XCFImageFormat::mergeIndexedToIndexed(Layer &layer, uint i, uint j, int k,
|
||||
* \param m x pixel of destination image.
|
||||
* \param n y pixel of destination image.
|
||||
*/
|
||||
void XCFImageFormat::mergeIndexedAToIndexed(Layer &layer, uint i, uint j, int k, int l,
|
||||
void XCFImageFormat::mergeIndexedAToIndexed(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n)
|
||||
{
|
||||
uchar src = layer.image_tiles[j][i].pixelIndex(k, l);
|
||||
@ -2626,7 +2645,7 @@ void XCFImageFormat::mergeIndexedAToIndexed(Layer &layer, uint i, uint j, int k,
|
||||
* \param m x pixel of destination image.
|
||||
* \param n y pixel of destination image.
|
||||
*/
|
||||
void XCFImageFormat::mergeIndexedAToRGB(Layer &layer, uint i, uint j, int k, int l,
|
||||
void XCFImageFormat::mergeIndexedAToRGB(const Layer &layer, uint i, uint j, int k, int l,
|
||||
QImage &image, int m, int n)
|
||||
{
|
||||
QRgb src = layer.image_tiles[j][i].pixel(k, l);
|
||||
|
@ -116,8 +116,8 @@ int main(int argc, char **argv)
|
||||
}
|
||||
img = img.convertToFormat(qformat);
|
||||
}
|
||||
qint64 written = output.write(reinterpret_cast<const char *>(img.bits()), img.byteCount());
|
||||
if (written != img.byteCount()) {
|
||||
qint64 written = output.write(reinterpret_cast<const char *>(img.bits()), img.sizeInBytes());
|
||||
if (written != img.sizeInBytes()) {
|
||||
QTextStream(stderr) << "Could not write image data to " << files.at(1)
|
||||
<< ":" << output.errorString() << "\n";
|
||||
return 5;
|
||||
|
Reference in New Issue
Block a user