我想阅读和显示数码相机图片的缩略图版本。我目前使用QImageReader,它具有我需要的2个功能,但它们似乎不是最佳地交互...:

  • setScaledSize
  • setAutoTransform

  • 我想基于EXIF属性旋转后加载并显示宽度为100像素的图像。但是,发生的事情是这样的:

    码:
    QImageReader imageReader(filepath);
    auto origSize1 = imageReader.size();
    imageReader.setAutoTransform(true);
    auto origSize2 = imageReader.size();
    auto scaledSize1 = origSize1.scaled(QSize(100, 1000), Qt::KeepAspectRatio);
    auto scaledSize2 = origSize2.scaled(QSize(100, 1000), Qt::KeepAspectRatio);
    imageReader.setScaledSize(scaledSize2);
    auto qimage = imageReader.read();
    auto imageSize = qimage.size();
    auto qimageScaled = qimage.scaledToWidth(100, Qt::SmoothTransformation);
    auto scaledSize3 = qimageScaled.size();
    
    std::cout << "  origSize1 = (" << origSize1.width() << ", " << origSize1.height() << ")" << std::endl;
    std::cout << "  origSize2 = (" << origSize2.width() << ", " << origSize2.height() << ")" << std::endl;
    std::cout << "scaledSize1 = (" << scaledSize1.width() << ", " << scaledSize1.height() << ")" << std::endl;
    std::cout << "scaledSize2 = (" << scaledSize2.width() << ", " << scaledSize2.height() << ")" << std::endl;
    std::cout << "  imageSize = (" << imageSize.width() << ", " << imageSize.height() << ")" << std::endl;
    std::cout << "scaledSize3 = (" << scaledSize3.width() << ", " << scaledSize3.height() << ")" << std::endl;
    

    输出:
      origSize1 = (4896, 3672)
      origSize2 = (4896, 3672)
    scaledSize1 = (100, 75)
    scaledSize2 = (100, 75)
      imageSize = (75, 100)
    scaledSize3 = (100, 134)
    

    因此,在横向模式下以100像素的宽度读取图像,然后应用自动旋转,从而得到只有75像素宽和100像素高的纵向模式图像。额外的scaledToWidth()调用需要确保将图像设置为正确的大小,但是由于x1.34缩放,质量非常差。

    看来我可以用两倍(或三倍,或...)所需的分辨率调用setScaledSize,以获得足够的质量,然后依靠附加的scaledToWidth()调用来获取正确的最终宽度。

    更好的方法似乎是使用QImageReader::transformation()信息,并使用它来交换传递给setScaledSize的size对象中的宽度/高度:

    修改后的代码:
    QImageReader imageReader(filepath);
    auto origSize1 = imageReader.size();
    imageReader.setAutoTransform(true);
    auto transformation = imageReader.transformation();
    auto swapWH = transformation.testFlag(QImageIOHandler::TransformationRotate90);
    auto swappedSize = swapWH ? origSize1.transposed() : origSize1;
    auto scaledSwappedSize = swappedSize.scaled(QSize(100, 1000), Qt::KeepAspectRatio);
    imageReader.setScaledSize(scaledSwappedSize);
    auto qimage = imageReader.read();
    auto imageSize = qimage.size();
    auto qimageScaled = qimage.scaledToWidth(100, Qt::SmoothTransformation);
    auto scaledSize3 = qimageScaled.size();
    

    使用此修改后的代码输出:
      origSize1 = (4896, 3672)
    transformation = 7
    swap width/height? = 1
    swappedSize = (3672, 4896)
    scaledSwapp = (100, 133)
      imageSize = (133, 100)
    scaledSize3 = (100, 76)
    

    如您所见,我仍然得到一个风景型的图像。内容为纵向模式,但水平拉伸(stretch)(使每个人都胖)。因此,100x133的分辨率是可以的,但是我需要向setScaledSize()提供133x100才能获得“正常”结果:
    QImageReader imageReader(filepath);
    auto origSize1 = imageReader.size();
    imageReader.setAutoTransform(true);
    auto transformation = imageReader.transformation();
    auto swapWH = transformation.testFlag(QImageIOHandler::TransformationRotate90);
    auto swappedSize = swapWH ? origSize1.transposed() : origSize1;
    auto scaledSwappedSize = swappedSize.scaled(QSize(100, 1000), Qt::KeepAspectRatio);
    auto swappedScaledSwappedSize = swapWH ? scaledSwappedSize.transposed() : scaledSwappedSize;
    imageReader.setScaledSize(swappedScaledSwappedSize);
    auto qimage = imageReader.read();
    auto imageSize = qimage.size();
    auto qimageScaled = qimage.scaledToWidth(100, Qt::SmoothTransformation);
    auto scaledSize3 = qimageScaled.size();
    

    现在,我得到“正确”的结果(请注意,imagesize == scaledSize3):
      origSize1 = (4896, 3672)
    transformation = 7
    swap width/height? = 1
    swappedSize = (3672, 4896)
    scaledSwapp = (100, 133)
    swpSclSwapp = (133, 100)
      imageSize = (100, 133)
    scaledSize3 = (100, 133)
    

    因此,我可以使用它,但是我感觉我做的代码太多了。这是预期的行为吗?是否有更简单的方法来获得此结果?

    最佳答案

    AFAIK没有内置方法(请参见下面的原因)。

    我目前使用的方法遇到的问题是,在尝试使用内置缩放功能时,它过于复杂。相反,我建议您使用更容易阅读的内容,例如:

    QImageReader imageReader(filepath);
    imageReader.setAutoTransform(true);
    const auto qimage = imageReader.read();
    const auto qscaledImage = qimage.scaledToWidth(100, Qt::SmoothTransformation);
    

    (请参阅底部的一个案例)

    说明

    读取QImageReader::read(<qt_src_dir>/src/gui/image/qimagereader.cpp)的源代码,该方法首先读取图像,然后缩放图像,然后应用转换:
    bool QImageReader::read(QImage *image)
    {
        // [...]
    
        // read the image
        if (!d->handler->read(image)) {
            d->imageReaderError = InvalidDataError;
            d->errorString = QImageReader::tr("Unable to read image data");
            return false;
        }
    
        // provide default implementations for any unsupported image
        // options
        if (d->handler->supportsOption(QImageIOHandler::ClipRect) && !d->clipRect.isNull()) {
            if (d->handler->supportsOption(QImageIOHandler::ScaledSize) && d->scaledSize.isValid()) {
    
            // [... more lines about scaling ...]
    
            }
        }
    
        // [...]
        if (autoTransform())
            qt_imageTransform(*image, transformation());
    
        return true;
    }
    

    另外,阅读 QImageIOHandler::ImageOption::ScaledSize 的文档(QImageIOHandler使用QImageReader实际读取图像数据)会看到:



    因此,在转换之前,始终由处理程序或读取器应用比例。

    结论

    基于上述要点,您必须使用EXIF数据来提供正确的缩放大小,或者在读取图像后对图像进行缩放(更易于阅读)。因此,除非您正在阅读数千张非常大的图像并且预缩放操作显着加快了转换速度,否则我建议您使用可维护性更高的代码。

    09-11 06:30