From c96ad6ba8ae71228da2f5cd14b156dabd667150c Mon Sep 17 00:00:00 2001 From: Mirco Miranda Date: Sun, 25 Sep 2022 08:27:47 +0200 Subject: [PATCH] Fixes for sequential devices --- autotests/read/pcx/indexed8.pcx | Bin 0 -> 1377 bytes autotests/read/pcx/indexed8.png | Bin 0 -> 1575 bytes autotests/readtest.cpp | 176 +++++++++++++++++++++----------- src/imageformats/kra.cpp | 3 + src/imageformats/ora.cpp | 3 + src/imageformats/pcx.cpp | 8 +- src/imageformats/psd.cpp | 3 + src/imageformats/raw.cpp | 8 ++ src/imageformats/xcf.cpp | 3 + 9 files changed, 137 insertions(+), 67 deletions(-) create mode 100644 autotests/read/pcx/indexed8.pcx create mode 100644 autotests/read/pcx/indexed8.png diff --git a/autotests/read/pcx/indexed8.pcx b/autotests/read/pcx/indexed8.pcx new file mode 100644 index 0000000000000000000000000000000000000000..121a45e424ef85a80c41dec131ea02139a672ef7 GIT binary patch literal 1377 zcmbuo^={_WFy{`oxT{r%4G`=0YWXVHAyg*Mb$ zMP2r`_O`U2XxXl|dGe;m6Gr8u@>V$*1QO5-hQI?b3WkAzI{?HD6?Ii5fCD-}E8qbk zXa{`IPn8U|%DGfSS#VHt;U6hcjKt8-KL5r3UEkk!`o|vr{Veki8069wlHlc=qth?@ z?f7}mhDFb>S+@G=)nVB7T#BI;p^K2KqxYlR?#!ub9`}Nq~ zbB`*hDFK(N0jSNtcJa`&bD#R=YV+-ch#c09ye#V&D!Ftvd7GSyHc<4=3onHM37wBR z&Iq+Fqw@;n>>s~!$^e4`ia-!~JiJCotL>-PT>hk0ZnyZYn>6abUjNZ`8h0I^e&akC zp&M?!JZE7bkkYJjc>UFwS>FAA%eLZK{wK8foM%v3c&w z?Bs$KOJ6xL%hFA6uJZt$);!$Z?|*rCu?&8LV7Hm$AFPFl-?E3X>h~+f>(5 zP;#p>fnA#FER0`1+_ks;AJxr>IPOJ$A=FyKEUujl>G{i7^OPxlQjeuo?Gnk^nIYdGq$B!kt5GKv6?qA<5ba7W6XY+Gz z2!)QihR*i9j{ar&eKlJk!7lU8FnL0N;!?!KIZw@5KTTl1M8NLVG>D|*t%~ys#!+K% zqevl;go^oi{ZL7ftYf?biPq(mNwpzRHGj-4Y(^FbyXretoCo=B4?U9%u`G3W=8UjR z$Bae=%@5%$EjDwnCr>xX(wZ)!capHW5gAqtbvNKEDvXt-@MYPU<(~5TEmKb$IZr$R z>t#?nF6I!MDj{P#;ed~INmQ}{^~m&;s@ou#PlLud zXdqF8N@Ibh5w(JBLX40KhV`(<1dl@&RErq2n8E~`U|5SF{S_j literal 0 HcmV?d00001 diff --git a/autotests/read/pcx/indexed8.png b/autotests/read/pcx/indexed8.png new file mode 100644 index 0000000000000000000000000000000000000000..a97850026cb21fc2b13c42d86ffd16ef22e3d871 GIT binary patch literal 1575 zcmV+?2H5$DP)EX>4Tx04R}tkv&MmKpe$iQ?)7;2Ro=ZWT?7W5EXIMDionYs1;guFuC*#nlvOS zE{=k0!NHHks)LKOt`4q(Aou~|=;Wm6A|?JWDYS_7;J6>}?mh0_0YbING^=eK&~)2O z#G+yiUxS;m|s#nEzn-NVP%y9m!}eeTcEqh>4y_(bAaW|%hd2J!T! zZE)Tv4zawf5}y-~nRG$oN3JU#zj4mFEbz>bnM}+Rhls^o6Dv*3@}@>SMI2T&o$`g0 z$13M7&RVg|>i6U?3}*C|Wvu?$|#@+8xdM{QY<8BKia}S==vpcDdZ}E zkz)ZRXpmh$_#gc4*2+#!cuB!1(Ej2$AHzUk7pPSn=lj@kYA1mI8Mx9L{!$f~`6Rv4 z(85PR?>2C8-O!Xh;Bp7(e==lKb|pVeA)5u>&*+=dK;JFUz2@~+-^b|#kfg5SH^9Lm zFp{I}^%n2$Z0_yfGxh#{06a5tkrWt#EC2ukwNOk{MFT4IBqsHx5y5*U^<+4@G(_fB zLeY6g@TNe@pH78-T8eOAmBvVYfmz*CXyRjM-)?M^TXm4qQh{}A?!Z~Mm~Qoicl@_( z(RqN8K z?Svw9p^wIjn(lqAGPCGes>-XDlZvHY>4T$Ttj36{VSTWKou2yfl}xv#cGjAah_-iV zyS2TesHv`nwyKgx&Vd%&%TveW?4o#p!i&nK^TV=;r?cm7&}<~&+yLy;lE#>D%iW00 zg2cF=!M%^bz<#pM4{^}w9Q1vJ(5gV->$<_60R4oB(WL_Zh10-kozaPQ+?cV{DZI{3 zS?g-H%ABCi&N%V7$;Y3_)Dof7vNZF}OZQ54<%MkNjd0)xY69= z!|8|Vgk|+}y3y&))pgR!{kPhvrrpTm$ohQooU7dLbn~&w;a7I>-GKR0^2zML-=W0h zV2t#Bo$bt+@Xo98hzk?e&&2-((&qW{-Sd?F(!l;NuJiTB{xSXG%hl}N*6rTv=-P5P>HO*P^y~QW?eg>O|M>0n@A2;T@zwt9^xgOF*8aWW`03#M z%iH?>_VnfL_5J_x>-O{a@%YpA_3Z8U^6B~P_4NPy^z82V^XmHT>HoX>_4Dlc`SSVh z_W9!T`1|kr^zZ!X_WAbt`S1Jq{q_3&>;Cro`tbJr>i7Hp`}^|q{rK(w`1k$m{QCax z|M~d*|MLF-{QUFu{`vU+?Ed@z^Z)<*{rdU;?fd`d|NQ^?{{R2||N8&`{Qvv?|NQt< zt2Y1u010qNS#tmYE+YT{E+YYWr9XB6000McNliru<_Q@F1UVBd8RY-~0dz@3K~y-) zV|YpcFc72Q`qc}!?mxJF_S&^eJJxPpzv94&!^h4YKXv8Sb%=uNtBVW!moAx5-O^QR zZ4;rRossXAU6)+c+_B|4Si#j|F{7F(eVHDifm&PwN$b}~-hmj1Esoi|_#^a^Io zYDftWRA*si6H!fz(zS~8j7bk}y8*Kzr+4GQ%?qb@$MZ6?J5SrQp|xVp+y(PzLalgu z2k1zUgKu41rXeg^b`_}S!aX4W?sW`rZVRw?n0g&gIGnA_D&K@JppJw{`|ZT1V2uio z@*;c+wmWK?&Bmu-p9QB}`#n4gR*Exm3Q7!Hy9tDSd42%=;DY(>_kkE7q zkAhp1)6yp2!lU5kr0D2LH}NRASRyZ9auJV$W3H^MuE+2wxYJ{5+Ji5$p5EEJ_YR4< Z8vx=9AuVZ$zr+9l002ovPDHLkV1j1TnZf`7 literal 0 HcmV?d00001 diff --git a/autotests/readtest.cpp b/autotests/readtest.cpp index 6390a36..b41bdf6 100644 --- a/autotests/readtest.cpp +++ b/autotests/readtest.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -18,6 +19,44 @@ #include "fuzzyeq.cpp" +/** + * @brief The SequentialFile class + * Class to make a file a sequential device. This class is used to check if the plugins could works + * on a sequential device such as a socket. + */ +class SequentialFile : public QFile +{ +public: + SequentialFile() + : QFile() + { + } + explicit SequentialFile(const QString &name) + : QFile(name) + { + } +#ifndef QT_NO_QOBJECT + explicit SequentialFile(QObject *parent) + : QFile(parent) + { + } + SequentialFile(const QString &name, QObject *parent) + : QFile(name, parent) + { + } +#endif + + bool isSequential() const override + { + return true; + } + + qint64 size() const override + { + return bytesAvailable(); + } +}; + static void writeImageData(const char *name, const QString &filename, const QImage &image) { QFile file(filename); @@ -56,7 +95,7 @@ int main(int argc, char **argv) QCoreApplication::removeLibraryPath(QStringLiteral(PLUGIN_DIR)); QCoreApplication::addLibraryPath(QStringLiteral(PLUGIN_DIR)); QCoreApplication::setApplicationName(QStringLiteral("readtest")); - QCoreApplication::setApplicationVersion(QStringLiteral("1.0.0")); + QCoreApplication::setApplicationVersion(QStringLiteral("1.1.0")); QCommandLineParser parser; parser.setApplicationDescription(QStringLiteral("Performs basic image conversion checking.")); @@ -98,6 +137,7 @@ int main(int argc, char **argv) int passed = 0; int failed = 0; + int skipped = 0; QTextStream(stdout) << "********* " << "Starting basic read tests for " << suffix << " images *********\n"; @@ -111,72 +151,88 @@ int main(int argc, char **argv) QTextStream(stdout) << "QImageReader::supportedImageFormats: " << formatStrings.join(", ") << "\n"; const QFileInfoList lstImgDir = imgdir.entryInfoList(); - for (const QFileInfo &fi : lstImgDir) { - if (!fi.suffix().compare("png", Qt::CaseInsensitive)) { - continue; - } - int suffixPos = fi.filePath().count() - suffix.count(); - QString inputfile = fi.filePath(); - QString expfile = fi.filePath().replace(suffixPos, suffix.count(), QStringLiteral("png")); - QString expfilename = QFileInfo(expfile).fileName(); - - QImageReader inputReader(inputfile, format); - QImageReader expReader(expfile, "png"); - - QImage inputImage; - QImage expImage; - - if (!expReader.read(&expImage)) { - QTextStream(stdout) << "ERROR: " << fi.fileName() << ": could not load " << expfilename << ": " << expReader.errorString() << "\n"; - ++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: " << inputReader.errorString() << "\n"; - ++failed; - continue; - } - if (expImage.width() != inputImage.width()) { - QTextStream(stdout) << "FAIL : " << fi.fileName() << ": width was " << inputImage.width() << " but " << expfilename << " width was " - << expImage.width() << "\n"; - ++failed; - } else if (expImage.height() != inputImage.height()) { - QTextStream(stdout) << "FAIL : " << fi.fileName() << ": height was " << inputImage.height() << " but " << expfilename << " height was " - << expImage.height() << "\n"; - ++failed; + // Launch 2 runs for each test: first run on a random device, second run on a sequential device + for (int seq = 0; seq < 2; ++seq) { + if (seq) { + QTextStream(stdout) << "* Run on SEQUENTIAL device (SKIP = no sequential support and it's OK)\n"; } else { - QImage::Format inputFormat = preferredFormat(inputImage.format()); - QImage::Format expFormat = preferredFormat(expImage.format()); - QImage::Format cmpFormat = inputFormat == expFormat ? inputFormat : QImage::Format_ARGB32; + QTextStream(stdout) << "* Run on RANDOM device\n"; + } + for (const QFileInfo &fi : lstImgDir) { + if (!fi.suffix().compare("png", Qt::CaseInsensitive)) { + continue; + } + int suffixPos = fi.filePath().count() - suffix.count(); + QString inputfile = fi.filePath(); + QString expfile = fi.filePath().replace(suffixPos, suffix.count(), QStringLiteral("png")); + QString expfilename = QFileInfo(expfile).fileName(); - if (inputImage.format() != cmpFormat) { - QTextStream(stdout) << "INFO : " << fi.fileName() << ": converting " << fi.fileName() << " from " << formatToString(inputImage.format()) - << " to " << formatToString(cmpFormat) << '\n'; - inputImage = inputImage.convertToFormat(cmpFormat); - } - if (expImage.format() != cmpFormat) { - QTextStream(stdout) << "INFO : " << fi.fileName() << ": converting " << expfilename << " from " << formatToString(expImage.format()) << " to " - << formatToString(cmpFormat) << '\n'; - expImage = expImage.convertToFormat(cmpFormat); - } - if (fuzzyeq(inputImage, expImage, fuzziness)) { - QTextStream(stdout) << "PASS : " << fi.fileName() << "\n"; - ++passed; - } else { - QTextStream(stdout) << "FAIL : " << fi.fileName() << ": differs from " << expfilename << "\n"; - writeImageData("expected data", fi.fileName() + QLatin1String("-expected.data"), expImage); - writeImageData("actual data", fi.fileName() + QLatin1String("-actual.data"), inputImage); + std::unique_ptr inputDevice(seq ? new SequentialFile(inputfile) : new QFile(inputfile)); + QImageReader inputReader(inputDevice.get(), format); + QImageReader expReader(expfile, "png"); + + QImage inputImage; + QImage expImage; + + if (!expReader.read(&expImage)) { + QTextStream(stdout) << "ERROR: " << fi.fileName() << ": could not load " << expfilename << ": " << expReader.errorString() << "\n"; ++failed; + continue; + } + if (!inputReader.canRead()) { + // All plugins must pass the test on a random device. + // canRead() must also return false if the plugin is unable to run on a sequential device. + if (inputDevice->isSequential()) { + QTextStream(stdout) << "SKIP : " << fi.fileName() << ": cannot read on a sequential device\n"; + ++skipped; + } else { + 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: " << inputReader.errorString() << "\n"; + ++failed; + continue; + } + if (expImage.width() != inputImage.width()) { + QTextStream(stdout) << "FAIL : " << fi.fileName() << ": width was " << inputImage.width() << " but " << expfilename << " width was " + << expImage.width() << "\n"; + ++failed; + } else if (expImage.height() != inputImage.height()) { + QTextStream(stdout) << "FAIL : " << fi.fileName() << ": height was " << inputImage.height() << " but " << expfilename << " height was " + << expImage.height() << "\n"; + ++failed; + } else { + QImage::Format inputFormat = preferredFormat(inputImage.format()); + QImage::Format expFormat = preferredFormat(expImage.format()); + QImage::Format cmpFormat = inputFormat == expFormat ? inputFormat : QImage::Format_ARGB32; + + if (inputImage.format() != cmpFormat) { + QTextStream(stdout) << "INFO : " << fi.fileName() << ": converting " << fi.fileName() << " from " << formatToString(inputImage.format()) + << " to " << formatToString(cmpFormat) << '\n'; + inputImage = inputImage.convertToFormat(cmpFormat); + } + if (expImage.format() != cmpFormat) { + QTextStream(stdout) << "INFO : " << fi.fileName() << ": converting " << expfilename << " from " << formatToString(expImage.format()) + << " to " << formatToString(cmpFormat) << '\n'; + expImage = expImage.convertToFormat(cmpFormat); + } + if (fuzzyeq(inputImage, expImage, fuzziness)) { + QTextStream(stdout) << "PASS : " << fi.fileName() << "\n"; + ++passed; + } else { + QTextStream(stdout) << "FAIL : " << fi.fileName() << ": differs from " << expfilename << "\n"; + writeImageData("expected data", fi.fileName() + QLatin1String("-expected.data"), expImage); + writeImageData("actual data", fi.fileName() + QLatin1String("-actual.data"), inputImage); + ++failed; + } } } } - QTextStream(stdout) << "Totals: " << passed << " passed, " << failed << " failed\n"; + QTextStream(stdout) << "Totals: " << passed << " passed, " << skipped << " skipped, " << failed << " failed\n"; QTextStream(stdout) << "********* " << "Finished basic read tests for " << suffix << " images *********\n"; diff --git a/src/imageformats/kra.cpp b/src/imageformats/kra.cpp index a5e75ca..fff976c 100644 --- a/src/imageformats/kra.cpp +++ b/src/imageformats/kra.cpp @@ -57,6 +57,9 @@ bool KraHandler::canRead(QIODevice *device) qWarning("KraHandler::canRead() called with no device"); return false; } + if (device->isSequential()) { + return false; + } char buff[57]; if (device->peek(buff, sizeof(buff)) == sizeof(buff)) { diff --git a/src/imageformats/ora.cpp b/src/imageformats/ora.cpp index 96290e8..79c5353 100644 --- a/src/imageformats/ora.cpp +++ b/src/imageformats/ora.cpp @@ -56,6 +56,9 @@ bool OraHandler::canRead(QIODevice *device) qWarning("OraHandler::canRead() called with no device"); return false; } + if (device->isSequential()) { + return false; + } char buff[54]; if (device->peek(buff, sizeof(buff)) == sizeof(buff)) { diff --git a/src/imageformats/pcx.cpp b/src/imageformats/pcx.cpp index e9b0a23..477c3cc 100644 --- a/src/imageformats/pcx.cpp +++ b/src/imageformats/pcx.cpp @@ -174,7 +174,7 @@ static QDataStream &operator>>(QDataStream &s, PCXHEADER &ph) // Skip the rest of the header quint8 byte; - while (s.device()->pos() < 128) { + for (auto i = 0; i < 54; ++i) { s >> byte; } @@ -684,12 +684,6 @@ bool PCXHandler::canRead(QIODevice *device) return false; } - // We do not support sequential images - // We need to know the current position to properly read the header - if (device->isSequential()) { - return false; - } - qint64 oldPos = device->pos(); char head[1]; diff --git a/src/imageformats/psd.cpp b/src/imageformats/psd.cpp index 80a61b2..1c7d263 100644 --- a/src/imageformats/psd.cpp +++ b/src/imageformats/psd.cpp @@ -1249,6 +1249,9 @@ bool PSDHandler::canRead(QIODevice *device) qWarning("PSDHandler::canRead() called with no device"); return false; } + if (device->isSequential()) { + return false; + } qint64 oldPos = device->pos(); diff --git a/src/imageformats/raw.cpp b/src/imageformats/raw.cpp index 5151489..8ec8bc2 100644 --- a/src/imageformats/raw.cpp +++ b/src/imageformats/raw.cpp @@ -855,6 +855,14 @@ int RAWHandler::currentImageNumber() const bool RAWHandler::canRead(QIODevice *device) { + if (!device) { + qWarning("RAWHandler::canRead() called with no device"); + return false; + } + if (device->isSequential()) { + return false; + } + device->startTransaction(); std::unique_ptr rawProcessor(new LibRaw); diff --git a/src/imageformats/xcf.cpp b/src/imageformats/xcf.cpp index 9885452..fa04267 100644 --- a/src/imageformats/xcf.cpp +++ b/src/imageformats/xcf.cpp @@ -3341,6 +3341,9 @@ bool XCFHandler::canRead(QIODevice *device) qCDebug(XCFPLUGIN) << "XCFHandler::canRead() called with no device"; return false; } + if (device->isSequential()) { + return false; + } qint64 oldPos = device->pos();