mirror of
https://invent.kde.org/frameworks/kimageformats.git
synced 2026-07-05 01:39:10 -04:00
IFF: add support for CD-i YUVS chunk (and minor code improvements)
This commit is contained in:
@@ -357,11 +357,15 @@ The plugin supports the following image data:
|
|||||||
type 4.
|
type 4.
|
||||||
- FORM PBM: PBM is a chunky version of IFF pictures. It supports 8-bit images
|
- FORM PBM: PBM is a chunky version of IFF pictures. It supports 8-bit images
|
||||||
with color map only.
|
with color map only.
|
||||||
- FORM IMAG (Compact Disc-Interactive): It supports CLut4, CLut8 and DYuv
|
- FORM IMAG (Compact Disc-Interactive): It supports CLut4, CLut7, CLut8 and
|
||||||
formats.
|
DYuv formats.
|
||||||
- FOR4 CIMG (Maya Image File Format): It supports 24/48-bit RGB and 32/64-bit
|
- FOR4 CIMG (Maya Image File Format): It supports 24/48-bit RGB and 32/64-bit
|
||||||
RGBA images.
|
RGBA images.
|
||||||
|
|
||||||
|
> [!note]
|
||||||
|
> The plugin only supports the IFF, ILBM, and LBM file extensions. You'll
|
||||||
|
> need to rename files with different extensions to open them.
|
||||||
|
|
||||||
### The JP2 plugin
|
### The JP2 plugin
|
||||||
|
|
||||||
**This plugin can be disabled by setting `KIMAGEFORMATS_JP2` to `OFF`
|
**This plugin can be disabled by setting `KIMAGEFORMATS_JP2` to `OFF`
|
||||||
|
|||||||
BIN
autotests/read/iff/cdi_dyuv_each.iff
Normal file
BIN
autotests/read/iff/cdi_dyuv_each.iff
Normal file
Binary file not shown.
9
autotests/read/iff/cdi_dyuv_each.iff.json
Normal file
9
autotests/read/iff/cdi_dyuv_each.iff.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"fileName" : "cdi_dyuv_each.iff",
|
||||||
|
"resolution" : {
|
||||||
|
"dotsPerMeterX" : 3937,
|
||||||
|
"dotsPerMeterY" : 5249
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
BIN
autotests/read/iff/cdi_dyuv_each.png
Normal file
BIN
autotests/read/iff/cdi_dyuv_each.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.2 KiB |
BIN
autotests/read/iff/cdi_dyuv_one.iff
Normal file
BIN
autotests/read/iff/cdi_dyuv_one.iff
Normal file
Binary file not shown.
BIN
autotests/read/iff/cdi_dyuv_one.png
Normal file
BIN
autotests/read/iff/cdi_dyuv_one.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.2 KiB |
@@ -337,6 +337,8 @@ IFFChunk::ChunkList IFFChunk::innerFromDevice(QIODevice *d, bool *ok, IFFChunk *
|
|||||||
chunk = QSharedPointer<IFFChunk>(new XBMIChunk());
|
chunk = QSharedPointer<IFFChunk>(new XBMIChunk());
|
||||||
} else if (cid == XMP0_CHUNK) {
|
} else if (cid == XMP0_CHUNK) {
|
||||||
chunk = QSharedPointer<IFFChunk>(new XMP0Chunk());
|
chunk = QSharedPointer<IFFChunk>(new XMP0Chunk());
|
||||||
|
} else if (cid == YUVS_CHUNK) {
|
||||||
|
chunk = QSharedPointer<IFFChunk>(new YUVSChunk());
|
||||||
} else { // unknown chunk
|
} else { // unknown chunk
|
||||||
chunk = QSharedPointer<IFFChunk>(new IFFChunk());
|
chunk = QSharedPointer<IFFChunk>(new IFFChunk());
|
||||||
qCDebug(LOG_IFFPLUGIN) << "IFFChunk::innerFromDevice(): unknown chunk" << cid;
|
qCDebug(LOG_IFFPLUGIN) << "IFFChunk::innerFromDevice(): unknown chunk" << cid;
|
||||||
@@ -922,11 +924,11 @@ CAMGChunk::ModeIds BODYChunk::safeModeId(const BMHDChunk *header, const CAMGChun
|
|||||||
auto cmapCount = cmap ? cmap->count() : 0;
|
auto cmapCount = cmap ? cmap->count() : 0;
|
||||||
auto bitplanes = header->bitplanes();
|
auto bitplanes = header->bitplanes();
|
||||||
if (bitplanes >= BITPLANES_HALFBRIDE_MIN && bitplanes <= BITPLANES_HALFBRIDE_MAX) {
|
if (bitplanes >= BITPLANES_HALFBRIDE_MIN && bitplanes <= BITPLANES_HALFBRIDE_MAX) {
|
||||||
if (cmapCount == (1 << (header->bitplanes() - 1)))
|
if (cmapCount == (1 << (bitplanes - 1)))
|
||||||
return CAMGChunk::ModeIds(CAMGChunk::ModeId::HalfBrite);
|
return CAMGChunk::ModeIds(CAMGChunk::ModeId::HalfBrite);
|
||||||
}
|
}
|
||||||
if (bitplanes >= BITPLANES_HAM_MIN && bitplanes <= BITPLANES_HAM_MAX) {
|
if (bitplanes >= BITPLANES_HAM_MIN && bitplanes <= BITPLANES_HAM_MAX) {
|
||||||
if (cmapCount == (1 << (header->bitplanes() - 2)))
|
if (cmapCount == (1 << (bitplanes - 2)))
|
||||||
return CAMGChunk::ModeIds(CAMGChunk::ModeId::Ham);
|
return CAMGChunk::ModeIds(CAMGChunk::ModeId::Ham);
|
||||||
}
|
}
|
||||||
return CAMGChunk::ModeIds();
|
return CAMGChunk::ModeIds();
|
||||||
@@ -1488,13 +1490,13 @@ QImage::Format FORMChunk::cdiFormat() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (h->depth() == 8) {
|
if (h->depth() == 8) {
|
||||||
if (h->model() == IHDRChunk::CLut8 || h->model() == IHDRChunk::CLut7) { // CLut7: no test case
|
if (h->model() == IHDRChunk::CLut8 || h->model() == IHDRChunk::CLut7) {
|
||||||
return QImage::Format_Indexed8;
|
return QImage::Format_Indexed8;
|
||||||
}
|
}
|
||||||
if (h->model() == IHDRChunk::Rgb888) { // no test case
|
if (h->model() == IHDRChunk::Rgb888) { // no test case
|
||||||
return FORMAT_RGB_8BIT;
|
return FORMAT_RGB_8BIT;
|
||||||
}
|
}
|
||||||
if (h->model() == IHDRChunk::DYuv && h->yuvKind() == IHDRChunk::One) {
|
if (h->model() == IHDRChunk::DYuv) {
|
||||||
return FORMAT_RGB_8BIT;
|
return FORMAT_RGB_8BIT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1938,7 +1940,7 @@ QImage RGBAChunk::compressedTile(QIODevice *d, const TBHDChunk *header) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (bpc == 2) {
|
} else if (bpc == 2) {
|
||||||
auto cs = header->channels();
|
auto cs = std::max(1, header->channels());
|
||||||
if (cs < 4) { // alpha on 64-bit images must be 0xFF
|
if (cs < 4) { // alpha on 64-bit images must be 0xFF
|
||||||
std::memset(img.bits(), 0xFF, img.sizeInBytes());
|
std::memset(img.bits(), 0xFF, img.sizeInBytes());
|
||||||
}
|
}
|
||||||
@@ -2512,7 +2514,7 @@ IHDRChunk::Yuv IHDRChunk::yuvStart() const
|
|||||||
if (!isValid()) {
|
if (!isValid()) {
|
||||||
return{};
|
return{};
|
||||||
}
|
}
|
||||||
return(Yuv(data().at(11), data().at(12), data().at(13)));
|
return Yuv(data().at(11), data().at(12), data().at(13));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IHDRChunk::innerReadStructure(QIODevice *d)
|
bool IHDRChunk::innerReadStructure(QIODevice *d)
|
||||||
@@ -2683,6 +2685,44 @@ QList<QRgb> PLTEChunk::innerPalette() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ******************
|
||||||
|
* *** YUVS Chunk ***
|
||||||
|
* ****************** */
|
||||||
|
|
||||||
|
YUVSChunk::~YUVSChunk()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
YUVSChunk::YUVSChunk()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool YUVSChunk::isValid() const
|
||||||
|
{
|
||||||
|
return chunkId() == YUVSChunk::defaultChunkId();
|
||||||
|
}
|
||||||
|
|
||||||
|
qint32 YUVSChunk::count() const
|
||||||
|
{
|
||||||
|
return dataBytes() / 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
IHDRChunk::Yuv YUVSChunk::yuvStart(qint32 y) const
|
||||||
|
{
|
||||||
|
if (!isValid() || y >= count()) {
|
||||||
|
return{};
|
||||||
|
}
|
||||||
|
return IHDRChunk::Yuv(data().at(y * 3), data().at(y * 3 + 1), data().at(y * 3 + 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool YUVSChunk::innerReadStructure(QIODevice *d)
|
||||||
|
{
|
||||||
|
return cacheData(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ******************
|
/* ******************
|
||||||
* *** IDAT Chunk ***
|
* *** IDAT Chunk ***
|
||||||
* ****************** */
|
* ****************** */
|
||||||
@@ -2721,9 +2761,8 @@ inline IPARChunk::Rgb yuvToRgb(IHDRChunk::Yuv yuv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QByteArray IDATChunk::strideRead(QIODevice *d, qint32 y, const IHDRChunk *header, const IPARChunk *params) const
|
QByteArray IDATChunk::strideRead(QIODevice *d, qint32 y, const IHDRChunk *header, const IPARChunk *params, const YUVSChunk *yuvs) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(y)
|
|
||||||
Q_UNUSED(params)
|
Q_UNUSED(params)
|
||||||
if (!isValid() || header == nullptr || d == nullptr) {
|
if (!isValid() || header == nullptr || d == nullptr) {
|
||||||
return {};
|
return {};
|
||||||
@@ -2765,6 +2804,10 @@ QByteArray IDATChunk::strideRead(QIODevice *d, qint32 y, const IHDRChunk *header
|
|||||||
};
|
};
|
||||||
|
|
||||||
auto yuv = header->yuvStart();
|
auto yuv = header->yuvStart();
|
||||||
|
if (header->yuvKind() == IHDRChunk::Each && yuvs) {
|
||||||
|
yuv = yuvs->yuvStart(y);
|
||||||
|
}
|
||||||
|
|
||||||
QByteArray tmp(header->width() * 3, char());
|
QByteArray tmp(header->width() * 3, char());
|
||||||
for (auto x = 0, w = header->width() - 1; x < w; x += 2) {
|
for (auto x = 0, w = header->width() - 1; x < w; x += 2) {
|
||||||
// nibble order from Green Book Cap. V Par. 6.5.1.1
|
// nibble order from Green Book Cap. V Par. 6.5.1.1
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ Q_DECLARE_LOGGING_CATEGORY(LOG_IFFPLUGIN)
|
|||||||
#define IPAR_CHUNK QByteArray("IPAR")
|
#define IPAR_CHUNK QByteArray("IPAR")
|
||||||
#define PLTE_CHUNK QByteArray("PLTE")
|
#define PLTE_CHUNK QByteArray("PLTE")
|
||||||
#define XBMI_CHUNK QByteArray("XBMI")
|
#define XBMI_CHUNK QByteArray("XBMI")
|
||||||
|
#define YUVS_CHUNK QByteArray("YUVS")
|
||||||
|
|
||||||
// Different palette for scanline
|
// Different palette for scanline
|
||||||
#define BEAM_CHUNK QByteArray("BEAM")
|
#define BEAM_CHUNK QByteArray("BEAM")
|
||||||
@@ -1630,6 +1631,31 @@ protected:
|
|||||||
virtual QList<QRgb> innerPalette() const override;
|
virtual QList<QRgb> innerPalette() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief The YUVSChunk class
|
||||||
|
*/
|
||||||
|
class YUVSChunk : public IFFChunk
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~YUVSChunk() override;
|
||||||
|
YUVSChunk();
|
||||||
|
YUVSChunk(const YUVSChunk& other) = default;
|
||||||
|
YUVSChunk& operator =(const YUVSChunk& other) = default;
|
||||||
|
|
||||||
|
virtual bool isValid() const override;
|
||||||
|
|
||||||
|
qint32 count() const;
|
||||||
|
|
||||||
|
IHDRChunk::Yuv yuvStart(qint32 y) const;
|
||||||
|
|
||||||
|
CHUNKID_DEFINE(YUVS_CHUNK)
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual bool innerReadStructure(QIODevice *d) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief The IDATChunk class
|
* \brief The IDATChunk class
|
||||||
*/
|
*/
|
||||||
@@ -1657,7 +1683,8 @@ public:
|
|||||||
QByteArray strideRead(QIODevice *d,
|
QByteArray strideRead(QIODevice *d,
|
||||||
qint32 y,
|
qint32 y,
|
||||||
const IHDRChunk *header,
|
const IHDRChunk *header,
|
||||||
const IPARChunk *params = nullptr) const;
|
const IPARChunk *params = nullptr,
|
||||||
|
const YUVSChunk *yuvs = nullptr) const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief resetStrideRead
|
* \brief resetStrideRead
|
||||||
|
|||||||
@@ -334,7 +334,6 @@ bool IFFHandler::readStandardImage(QImage *image)
|
|||||||
// show the first one (I don't have a sample with many images)
|
// show the first one (I don't have a sample with many images)
|
||||||
auto headers = IFFChunk::searchT<BMHDChunk>(form);
|
auto headers = IFFChunk::searchT<BMHDChunk>(form);
|
||||||
if (headers.isEmpty()) {
|
if (headers.isEmpty()) {
|
||||||
qCWarning(LOG_IFFPLUGIN) << "IFFHandler::readStandardImage(): no supported image found";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,7 +432,6 @@ bool IFFHandler::readMayaImage(QImage *image)
|
|||||||
// show the first one (I don't have a sample with many images)
|
// show the first one (I don't have a sample with many images)
|
||||||
auto headers = IFFChunk::searchT<TBHDChunk>(form);
|
auto headers = IFFChunk::searchT<TBHDChunk>(form);
|
||||||
if (headers.isEmpty()) {
|
if (headers.isEmpty()) {
|
||||||
qCWarning(LOG_IFFPLUGIN) << "IFFHandler::readMayaImage(): no supported image found";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,7 +492,6 @@ bool IFFHandler::readCDIImage(QImage *image)
|
|||||||
// show the first one (I don't have a sample with many images)
|
// show the first one (I don't have a sample with many images)
|
||||||
auto headers = IFFChunk::searchT<IHDRChunk>(form);
|
auto headers = IFFChunk::searchT<IHDRChunk>(form);
|
||||||
if (headers.isEmpty()) {
|
if (headers.isEmpty()) {
|
||||||
qCWarning(LOG_IFFPLUGIN) << "IFFHandler::readCDIImage(): no supported image found";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -525,9 +522,12 @@ bool IFFHandler::readCDIImage(QImage *image)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto pars = IFFChunk::searchT<IPARChunk>(form);
|
auto pars = IFFChunk::searchT<IPARChunk>(form);
|
||||||
|
auto yuvs = IFFChunk::searchT<YUVSChunk>(form);
|
||||||
for (auto y = 0, h = img.height(); y < h; ++y) {
|
for (auto y = 0, h = img.height(); y < h; ++y) {
|
||||||
auto line = reinterpret_cast<char*>(img.scanLine(y));
|
auto line = reinterpret_cast<char*>(img.scanLine(y));
|
||||||
auto ba = body->strideRead(device(), y, header, pars.isEmpty() ? nullptr : pars.first());
|
auto ba = body->strideRead(device(), y, header,
|
||||||
|
pars.isEmpty() ? nullptr : pars.first(),
|
||||||
|
yuvs.isEmpty() ? nullptr : yuvs.first());
|
||||||
if (ba.isEmpty()) {
|
if (ba.isEmpty()) {
|
||||||
qCWarning(LOG_IFFPLUGIN) << "IFFHandler::readCDIImage(): error while reading image scanline";
|
qCWarning(LOG_IFFPLUGIN) << "IFFHandler::readCDIImage(): error while reading image scanline";
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user