diff --git a/autotests/read/iff/pbm_64colors.iff b/autotests/read/iff/pbm_64colors.iff new file mode 100644 index 0000000..7b847da Binary files /dev/null and b/autotests/read/iff/pbm_64colors.iff differ diff --git a/autotests/read/iff/pbm_64colors.png b/autotests/read/iff/pbm_64colors.png new file mode 100644 index 0000000..274bc77 Binary files /dev/null and b/autotests/read/iff/pbm_64colors.png differ diff --git a/src/imageformats/chunks.cpp b/src/imageformats/chunks.cpp index 8827a9a..ab71e63 100644 --- a/src/imageformats/chunks.cpp +++ b/src/imageformats/chunks.cpp @@ -1517,7 +1517,8 @@ QImage::Format FORMChunk::iffFormat() const return QImage::Format_RGBA64; } if (h->bitplanes() >= 1 && h->bitplanes() <= 8) { - if (h->bitplanes() >= BITPLANES_HAM_MIN && h->bitplanes() <= BITPLANES_HAM_MAX) { + // PBM data are chunky indexes (no HAM decoding) + if (h->bitplanes() >= BITPLANES_HAM_MIN && h->bitplanes() <= BITPLANES_HAM_MAX && formType() != PBM__FORM_TYPE) { if (modeId & CAMGChunk::ModeId::Ham) return FORMAT_RGB_8BIT; } diff --git a/src/imageformats/iff.cpp b/src/imageformats/iff.cpp index d46f094..95dd1f0 100644 --- a/src/imageformats/iff.cpp +++ b/src/imageformats/iff.cpp @@ -327,6 +327,24 @@ static QImage convertIPAL(const QImage& img, const IPALChunk *ipal) return tmp; } +/*! + * \brief copyStride + * Copies the decoded stride to an image line. + * \param img The image. + * \param y The line of the image. + * \param ba The decoded stride. + * \return False if the stride does not hold all the pixels of the line. + */ +static bool copyStride(QImage &img, qint32 y, const QByteArray &ba) +{ + // the stride must cover every pixel (bytesPerLine() may include padding) + if (ba.size() < (qsizetype(img.width()) * img.depth() + 7) / 8) { + return false; + } + memcpy(img.scanLine(y), ba.constData(), std::min(img.bytesPerLine(), ba.size())); + return true; +} + bool IFFHandler::readStandardImage(QImage *image) { auto forms = d->searchForms(); @@ -403,13 +421,11 @@ bool IFFHandler::readStandardImage(QImage *image) return false; } for (auto y = 0, h = img.height(); y < h; ++y) { - auto line = reinterpret_cast(img.scanLine(y)); auto ba = body->strideRead(device(), y, header, camg, cmap, ipal.get(), form->formType()); - if (ba.isEmpty()) { + if (!copyStride(img, y, ba)) { qCWarning(LOG_IFFPLUGIN) << "IFFHandler::readStandardImage(): error while reading image scanline"; return false; } - memcpy(line, ba.constData(), std::min(img.bytesPerLine(), ba.size())); } } @@ -442,7 +458,8 @@ bool IFFHandler::readMayaImage(QImage *image) // create the image auto &&header = headers.first(); - auto img = imageAlloc(header->size(), form->format()); + // tiles are not required to cover the whole image + auto img = imageAlloc(header->size(), form->format(), ImageInitToZero::All); if (img.isNull()) { qCWarning(LOG_IFFPLUGIN) << "IFFHandler::readMayaImage(): error while allocating the image"; return false; @@ -525,15 +542,13 @@ bool IFFHandler::readCDIImage(QImage *image) 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(), yuvs.isEmpty() ? nullptr : yuvs.first()); - if (ba.isEmpty()) { + if (!copyStride(img, y, ba)) { qCWarning(LOG_IFFPLUGIN) << "IFFHandler::readCDIImage(): error while reading image scanline"; return false; } - memcpy(line, ba.constData(), std::min(img.bytesPerLine(), ba.size())); } } @@ -588,15 +603,13 @@ bool IFFHandler::readRGFXImage(QImage *image) auto rcsms = IFFChunk::searchT(form); auto rcols = 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, rcsms.isEmpty() ? nullptr : rcsms.first(), rcols.isEmpty() ? nullptr : rcols.first()); - if (ba.isEmpty()) { + if (!copyStride(img, y, ba)) { qCWarning(LOG_IFFPLUGIN) << "IFFHandler::readRGFXImage(): error while reading image scanline"; return false; } - memcpy(line, ba.constData(), std::min(img.bytesPerLine(), ba.size())); } } @@ -651,15 +664,13 @@ bool IFFHandler::readDEEPImage(QImage *image) } auto tvdcs = 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, pels.first(), locs.isEmpty() ? nullptr : locs.first(), tvdcs.isEmpty() ? nullptr : tvdcs.first()); - if (ba.isEmpty()) { + if (!copyStride(img, y, ba)) { qCWarning(LOG_IFFPLUGIN) << "IFFHandler::readDEEPImage(): error while reading image scanline"; return false; } - memcpy(line, ba.constData(), std::min(img.bytesPerLine(), ba.size())); } }