mirror of
https://invent.kde.org/frameworks/kimageformats.git
synced 2026-03-21 15:29:47 -04:00
IFF: add support for CD-i YUVS chunk (and minor code improvements)
This commit is contained in:
@ -337,6 +337,8 @@ IFFChunk::ChunkList IFFChunk::innerFromDevice(QIODevice *d, bool *ok, IFFChunk *
|
||||
chunk = QSharedPointer<IFFChunk>(new XBMIChunk());
|
||||
} else if (cid == XMP0_CHUNK) {
|
||||
chunk = QSharedPointer<IFFChunk>(new XMP0Chunk());
|
||||
} else if (cid == YUVS_CHUNK) {
|
||||
chunk = QSharedPointer<IFFChunk>(new YUVSChunk());
|
||||
} else { // unknown chunk
|
||||
chunk = QSharedPointer<IFFChunk>(new IFFChunk());
|
||||
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 bitplanes = header->bitplanes();
|
||||
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);
|
||||
}
|
||||
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();
|
||||
@ -1488,13 +1490,13 @@ QImage::Format FORMChunk::cdiFormat() const
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if (h->model() == IHDRChunk::Rgb888) { // no test case
|
||||
return FORMAT_RGB_8BIT;
|
||||
}
|
||||
if (h->model() == IHDRChunk::DYuv && h->yuvKind() == IHDRChunk::One) {
|
||||
if (h->model() == IHDRChunk::DYuv) {
|
||||
return FORMAT_RGB_8BIT;
|
||||
}
|
||||
}
|
||||
@ -1938,7 +1940,7 @@ QImage RGBAChunk::compressedTile(QIODevice *d, const TBHDChunk *header) const
|
||||
}
|
||||
}
|
||||
} 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
|
||||
std::memset(img.bits(), 0xFF, img.sizeInBytes());
|
||||
}
|
||||
@ -2512,7 +2514,7 @@ IHDRChunk::Yuv IHDRChunk::yuvStart() const
|
||||
if (!isValid()) {
|
||||
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)
|
||||
@ -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 ***
|
||||
* ****************** */
|
||||
@ -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)
|
||||
if (!isValid() || header == nullptr || d == nullptr) {
|
||||
return {};
|
||||
@ -2765,6 +2804,10 @@ QByteArray IDATChunk::strideRead(QIODevice *d, qint32 y, const IHDRChunk *header
|
||||
};
|
||||
|
||||
auto yuv = header->yuvStart();
|
||||
if (header->yuvKind() == IHDRChunk::Each && yuvs) {
|
||||
yuv = yuvs->yuvStart(y);
|
||||
}
|
||||
|
||||
QByteArray tmp(header->width() * 3, char());
|
||||
for (auto x = 0, w = header->width() - 1; x < w; x += 2) {
|
||||
// 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 PLTE_CHUNK QByteArray("PLTE")
|
||||
#define XBMI_CHUNK QByteArray("XBMI")
|
||||
#define YUVS_CHUNK QByteArray("YUVS")
|
||||
|
||||
// Different palette for scanline
|
||||
#define BEAM_CHUNK QByteArray("BEAM")
|
||||
@ -1630,6 +1631,31 @@ protected:
|
||||
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
|
||||
*/
|
||||
@ -1657,7 +1683,8 @@ public:
|
||||
QByteArray strideRead(QIODevice *d,
|
||||
qint32 y,
|
||||
const IHDRChunk *header,
|
||||
const IPARChunk *params = nullptr) const;
|
||||
const IPARChunk *params = nullptr,
|
||||
const YUVSChunk *yuvs = nullptr) const;
|
||||
|
||||
/*!
|
||||
* \brief resetStrideRead
|
||||
|
||||
@ -334,7 +334,6 @@ bool IFFHandler::readStandardImage(QImage *image)
|
||||
// show the first one (I don't have a sample with many images)
|
||||
auto headers = IFFChunk::searchT<BMHDChunk>(form);
|
||||
if (headers.isEmpty()) {
|
||||
qCWarning(LOG_IFFPLUGIN) << "IFFHandler::readStandardImage(): no supported image found";
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -433,7 +432,6 @@ bool IFFHandler::readMayaImage(QImage *image)
|
||||
// show the first one (I don't have a sample with many images)
|
||||
auto headers = IFFChunk::searchT<TBHDChunk>(form);
|
||||
if (headers.isEmpty()) {
|
||||
qCWarning(LOG_IFFPLUGIN) << "IFFHandler::readMayaImage(): no supported image found";
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -494,7 +492,6 @@ bool IFFHandler::readCDIImage(QImage *image)
|
||||
// show the first one (I don't have a sample with many images)
|
||||
auto headers = IFFChunk::searchT<IHDRChunk>(form);
|
||||
if (headers.isEmpty()) {
|
||||
qCWarning(LOG_IFFPLUGIN) << "IFFHandler::readCDIImage(): no supported image found";
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -525,9 +522,12 @@ bool IFFHandler::readCDIImage(QImage *image)
|
||||
return false;
|
||||
}
|
||||
auto pars = IFFChunk::searchT<IPARChunk>(form);
|
||||
auto yuvs = IFFChunk::searchT<YUVSChunk>(form);
|
||||
for (auto y = 0, h = img.height(); y < h; ++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()) {
|
||||
qCWarning(LOG_IFFPLUGIN) << "IFFHandler::readCDIImage(): error while reading image scanline";
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user