使用libheif库读取heic文件的缩略图 1.先使用vcpkg安装libheif库 在开始之前,我们需要安装 libheif 库。通过 vcpkg 工具可以方便地安装所需的依赖,根据实际需求选择适合的位数以及动态库或静态库版本。
安装命令示例:
1 2 vcpkg install libheif:x86-windows-static vcpkg install libheif:x64-windows-static
完成安装后,确保正确配置 vcpkg 环境,能够被 CMake 或其他构建工具找到。
2.解码缩略图和解码原图的区别 在处理 HEIC 格式文件时,缩略图解码和原图解码的使用场景有所不同。以下从资源占用和代码实现两方面进行比较。
1.解码原图
解码原图时,图像数据会被完全加载到内存中,适合用于查看高清图片或后续进行深度处理。但这也意味着需要更多的内存和 CPU 资源。
2.解码缩略图
如果仅用于预览或快速浏览,可以选择解码缩略图。这种方法占用资源更少,加载速度更快,非常适合需要快速显示大量图片的场景。
解码原图(查看图片使用)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 void heifToQPixmap (const QString& filePath, QPixmap& pixmap) { QString extension = QFileInfo (filePath).suffix ().toLower (); if (extension == "jpg" || extension == "jpeg" ) { if (!pixmap.load (filePath)) { throw std::runtime_error ("Failed to load JPG image." ); } return ; } std::string filePathStd = filePath.toStdString (); struct heif_context * ctx = heif_context_alloc (); if (!ctx) { throw std::runtime_error ("Failed to allocate HEIF context." ); } struct heif_error err = heif_context_read_from_file (ctx, filePathStd.c_str (), nullptr ); if (err.code != heif_error_Ok) { heif_context_free (ctx); throw std::runtime_error ("Failed to read HEIF file: " + std::string (err.message)); } struct heif_image_handle * handle = nullptr ; err = heif_context_get_primary_image_handle (ctx, &handle); if (err.code != heif_error_Ok) { heif_context_free (ctx); throw std::runtime_error ("Failed to get primary image handle: " + std::string (err.message)); } struct heif_image * img = nullptr ; err = heif_decode_image (handle, &img, heif_colorspace_RGB, heif_chroma_interleaved_RGBA, nullptr ); if (err.code != heif_error_Ok) { heif_image_handle_release (handle); heif_context_free (ctx); throw std::runtime_error ("Failed to decode HEIF image: " + std::string (err.message)); } int width = heif_image_get_width (img, heif_channel_interleaved); int height = heif_image_get_height (img, heif_channel_interleaved); const uint8_t * data = heif_image_get_plane_readonly (img, heif_channel_interleaved, nullptr ); QVector<uchar> buffer (width * height * 4 ) ; memcpy (buffer.data (), data, buffer.size ()); QImage image (buffer.data(), width, height, QImage::Format_RGBA8888) ; pixmap = QPixmap::fromImage (image); heif_image_release (img); heif_image_handle_release (handle); heif_context_free (ctx); }
解码缩略图(供预览使用)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 bool loadHeicThumbnail (const QString& filePath, QPixmap& thumbnail) { QString extension = QFileInfo (filePath).suffix ().toLower (); if (extension == "jpg" || extension == "jpeg" ) { QImageReader reader (filePath) ; reader.setAutoTransform (true ); QSize originalSize = reader.size (); if (originalSize.isEmpty ()) { qDebug () << "Failed to read image size:" << reader.errorString () << filePath; return false ; } QSize scaledSize = originalSize.scaled (QSize (originalSize/20 ), Qt::KeepAspectRatio); reader.setScaledSize (scaledSize); QImage image = reader.read (); if (image.isNull ()) { qWarning () << "Failed to load image:" << reader.errorString () << filePath; return false ; } thumbnail = QPixmap::fromImage (image); return true ; } heif_context* ctx = heif_context_alloc (); heif_error err = heif_context_read_from_file (ctx, filePath.toStdString ().c_str (), nullptr ); if (err.code != heif_error_Ok) { qDebug () << "Failed to read HEIF file: " ; heif_context_free (ctx); return false ; } heif_image_handle* handle = nullptr ; err = heif_context_get_primary_image_handle (ctx, &handle); if (err.code != heif_error_Ok) { qDebug () << "Failed to get primary image handle: " ; heif_context_free (ctx); return false ; } heif_image_handle* thumbnail_handle = nullptr ; int num_thumbnails = heif_image_handle_get_number_of_thumbnails (handle); if (num_thumbnails > 0 ) { heif_item_id thumbnail_id; heif_image_handle_get_list_of_thumbnail_IDs (handle, &thumbnail_id, 1 ); err = heif_image_handle_get_thumbnail (handle, thumbnail_id, &thumbnail_handle); if (err.code != heif_error_Ok) { qDebug () << "Failed to get thumbnail handle: " ; heif_image_handle_release (handle); heif_context_free (ctx); return false ; } heif_image* thumbnail_image = nullptr ; err = heif_decode_image (thumbnail_handle, &thumbnail_image, heif_colorspace_RGB, heif_chroma_interleaved_RGB, nullptr ); if (err.code != heif_error_Ok) { qDebug () << "Failed to decode thumbnail: " << err.message; heif_image_handle_release (thumbnail_handle); heif_image_handle_release (handle); heif_context_free (ctx); return false ; } int width = heif_image_get_width (thumbnail_image, heif_channel_interleaved); int height = heif_image_get_height (thumbnail_image, heif_channel_interleaved); int stride; const uint8_t * data = heif_image_get_plane_readonly (thumbnail_image, heif_channel_interleaved, &stride); QImage image (data, width, height, stride, QImage::Format_RGB888) ; \ if (image.isNull ()) { qDebug () << "Failed to convert HEIF thumbnail to QImage." ; heif_image_release (thumbnail_image); heif_image_handle_release (thumbnail_handle); heif_image_handle_release (handle); heif_context_free (ctx); return false ; } thumbnail = QPixmap::fromImage (image.copy ()); heif_image_release (thumbnail_image); heif_image_handle_release (thumbnail_handle); } else { qDebug () << "No thumbnails found in the HEIF file." ; heif_image_handle_release (handle); heif_context_free (ctx); return false ; } heif_image_handle_release (handle); heif_context_free (ctx); return true ; }
3.测试代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 #include <QApplication> #include <QLabel> #include <QImage> #include <QPixmap> #include <libheif/heif.h> #include <iostream> QImage heifToQImage (const std::string& filePath) { struct heif_context * ctx = heif_context_alloc (); if (!ctx) { throw std::runtime_error ("Failed to allocate HEIF context." ); } struct heif_error err = heif_context_read_from_file (ctx, filePath.c_str (), nullptr ); if (err.code != heif_error_Ok) { heif_context_free (ctx); throw std::runtime_error ("Failed to read HEIF file: " + std::string (err.message)); } struct heif_image_handle * handle = nullptr ; err = heif_context_get_primary_image_handle (ctx, &handle); if (err.code != heif_error_Ok) { heif_context_free (ctx); throw std::runtime_error ("Failed to get primary image handle: " + std::string (err.message)); } struct heif_image * img = nullptr ; err = heif_decode_image (handle, &img, heif_colorspace_RGB, heif_chroma_interleaved_RGBA, nullptr ); if (err.code != heif_error_Ok) { heif_image_handle_release (handle); heif_context_free (ctx); throw std::runtime_error ("Failed to decode HEIF image: " + std::string (err.message)); } int width = heif_image_get_width (img, heif_channel_interleaved); int height = heif_image_get_height (img, heif_channel_interleaved); const uint8_t * data = heif_image_get_plane_readonly (img, heif_channel_interleaved, nullptr ); QVector<uchar> buffer (width * height * 4 ) ; memcpy (buffer.data (), data, buffer.size ()); QImage qimage (buffer.data(), width, height, QImage::Format_RGBA8888) ; heif_image_release (img); heif_image_handle_release (handle); heif_context_free (ctx); return qimage.copy (); } int main (int argc, char * argv[]) { QApplication app (argc, argv) ; try { QImage image = heifToQImage ("C:/Users/lianx/Pictures/IMG_0001.HEIC" ); QLabel label; label.setPixmap (QPixmap::fromImage (image)); label.setScaledContents (true ); label.resize (image.size ()/2 ); label.show (); return app.exec (); } catch (const std::exception& e) { std::cerr << "Error: " << e.what () << std::endl; return -1 ; } }
4.效果如图