[Qt] png 形式と jpg 形式の画像 (2)

バックグラウンド

前回の記事【Qt】png 形式と jp​​g 形式の画像 (1) - Nuggets (juejin.cn) でjpg2 つの形式について作者がpng説明しましたが、Qt を開いてサフィックス ファイル名を変更する問題についてはまだ説明がありません。写真のQt がサフィックスが変更された画像ファイルを開けない理由を調べるには、さまざまな方法で画像ファイルを見つける必要があります。上で述べたように、QLabelの写真は 3 つの方法で設定されます。

シーンの繰り返し

設定に失敗する場面を再現する方法は次のとおりです。

  1. の画像を検索し.jpg、サフィックス、つまりファイル属性を変更します。.png
  2. QLabel画像として設定するには、以下の3つの方法があります。

Qtのバージョンは5.9

コンパイラは試しましたがMSVCmingw動作しませんでした。

QLabel映像方式の設定

  1. QPixmap設定によるQLabel画像
QPixmap img(":/Win11.png");

ui->label->setPixmap(img);
ui->label->setScaledContents(true);
  1. QImage設定によるQLabel画像
QImage img;
img.load(":/Win11.png");
ui->label->setPixmap(QPixmap::fromImage(img))
  1. QLabel.setStyleSheet()写真経由
ui->label->setStyleSheet(QString("QLabel{"
                                 "border-image:url(:/Win11.png) 4 4 4 4 stretch stretch;"
                                 "}"));

もちろん、次のようにQSvgRenderer設定する 4 番目の方法もあります。

#include <QSvgRenderer>

QSvgRenderer svgRender(QString(":/Win11.svg"));
QPixmap pixmap(20,20);
QPainter painter(&pixmap);
svgRender.render(&painter);
ui->label->setPixmap(pixmap);

シーンが説明されているので、自分で試してみることができます

操作する

次のステップは、いくつかの実装メソッドのソースコードがどのように設定されているかを確認することですが、最初に結論を推測しましょう。

つまりpngjpg形式のアルゴリズムと形式のアルゴリズムが異なり、形式の問題による読み取りアルゴリズムが一貫していないため、Qt 内部で実装された画像の読み取りアルゴリズムは、形式に対応したアルゴリズムに従ってのみ読み込むことができます。アルゴリズムもそのようなロジックに基づいているためsetStyleSheet、3 つの読み取り方法はすべて失敗します。

画像アルゴリズムの問​​題については、前回の記事でも少し触れましたが、これについては深く調べているわけではなく、それが分かればよく、同じアルゴリズムではなく、普遍的ではありませjpgpng

事前検証

著者は上記の手順をすべて試しているため、検証プロセス中にどの方法を使用するかについて心配する必要はなく、結果だけを見てください。

  1. 次に、それをどのように検証するかですが、引き続きコードを確認します。今回は、Qt ファイル内のピクチャのサフィックス名を削除し、qrcsuffix 属性なしでピクチャを読み取り、正常に読み取れるかどうかを確認します。

suffix 属性を削除する

演算結果:QLabel正常に読み取られました

上の図に示すように、qrcファイル内の画像のサフィックスを削除し、画像を読み取るように設定してQLabelも成功します。

  1. コード内の画像サフィックスを変更して、png今度は正常に読み取れるかどうかを確認してみましょう。

サフィックスを png に変更します

演算結果: 読み取りに失敗しました

上の図に示すように、サフィックスを追加した後も表示に失敗します。

事前検証の結果

これは基本的に次のように言えます。

内部ではQt、どの画像読み取りアルゴリズムを呼び出すかを決定するためにファイルのサフィックスが使用される可能性が高くなります。つまり、 を人為的に改造するとpng->jpgQtに画像を設定できないという問題が発生します。現時点では、コードに問題がないにもかかわらず、設定後に画像が表示されない場合は、画像のサフィックスを削除して、画像を読み取るためにどのアルゴリズムを呼び出すかをユーザーに決定させるのが最善の方法であるようですQt

ソースコード分析

ここではQtイメージの説明を示しますI\O。イメージ ファイルの読み取りと書き込みに関するドキュメントは Qt ヘルプ マニュアルで参照できます。

画像ファイルの読み取りと書き込み

ソースコード部分ではQtクラスを2つ見れば良いので、個人的には1つを見れば分かるような気がします。2 つの画像の間で画像を識別するアルゴリズムは同じである必要があります。setStyleSheet()インターフェイス内の設定画面を含むインターフェイスは一貫している必要があります。

  1. QPixmap は、それが配置されているプラ​​ットフォームの描画エンジンに依存するため、アンチエイリアシングなどの一部の効果は、異なるプラットフォームでは異なる表示効果を持つ可能性があります。QImage は、Qt 独自の描画エンジンを使用して、異なるプラットフォームで同じ表示効果を実現します。
  2. 現在の Qt は QPixmap をグラフィックス メモリに保存し、QImage はハードウェアから独立したクライアント側に保存されます。X11、Mac、Symbian プラットフォームでは、QPixmap はサーバー側に保存され、QImage はクライアント側に保存されますが、Windows プラットフォームでは、QPixmap と QImage の両方が GDI リソースを使用せずにクライアント側に保存されます。
  3. QImage はハードウェアに依存せず、QPaintDevice の一種でもあるため、GUI スレッドで処理せずに別スレッドで描画することができ、この方法を利用することで UI の応答速度が大幅に向上します。

Qピクスマップ

Qt通常、インストール ディレクトリに保存されている QPixmap のソース ファイルをクエリします${安装目录}\5.9.9\Src\qtbase\src\gui\image。ファイル名は次のとおりです。qpixmap.h qpixmap.cpp

まずは のQPixmapコンストラクターで画像ファイルを読み込む方法を見てみましょう。

  1. QPixmap::QPixmap(const QString& fileName, const char *format, Qt::ImageConversionFlags flags)ソースコード

    QPixmap::QPixmap(const QString& fileName, const char *format, Qt::ImageConversionFlags flags)
        : QPaintDevice()
       {
          
          
            doInit(0, 0, QPlatformPixmap::PixmapType);
            if (!qt_pixmap_thread_test())
                return;
    
            load(fileName, format, flags); // 这里看到调用了load()的接口,接着查看load是如何实现的
        }
    
  2. load()関数のソースコード

    /*!
        Loads a pixmap from the file with the given \a fileName. Returns
        true if the pixmap was successfully loaded; otherwise invalidates
        the pixmap and returns \c false.
    
        The loader attempts to read the pixmap using the specified \a
        format. If the \a format is not specified (which is the default),
        the loader probes the file for a header to guess the file format.
    
        The file name can either refer to an actual file on disk or to one
        of the application's embedded resources. See the
        \l{resources.html}{Resource System} overview for details on how to
        embed pixmaps and other resource files in the application's
        executable.
    
        If the data needs to be modified to fit in a lower-resolution
        result (e.g. converting from 32-bit to 8-bit), use the \a flags to
        control the conversion.
    
        Note that QPixmaps are automatically added to the QPixmapCache
        when loaded from a file; the key used is internal and can not
        be acquired.
    
        \sa loadFromData(), {QPixmap#Reading and Writing Image
        Files}{Reading and Writing Image Files}
    */
    
    /* 翻译过来就是
    从给定的文件名的文件中加载一个像素图。如果pixmap成功加载,则为True;否则返回无效pixmap并返回\c false。
    
    加载器尝试使用指定的\a读取pixmap格式。如果没有指定\a格式(这是默认的),
    加载器探测文件的头,以猜测文件的格式。
    
    文件名可以指向磁盘上的实际文件,也可以指向磁盘上的实际文件应用程序的嵌入式资源。看到\l{resources.html}{Resource System}概述如何嵌入pixmap和其他资源文件在应用程序的可执行文件。
    
    如果数据需要修改以适应低分辨率结果(例如从32位转换到8位),使用\a标志来控制转换。
    
    注意,qpixmap会自动添加到QPixmapCache中
    当从文件加载时;使用的密钥是内部的,不能被收购。
    
    \sa loadFromData(), {QPixmap#读写图像读写图像文件}
    */
    
    // loadFromdata的源码我也补充到了文末
    bool QPixmap::load(const QString &fileName, const char *format, Qt::ImageConversionFlags flags)
    {
          
          
        if (!fileName.isEmpty()) {
          
          
    
            QFileInfo info(fileName);
            // Note: If no extension is provided, we try to match the
            // file against known plugin extensions
            if (info.completeSuffix().isEmpty() || info.exists()) {
          
          
    
                QString key = QLatin1String("qt_pixmap")
                        % info.absoluteFilePath()
                        % HexString<uint>(info.lastModified().toSecsSinceEpoch())
                        % HexString<quint64>(info.size())
                        % HexString<uint>(data ? data->pixelType() : QPlatformPixmap::PixmapType);
    
                if (QPixmapCache::find(key, this))
                    return true;
    
                data = QPlatformPixmap::create(0, 0, data ? data->pixelType() : QPlatformPixmap::PixmapType);
    
                if (data->fromFile(fileName, format, flags)) {
          
          
                    QPixmapCache::insert(key, *this);
                    return true;
                }
            }
        }
    
        if (!isNull()) {
          
          
            if (isQBitmap())
                *this = QBitmap();
            else
                data.reset();
        }
        return false;
    }
    

ソースコードがより明確になっているかどうかを確認してください。関数の実装ではload()、①ファイル名が空かどうかを判断し、②空でない場合は、まずファイルの拡張子を読み取ります。ここでは、2番目のif判定でどのような処理が行われるかを詳しく確認します。QStringkey

QString key = QLatin1String("qt_pixmap")
                    % info.absoluteFilePath() // 返回文件名的绝对路径
                    % HexString<uint>(info.lastModified().toSecsSinceEpoch()) // 返回文件最后一次修改的日期和时间
                    % HexString<quint64>(info.size()) // 返回文件的大小
                    % HexString<uint>(data ? data->pixelType() : QPlatformPixmap::PixmapType); // 这里的data是成员变量,就是说如果设置了data的pixelType的值就读取,没设置的话就是默认值 QPlatformPixmap::PixmapType

上記はHexString<type>ASCII 配列形式、16进制配列です。剰余でない場合、上記のコードの操作は何ですか%余剰を要求している場合、QStringエラーが報告されますか? ? ?

最後に、 のQPixmap組み込み変数にフラグを設定してチェックすることでdata、現在のファイルが画像かどうかを確認します。画像の場合は現在のQPixmapポインタが変更され、そうでない場合は戻り値が返されます。間違い

if (QPixmapCache::find(key, this))
                return true;

QPixmapCache追加するデモは次のとおりです。

/*在缓存中查找与给定键关联的缓存pixmap。如果找到了pixmap,函数将pixmap设置为该pixmap并返回true;否则,它将保留pixmap并返回false。*/
QPixmap pm;
if (!QPixmapCache::find("my_big_image", &pm)) {
    
    
    pm.load("bigimage.png");
    QPixmapCache::insert("my_big_image", pm);
}
painter->drawPixmap(0, 0, pm);

現在のファイルが画像であるかどうかの最終的な判断は、data->fromFile()で実現される必要があります。

これの定義data:

QExplicitlySharedDataPointer<QPlatformPixmap> data;

次の記事では、Qt 内で画像を読み取るためのコードを学習していきます。

補充する

追加

load()関数を読む必要があります。

QPixmap::loadFromData()ソースコード。

/*!
    \fn bool QPixmap::loadFromData(const uchar *data, uint len, const char *format, Qt::ImageConversionFlags flags)

    Loads a pixmap from the \a len first bytes of the given binary \a
    data.  Returns \c true if the pixmap was loaded successfully;
    otherwise invalidates the pixmap and returns \c false.

    The loader attempts to read the pixmap using the specified \a
    format. If the \a format is not specified (which is the default),
    the loader probes the file for a header to guess the file format.

    If the data needs to be modified to fit in a lower-resolution
    result (e.g. converting from 32-bit to 8-bit), use the \a flags to
    control the conversion.

    \sa load(), {QPixmap#Reading and Writing Image Files}{Reading and
    Writing Image Files}
*/

bool QPixmap::loadFromData(const uchar *buf, uint len, const char *format, Qt::ImageConversionFlags flags)
{
     
     
    if (len == 0 || buf == 0) {
     
     
        data.reset();
        return false;
    }

    data = QPlatformPixmap::create(0, 0, QPlatformPixmap::PixmapType);

    if (data->fromData(buf, len, format, flags))
        return true;

    data.reset();
    return false;
}

おすすめ

転載: blog.csdn.net/Fuel_Ming/article/details/124397625