From 99e4223393eb7ee74c02526fc3fac936d60bad57 Mon Sep 17 00:00:00 2001 From: Mirco Miranda Date: Thu, 15 Jan 2026 12:39:16 +0100 Subject: [PATCH] IFF: add support for CD-i YUVS chunk (and minor code improvements) --- README.md | 8 ++- autotests/read/iff/cdi_dyuv_each.iff | Bin 0 -> 16848 bytes autotests/read/iff/cdi_dyuv_each.iff.json | 9 ++++ autotests/read/iff/cdi_dyuv_each.png | Bin 0 -> 5355 bytes autotests/read/iff/cdi_dyuv_one.iff | Bin 0 -> 16456 bytes autotests/read/iff/cdi_dyuv_one.png | Bin 0 -> 5351 bytes src/imageformats/chunks.cpp | 59 +++++++++++++++++++--- src/imageformats/chunks_p.h | 29 ++++++++++- src/imageformats/iff.cpp | 8 +-- 9 files changed, 98 insertions(+), 15 deletions(-) create mode 100644 autotests/read/iff/cdi_dyuv_each.iff create mode 100644 autotests/read/iff/cdi_dyuv_each.iff.json create mode 100644 autotests/read/iff/cdi_dyuv_each.png create mode 100644 autotests/read/iff/cdi_dyuv_one.iff create mode 100644 autotests/read/iff/cdi_dyuv_one.png diff --git a/README.md b/README.md index 574daac..1c1f971 100644 --- a/README.md +++ b/README.md @@ -357,11 +357,15 @@ The plugin supports the following image data: type 4. - FORM PBM: PBM is a chunky version of IFF pictures. It supports 8-bit images with color map only. -- FORM IMAG (Compact Disc-Interactive): It supports CLut4, CLut8 and DYuv - formats. +- FORM IMAG (Compact Disc-Interactive): It supports CLut4, CLut7, CLut8 and + DYuv formats. - FOR4 CIMG (Maya Image File Format): It supports 24/48-bit RGB and 32/64-bit 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 **This plugin can be disabled by setting `KIMAGEFORMATS_JP2` to `OFF` diff --git a/autotests/read/iff/cdi_dyuv_each.iff b/autotests/read/iff/cdi_dyuv_each.iff new file mode 100644 index 0000000000000000000000000000000000000000..3dc7d7dc90a1cf432e07e778c60ad39d942f2c68 GIT binary patch literal 16848 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 C1O5j9 literal 0 HcmV?d00001 diff --git a/autotests/read/iff/cdi_dyuv_one.png b/autotests/read/iff/cdi_dyuv_one.png new file mode 100644 index 0000000000000000000000000000000000000000..7f400175a03561e308bc4f5865651576f5fe23d6 GIT binary patch literal 5351 zcmW+)1z3~c7ydTj#~59LI$#V?O1cGsfignMAtDk|GNdF&k4Xtgx5NMmQ9xP|7>d%N zAgy#rNvCZ7=l^|fJl}opbK^Vbp7Wmb%-B$e5qb#<005&dO52pu?NILf7T z)Q>c8YXU%x%XF^)9sqy{7%eShZ&Mv4+|C!{>TnI?4glEP%9K|94r7iliDs-XO*Lsb zlNr_>G&y3G(l2ZlF}X$FwHg*A;jS?1#&MW`Y?y<`&Rsp>D=(fChv50(hK32T2-LIH z5@cNci{o9dupcen`(86ts>}g5o37(=?i`iQf`URReWv4LQ*(>l+SP9+R*gSGyiqqv@9y0mt|hv-%Yww1z=}>AysSh} z3%(L7XK+ES#DJ>o(!HMhD#|EcGq;;k#Bf~2<^FuNy*K%iPdwaX)DK)bP2&S%ytx&M zV&K$tB56rlyrSp*|FybSz3}mk6E-g1!4xsX#WK_i+u=vqKDhK_#^e)Jdlyv6XRc*s zWiCHk`3d`zPiDGsRo4jjpX6?9b-m&RZ5g$fn2d8V;j)>>#15x^-I$vO2CLQ^zAJdP z(J`pz)Czql@iR11VQk6U>rT;_W&GM|y1#R*marXuqLTRg(!?Z9=lhwavmxGucg@^+ zb!*xG+nrLk9R$hoJtjo83w*NQJdkz5!k=P6$w87~xDqOL_qNkE(+U$pt!8&s# zda@QT#~Pm@#qzSzm>~b4Z128vc*QMag#;Q735N0pMxhMR>Iaj_mhA*Lr5cT=dT&#H zqT_`l#mvyCYmRz4GXwn_eBKYPZO8eyEb`p^%}hHlr}&}eh2r(?)&NDqt zLyGMgHGc#P7zFG3CdbI?C|~e4^z;z3^E7Fl9ZKko0GCT^kNf^rKkckd>Sg=R=+gO! zmI>x*Wo}lMZkgd|arfx?O8pNhh7mcdabL>CC~b(F!eR)7zviC!g}94R^8wc47wW|I z#}64o?xoJs09+CecK(Ev0xtUE7i4dbJb`sRG0anG2>IjJS35igzV@(Q`*Y#{k$B?_ z0*LpyU@+3R?~MBfcu#_s^JERuL}hKLzyAE`HhnZVHy0<__Nys|1@VYEho{l4Pq8ga z(yG~KZMfu~_{!yl(XtG^d*g?B*Zr$(h~)lk*=i#BY-h()knI&R%*V=qwk>44_1N0d za$0ssb>zp7T!SlInE*q_M2&sd($W%{^hce1vMB#}44ZF0%p>|mU$RwBMWxxkE8+QN zMFj-~(O5)RNkvcbl$PwSdgj%H zb-H$`c(kbR`NZ_>u@82X4(&t zoV0xVb`t`TJvQk?C@a%3ljW>*w5XkBN3IytRa-XwZu|2)Xscm7f<>|DaUM#L38wUQ zbd)o(Yhz<$6(u{A4m5xG5FH&o8*=3|><2q(~GDO*E3O zzg|})y9c4?Ij)MZi87|_mA?cGMpWl>$pxUMLvNRjRdhP=CDI-YYQMVLX>`8b-Ng64 ztYjWqmOBFVsg9+a8{%6(+1cS`@`bG{X)9~9qH`amhAgL|1g*)tL%+#^iZqdEME*Ur zD!hPiXPtd0FrSMPawkRHc@Li()!!&obfRR>kR}Mk;CM&}>BkrCGjoQhG)zGNfg+R0 zu8a1sP;9nST1UlQGdiD_Q;EC8GP%iRl7%20AUKz)s&;fk%MXK@BZqH4)nfysc0%?V z5*z$qS8Zg;BbN86^b%+}cBlda1Ic6$f6EL`GqWr?ZQw1!!E-bNKx*wN7; zlVdU*NzX9dI8d!#B144&qre(zawK_u(D~@k7wQ40&qw?2hXwss^o^~6v*c=0N!rew ztf{-skZ(pR6qVBwgc{aescpGC`v(6|^$C|j%X$$olI&bAk#scu_(s_DQiBT8)4c!} z6K;zak z#|XeUf*9;&F1KNn5FZb;C(XH-rliM_bgbYRZVB5JeyF!n~!e+mE z_nFP*9f$7F2uMpy^Yi@NEctdZ4UVh6xKS*yI9`qt7KWTum*dI-QJh41c9TU)*1N#h zyF%(XS$poXd!Ve+(}fQ@Q5h+L{~a<2TZajW2#P?UhzD!*z_9GEDaL2hvAcA!E_GvL zV>2@|b}mt-5>kGQVfd)L9?nqg#pwc9Wf~vrtGy;`odi$j2t|#Q9AYQ+x*|IC%I}t zM-Cg$!$Rgs!F`|owx-f~nD6C=YD86~kLCyO^-%uTa&P*VPAY~DPgt3!D*S*7`k5*) zD2Qh@^CDP`pO+=Ei{2a}(jU)w4+TU$bWj@OFY(%$``GY!{6bcZq#*9?AM=P$16k%k zPASiIKi4On??wBrZ?}vL52r{vQ--aqth|r{HjzmP-4fH|nIMlg<@y%z&Z@pvZ<&UD zMuR$hwwVyD%(nNCJE|13|29-Qz3{+SQ`4)9Y6%>mE^1uC$5QXj#T~gIL^Do9bBySR zF)LwrYzOy}EK;j=y&;6wR?<>WYTEEu>I!(m;%B>>%{>?xdomx*)jv!Q_!7lFr2SImMUa?zRlh|5C@IMDaTOLPxY|rW?&8p*6!&%uocxt}C%b`f&c@y1Zeg(I zqoI5^42E*w$z!NU0hvsWPch(0x?>W7j@?{g%-ln#@2?Jxh`h|ExX%jsLT|d*(_4DN zI2Vd@QB_j<6@91$LchSO@+NkLScVxcfJ!lE``a=<JQ(ld)_oj!G`n^iiG2(sWnC5UfM6ydYO_zX6>_Baq6oP z-EUd=BfJx+g-asftFT}7cQZ2kY|w3X(;xh+56qrM-aG@&>&y! zWPczWS|}4uUk0#7!cDUz>1f6)Ei?5>@U2j<|Es#KEzWzgPgLWUbG*q%P6IrP=rU9n zZ=58Ig0PFS(Lg*uaw2Tv@%S|^sVayuwG=cSd+6)IbU$}8=9@$EdngV9B)rD3ztA(;g6Be zOHr`|<5vb$sbo3EGLGO=8a_WWGkq0?ng!>a6(vKzfZyBSM@P+emkVpdSpo>HNuoHZ zO4jAedf~(MWQL5sD;YvavpW&p{HQAi^h}y2MaBs-=~Kbn_~zzjuMBe!iEc%(NC!j| ztc-ZeamzS6#;fz4F$5v?G0Bda&R!Kshk)p@@JGT#Skq)W5hxZ-fK8hN2SI|g;V4it zLMMVQT!Rw|1C_Al7vz(2KU2MNzm|;Zu6iyN9ur>zp=`@-UrU`N+ew|geRV0Qle_!u zToiG3c+no^a4H`#q|svrp#E~^r)^)fkGR5W5*lqu41Qfv5s?<;=~8lzD_Q`BdIbyr zWX{UMg7*Y0!}sfJmvaRm1nT#M2sq0uu!v+qI^2ej_bo39>Z6gY$#kF?=);)qk`>^S za`ZuR!!YyQ@(a$oeJTh0Gjq;#$#VQFsM6{P2i!dT^+!z`ehz9jy^@*!VcIpuy4V!M zkgfnHs6vr&=y5TmdpPhWs0euVo)b-w-iNk7fptjjh1_S0Eus!nEsQtrj7)O*sAvv# zcuCLemBY^;h1WV$(@8HDwR$fe^xEkSg&KZ-#(sLE(zFdO@-%maD9#_zof|)Sfu7B_ zXktGW!e2W+#3$>Maf%1#x|0RAwzg`sp=hxvaA?D9Cdj0agBqVzx*VI0N+RVUl3qE{ z>X|?@Sd^*mr1F>7)$La{&Gcqj(wm}yn0KM1GoOt#ov+nSx!`A}NY8cUIbo$zk~Ohs z@25`aTCNR>MMH0iJ|fGsy&)K^;5za3$Bzf_?GA?7wO`+gD=RD0)plQK#8ODHm~W1_ zB}wm_Ucm(4?0JpEH3mJ?76l`ms(o2IAa#}U{*xbjhzc(vL|UfGuqz6@8j#askKiv) za+{?y#?nDvXCQhd59i$t{1V;5kow=2(rZ0FKlD`80ao)jt;-d$z9<3J=ybM}RIF;~ z>E3ceLc%AW8sXN1Z$#qmN$ZPLy|Wf#(nV=L3lAd6&T?9Gy!Bo?HGUy4y{)ZHNIxS& z*)>*kq<)bvpS8yke1m-_o8?Wr2>1)s*4f$liz4x?&r$VNims#Rx*VrC#lGfLjf{@^ ze&i`3l-QuJeH|3a>MXOV{p(aLlK49PiFp?Eg2dj_ANcN%WhZAPr&mHkLi975ULrU| z=n8PIK317ejdrPgdva3VS*#O9kX$!?L_4%0Qssrz!5QyYCsZE%bYR);G^Gke#o&#hKZ8QmK*%5MMw z7VDETSg6LaKUSGGe(+I#(C_!l`tnGWF)+;h_Q<_XoPJIL*!fb>st)w38=Z7z9G0ld zhK)jz;krUFJOC(o%$#r9@I`#ieC?C7UQOQmCGgs#3?=~ML~^}9Yb71ONFygHdc34=N4+&W3o)O#V*^&kY zI0jBYib-KfBQqWt7dB+DZ{M-&wEO2m2r%e?T{@t03dr|-c!hl?3>JKt@1dGU*x10- z=ilOb`RJ`UbR*W}cRUI?0S{F{&>wI<5ej7H^x>$JR{a3Nxb=fQ5j=o1q zD8e=H;Lo2#QZuiGTJ5<$m0s~4Jq=~6$Nyl7Dm4+m@L@6G`q?abe)uub7CB$u8)`Fr z+e^k=O#bZ8pKan_vV~>WKJ;HYKrQtABwfs0)O}@O-ZZ;dC((Vn@fwAu?YHVT`{loN z8Lgk68QE8CEA02d3^Sv3RDT#<&N>nez_H6y?S;gdM z9LLj&is?qT%RK)u>f74h{HqsnY}-Q&I@y{3q+h$5c4-^&FrG)nr@Z7J95==)nQxrT z4Jgj4`tRRtuKE`QQ!*Ik6&1A1ysqx<8IQXjD{&7Nzmg793#Sm`huD0@8~;#+xj#P| z68Y?l9VJprR6EKFUZJc*WntZ6&F64q@OEzo7)N2Pea|umZyIV>A#L&h14(new XBMIChunk()); } else if (cid == XMP0_CHUNK) { chunk = QSharedPointer(new XMP0Chunk()); + } else if (cid == YUVS_CHUNK) { + chunk = QSharedPointer(new YUVSChunk()); } else { // unknown chunk chunk = QSharedPointer(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 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 diff --git a/src/imageformats/chunks_p.h b/src/imageformats/chunks_p.h index 55391ad..94854ff 100644 --- a/src/imageformats/chunks_p.h +++ b/src/imageformats/chunks_p.h @@ -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 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 diff --git a/src/imageformats/iff.cpp b/src/imageformats/iff.cpp index 422908c..f02d7a8 100644 --- a/src/imageformats/iff.cpp +++ b/src/imageformats/iff.cpp @@ -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(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(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(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(form); + auto yuvs = IFFChunk::searchT(form); for (auto y = 0, h = img.height(); y < h; ++y) { auto line = reinterpret_cast(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;