【问题标题】:Qt: PNG image transparency lost after openingQt:打开后PNG图像透明度丢失
【发布时间】:2019-05-04 23:46:17
【问题描述】:

我正在尝试使用 QT 打开 PNG 图像,但像素的 alpha 值始终为 255,即使图像为空白(即 alpha 值应为 0)

我尝试在加载后将图像转换为 ARGB 格式,但没有帮助。这是我尝试加载的空白 png 的示例:

图片:

QImage im = QImage("JGbVc0r.png");
int p1 = 20;
int p2 = 20;
QImage img = im.convertToFormat(QImage::Format_ARGB32);
qInfo()<<qRed(img.pixel(p1,p2))<<qBlue(img.pixel(p1,p2))<<qGreen(img.pixel(p1,p2))<<qAlpha(img.pixel(p1,p2));

预期的输出是 0 0 0 0 但我明白了 255 255 255 255

关于如何获得所需输出的任何建议?提前致谢。我正在使用 Qt 5.11。

【问题讨论】:

  • 如果im.format() == QImage::Format_ARGB32 则加载的图像已经是该格式,转换毫无意义。 im.hasAlphaChannel() 表明您的图像确实具有 Alpha 通道。当我将该文件加载到 QImage 并使用 getter qRed 等时,我得到 0。
  • 可能相关:stackoverflow.com/questions/25021966/… 我使用 Qt 5.12 进行了测试,所以这可能最近发生了变化。
  • alpha 为零并不意味着图像是黑色的。
  • @eyllanesc 声明的问题是 alpha 预期为 0,但实际上是 255。
  • 愚蠢的问题:你确定你的图片可以加载吗?有了这个想法后,我扩展了我的答案。 (我相信你应该注意到这是否是问题所在。)

标签: qt png qimage


【解决方案1】:

我试图重现 OP 的问题。

不幸的是,imgur.com 在我的公司被屏蔽(我是在这个问题上偶然发现的)。因此,我从自己在 GIMP 中准备的小样本图像开始。

← 真的很小:8x8 像素,RGBA 通道。

接下来,我制作了一个小示例应用程序来检查QImage - testQImageRGBA.cc 中的结果:

#include <iomanip>
#include <iostream>

#include <QtWidgets>

void dump(
  const QImage &qImg, int row, int col,
  std::function<void(const QImage&, int, int)> dumpPixel)
{
  qDebug() << qImg;
  const int nR = qImg.height(), nC = qImg.width();
  const int iR0 = row >= 0 ? row : 0;
  const int iRN = row >= 0 ? row + 1 : nR;
  const int iC0 = col >= 0 ? col : 0;
  const int iCN = col >= 0 ? col + 1 : nC;
  std::cout << "Dump of rows [" << iR0 << ", " << iRN << "),"
    << " cols [" << iC0 << ", " << iCN << ")\n"
    << "Pixel format: '#RRGGBBAA'\n";
  for (int iR = iR0; iR < iRN; ++iR) {
    for (int iC = iC0; iC < iCN; ++iC) {
      dumpPixel(qImg, iR, iC);
    }
    std::cout << '\n';
  }
}

int main(int argc, char **argv)
{
  std::function<void(const QImage&, int, int)> dumpPixelOP // OPs flavor
    = [](const QImage &qImg, int iR, int iC) {
      std::cout << std::hex << "_#"
        << std::setw(2) << std::setfill('0') << qRed(qImg.pixel(iC, iR))
        << std::setw(2) << std::setfill('0') << qGreen(qImg.pixel(iC, iR))
        << std::setw(2) << std::setfill('0') << qBlue(qImg.pixel(iC, iR))
        << std::setw(2) << std::setfill('0') << qAlpha(qImg.pixel(iC, iR));
    };
  std::function<void(const QImage&, int, int)> dumpPixel // my flavor
    = [](const QImage &qImg, int iR, int iC) {
      const QColor pixel = qImg.pixelColor(iC, iR);
      std::cout << std::hex << " #"
        << std::setw(2) << std::setfill('0') << pixel.red()
        << std::setw(2) << std::setfill('0') << pixel.green()
        << std::setw(2) << std::setfill('0') << pixel.blue()
        << std::setw(2) << std::setfill('0') << pixel.alpha();
    };
  qDebug() << "Qt Version:" << QT_VERSION_STR;
  QApplication app(argc, argv);
  const QStringList args = app.arguments();
  const QString filePath = args.size() > 1 ? args[1] : "smiley.8x8.rgba.png";
  const int row = args.size() > 2 ? args[2].toInt() : -1;
  const int col = args.size() > 3 ? args[3].toInt() : -1;
  const bool useDumpOP = args.size() > 4;
  QImage qImg(filePath);
  qImg = qImg.convertToFormat(QImage::Format_ARGB32);
  dump(qImg, row, col, useDumpOP ? dumpPixelOP : dumpPixel);
  return 0;
}

还有一个 Qt 项目文件——testQImageRGBA.pro:

SOURCES = testQImageRGBA.cc

QT += widgets

cygwin64中编译测试:

$ qmake-qt5 testQImageRGBA.pro

$ make && ./testQImageRGBA
g++ -c -fno-keep-inline-dllexport -D_GNU_SOURCE -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -isystem /usr/include/qt5 -isystem /usr/include/qt5/QtWidgets -isystem /usr/include/qt5/QtGui -isystem /usr/include/qt5/QtCore -I. -I/usr/lib/qt5/mkspecs/cygwin-g++ -o testQImageRGBA.o testQImageRGBA.cc
g++  -o testQImageRGBA.exe testQImageRGBA.o   -lQt5Widgets -lQt5Gui -lQt5Core -lGL -lpthread 
Qt Version: 5.9.4
QImage(QSize(8, 8),format=5,depth=32,devicePixelRatio=1,bytesPerLine=32,byteCount=256)
Dump of rows [0, 8), cols [0, 8)
Pixel format: '#RRGGBBAA'
 #00000000 #00000000 #000000ff #000000ff #000000ff #000000ff #00000000 #00000000
 #00000000 #000000ff #ffff00ff #ffff00ff #ffff00ff #ffff00ff #000000ff #00000000
 #000000ff #ffff00ff #0000ffff #ffff00ff #ffff00ff #0000ffff #ffff00ff #000000ff
 #000000ff #ffff00ff #ffff00ff #ffff00ff #ffff00ff #ffff00ff #ffff00ff #000000ff
 #000000ff #ffff00ff #ff0000ff #ffff00ff #ffff00ff #ff0000ff #ffff00ff #000000ff
 #000000ff #ffff00ff #ffff00ff #ff0000ff #ff0000ff #ffff00ff #ffff00ff #000000ff
 #00000000 #000000ff #ffff00ff #ffff00ff #ffff00ff #ffff00ff #000000ff #00000000
 #00000000 #00000000 #000000ff #000000ff #000000ff #000000ff #00000000 #00000000

转储准确地反映了我在 GIMP 中绘制的内容。请注意黑色透明的角落像素。

我准备了一个CMake源文件CMakeLists.txt

project(QImageRGBA)

cmake_minimum_required(VERSION 3.10.0)

set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

find_package(Qt5Widgets CONFIG REQUIRED)

include_directories("${CMAKE_SOURCE_DIR}")

add_executable(testQImageRGBA testQImageRGBA.cc)

target_link_libraries(testQImageRGBA Qt5::Widgets)

并在 VS2017 中编译了相同的源代码。在 Windows 10 上的 cmd.exe 中测试:

C:\Users\Scheff\tests\misc\Qt\QImageRGBA>set PATH=%PATH%;D:\Scheff\Qt\5.11.2\msvc2017_64\bin;$(LocalDebuggerEnvironment)

C:\Users\Scheff\tests\misc\Qt\QImageRGBA>build-VS2017\Debug\testQImageRGBA.exe
Qt Version: 5.11.2
QImage(QSize(8, 8),format=5,depth=32,devicePixelRatio=1,bytesPerLine=32,sizeInBytes=256)
Dump of rows [0, 8), cols [0, 8)
Pixel format: '#RRGGBBAA'
 #00000000 #00000000 #000000ff #000000ff #000000ff #000000ff #00000000 #00000000
 #00000000 #000000ff #ffff00ff #ffff00ff #ffff00ff #ffff00ff #000000ff #00000000
 #000000ff #ffff00ff #0000ffff #ffff00ff #ffff00ff #0000ffff #ffff00ff #000000ff
 #000000ff #ffff00ff #ffff00ff #ffff00ff #ffff00ff #ffff00ff #ffff00ff #000000ff
 #000000ff #ffff00ff #ff0000ff #ffff00ff #ffff00ff #ff0000ff #ffff00ff #000000ff
 #000000ff #ffff00ff #ffff00ff #ff0000ff #ff0000ff #ffff00ff #ffff00ff #000000ff
 #00000000 #000000ff #ffff00ff #ffff00ff #ffff00ff #ffff00ff #000000ff #00000000
 #00000000 #00000000 #000000ff #000000ff #000000ff #000000ff #00000000 #00000000

C:\Users\Scheff\tests\misc\Qt\QImageRGBA>

实际上没有区别。


有一次在家(可以访问 imgur.com),我下载了 OP JGbVc0r.png 的图像并再次尝试。

cygwin64中的第一个:

$ make && ./testQImageRGBA JGbVc0r.png 20 20   
make: Nothing to be done for 'first'.
Qt Version: 5.9.4
QImage(QSize(1000, 1000),format=5,depth=32,devicePixelRatio=1,bytesPerLine=4000,byteCount=4000000)
Dump of rows [20, 21), cols [20, 21)
Pixel format: '#RRGGBBAA'
 #00000000

然后在 VS2017 和cmd.exe:

C:\Users\Scheff\tests\misc\Qt\QImageRGBA>build-VS2017\Debug\testQImageRGBA.exe JGbVc0r.png 20 20
Qt Version: 5.11.2
QImage(QSize(1000, 1000),format=5,depth=32,devicePixelRatio=1,bytesPerLine=4000,sizeInBytes=4000000)
Dump of rows [20, 21), cols [20, 21)
Pixel format: '#RRGGBBAA'
 #00000000

OP 声明:

预期输出为 0 0 0 0

这正是我得到的。


replete 提供了一个有趣的提示,关于一个关于 QColor::QColor(QRgb) 的陷阱,这是 Q/A 的主题

SO: QImage setting alpha in PNG with transparency.

但是,我得出的结论是,这不应该是这里的问题,因为在 OPs 代码中

qInfo()<<qRed(img.pixel(p1,p2))<<qBlue(img.pixel(p1,p2))<<qGreen(img.pixel(p1,p2))<<qAlpha(img.pixel(p1,p2));

因此,不法分子QColor::QColor(QRgb) 根本不涉及。为了消除我最后的疑虑,我在 cygwin 中也简单地尝试了这个:

$ make && ./testQImageRGBA JGbVc0r.png 20 20 dumpLikeOP  
make: Nothing to be done for 'first'.
Qt Version: 5.9.4
QImage(QSize(1000, 1000),format=5,depth=32,devicePixelRatio=1,bytesPerLine=4000,byteCount=4000000)
Dump of rows [20, 21), cols [20, 21)
Pixel format: '#RRGGBBAA'
_#00000000

在 VS2017 和 cmd.exe:

C:\Users\Scheff\tests\misc\Qt\QImageRGBA>build-VS2017\Debug\testQImageRGBA.exe JGbVc0r.png 20 20 dumpLikeOP
Qt Version: 5.11.2
QImage(QSize(1000, 1000),format=5,depth=32,devicePixelRatio=1,bytesPerLine=4000,sizeInBytes=4000000)
Dump of rows [20, 21), cols [20, 21)
Pixel format: '#RRGGBBAA'
_#00000000

所以,虽然我很努力,但我根本无法重现 OP 的问题。

OP 也可能会使用我的代码进行测试。要么 OP 忽略了其他未公开的问题,要么 OP 的系统存在特定问题。


我最后一个(绝望的)想法是检查如果 QImage 根本没有加载(例如由于找不到文件)会发生什么。

在 cygwin 中:

$ make && ./testQImageRGBA ImageNotFound.png 20 20           
make: Nothing to be done for 'first'.
Qt Version: 5.9.4
QImage(null)
Dump of rows [20, 21), cols [20, 21)
Pixel format: '#RRGGBBAA'
QImage::pixelColor: coordinate (20,20) out of range
 #000000ff

$ make && ./testQImageRGBA ImageNotFound.png 20 20 dumpLikeOP
make: Nothing to be done for 'first'.
Qt Version: 5.9.4
QImage(null)
Dump of rows [20, 21), cols [20, 21)
Pixel format: '#RRGGBBAA'
QImage::pixel: coordinate (20,20) out of range
QImage::pixel: coordinate (20,20) out of range
QImage::pixel: coordinate (20,20) out of range
QImage::pixel: coordinate (20,20) out of range
_#00303900

请注意,超出范围的访问会在控制台上通知。除此之外,代码似乎运行正常,但返回任意值。

在 VS2017/cmd.exe:

C:\Users\Scheff\tests\misc\Qt\QImageRGBA>build-VS2017\Debug\testQImageRGBA.exe ImageNotFound.png 20 20
Qt Version: 5.11.2
QImage(null)
Dump of rows [20, 21), cols [20, 21)
Pixel format: '#RRGGBBAA'
QImage::pixelColor: coordinate (20,20) out of range
 #000000ff

C:\Users\Scheff\tests\misc\Qt\QImageRGBA>build-VS2017\Debug\testQImageRGBA.exe ImageNotFound.png 20 20 dumpLikeOP
Qt Version: 5.11.2
QImage(null)
Dump of rows [20, 21), cols [20, 21)
Pixel format: '#RRGGBBAA'
_#QImage::pixel: coordinate (20,20) out of range
00QImage::pixel: coordinate (20,20) out of range
30QImage::pixel: coordinate (20,20) out of range
39QImage::pixel: coordinate (20,20) out of range
00

输出顺序发生了一些变化。除此之外,我什至得到了相同的“任意”值(恕我直言,这毫无意义)。

【讨论】:

  • 一项出色且富有启发性的调查。也许值得指出的是,如果 (255, 255, 255, 255) 确实是来自无法加载的 QImage 垃圾的结果,那么可以通过在构造后使用 QImage::isNull() 进行测试来避免这种情况。在使用新的开发环境时,工作目录不是您所期望的,这并不罕见:QImage img("filenameWithoutDirectory.png") 也让我陷入困境。这也是一个很好的提醒,如果您的环境没有显示控制台,那就是一个问题。
  • @replete 我大体上同意。但是,OP 使用了qInfo(),因此我认为她/他有控制台焦点... ;-)
猜你喜欢
  • 2013-02-16
  • 2016-01-22
  • 1970-01-01
  • 1970-01-01
  • 2013-09-13
  • 2017-12-27
  • 2018-08-16
  • 2016-05-02
  • 2012-03-12
相关资源
最近更新 更多