最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++圖像加載之libpng、FreeImage、stb_image詳解

 更新時(shí)間:2023年06月30日 15:33:37   作者:略游  
libpng、FreeImage、stb_image都是圖像解析的開(kāi)源庫(kù),這篇文章主要為大家詳細(xì)介紹了這三者的使用方法,文中的示例代碼講解詳細(xì),需要的可以參考一下

一、前言

libpng、FreeImage、stb_image都是圖像解析的開(kāi)源庫(kù),由于三者我都簡(jiǎn)單使用過(guò),于是做個(gè)總結(jié)對(duì)比。

二、對(duì)比

庫(kù)開(kāi)源協(xié)議編譯依賴(lài)win編譯難度使用難度格式支持
libpngzlibzlib自帶vs工程只支持png
FreeImage混合自帶了7、8個(gè)庫(kù)有dll發(fā)行版簡(jiǎn)單很多
stb_imageMIT無(wú)只有頭文件簡(jiǎn)單常用的幾個(gè)

它們的官網(wǎng)如下:

libpng Home Page

The FreeImage Project

GitHub - nothings/stb: stb single-file public domain libraries for C/C++

總的來(lái)說(shuō),它們的開(kāi)源協(xié)議都問(wèn)題不大。源碼編譯stb_image最簡(jiǎn)單,因?yàn)樗挥幸粋€(gè)頭文件。而libpng是操作png文件的庫(kù),代碼比較復(fù)雜,但是它的優(yōu)點(diǎn)是靈活,速度更快。FreeImage集成了各種加載庫(kù),支持的格式比較多。

接下來(lái),我就按使用難度給出它們的基本代碼。注意均是讀取到uint32_t緩沖區(qū),代表RGBA32位顏色,如下:

class Image
{
//other
    uint32_t* _data;
    array<unsigned, 2> _size;
}

注意我并沒(méi)有處理字節(jié)序問(wèn)題,是寫(xiě)死的,在不同大小端的系統(tǒng)運(yùn)行,應(yīng)該改進(jìn)一下代碼(我懶得很,要等到遇到問(wèn)題再解決,就是交換一下單個(gè)像素RGBA通道的讀取順序)。

覺(jué)得有用,請(qǐng)點(diǎn)贊、收藏、關(guān)注。我寫(xiě)這篇文件就是因?yàn)橛腥薵et了我以前寫(xiě)的libpng的文章。

三、stb_image

讀取如下,確實(shí)很簡(jiǎn)單,直接返回的就是RGBA32位顏色:

#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
dnd::Image* Image::Create(string_view path_name)
{
    int texWidth, texHeight, texChannels;
    stbi_uc* pixels = stbi_load(string{ path_name }.c_str(),
        &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
    if (!pixels) 
    {
        debug_err(format("加載圖像失?。簕}", path_name));
        return nullptr;
    }
    Image* ret = new Image;
    ret->_data = (uint32_t*)pixels;
    ret->_size = { (unsigned)texWidth, (unsigned)texHeight };
    return ret;
}

導(dǎo)出圖像數(shù)據(jù)更簡(jiǎn)單;

#define STB_IMAGE_WRITE_IMPLEMENTATION
#include <stb_image_write.h>
bool Image::SaveToFile(string_view path_name)
{
    return stbi_write_png(string{ path_name }.c_str(), _size[0], _size[1], 4, _data, 0);
}

注意,我們應(yīng)該使用它的釋放函數(shù)來(lái)釋放資源,轉(zhuǎn)回stbi_uc*類(lèi)型(實(shí)際上也就是調(diào)用了free函數(shù),不過(guò)大家都懂不要自己free):

stbi_image_free((stbi_uc*)_data);

四、FreeImage

代碼中用到的一些函數(shù)(語(yǔ)法糖)如下:

/**
* @brief RAII清理操作
*/
template<typename F>
class finally
{
public:
    finally(F&& func) : _func(func) {}
    ~finally() { _func(); }
private:
    F _func;
};
//! 對(duì)容器任意元素的判斷
namespace Any
{
/**
    * @brief 判斷容器任意元素等于某值
    * @param[in] container 操作的容器
    * @param[in] v 要比較的值
*/
template<typename C, typename V>
bool Equal(const C& container, const V& v)
{
    for (auto& iter : container)
    {
        if (iter == v)
            return true;
    }
    return false;
}
}

讀取代碼如下:

#include <FreeImage.h>
string path_name_mb = String::cvt_u8_mb(path_name);
const char* filename = path_name_mb.c_str();
//讀文件頭判斷格式
FREE_IMAGE_FORMAT file_format = FreeImage_GetFileType(filename, 0);
if (file_format == FIF_UNKNOWN)
{//通過(guò)文件名讀取
    file_format = FreeImage_GetFIFFromFilename(filename);
}
if (file_format == FIF_UNKNOWN)
{
    debug_err("圖像文件格式不支持:" + string{ path_name });
    return nullptr;
}
//格式支持讀取則讀取
FIBITMAP* bitmap = nullptr;
if (FreeImage_FIFSupportsReading(file_format))
{
    bitmap = FreeImage_Load(file_format, filename);
}
if (!bitmap)
{
    return nullptr;
}
//資源釋放
finally f0([&]() {
    FreeImage_Unload(bitmap);
});
//
unsigned bpp = FreeImage_GetBPP(bitmap);            //取像素深度
FREE_IMAGE_TYPE file_type = FreeImage_GetImageType(bitmap);    //取數(shù)據(jù)類(lèi)型
BYTE* bits = FreeImage_GetBits(bitmap);                //取像素?cái)?shù)組
unsigned w = FreeImage_GetWidth(bitmap);            //寬
unsigned h = FreeImage_GetHeight(bitmap);            //高
unsigned pitch = FreeImage_GetPitch(bitmap);        //每行像素(freeimage自動(dòng)做了32位對(duì)齊, gl默認(rèn)也是32位對(duì)齊)
if (bits == 0 || w == 0 || h == 0)
{
    debug_err("圖像文件基本數(shù)據(jù)錯(cuò)誤:" + string{ path_name });
    return nullptr;
}
//
if (file_type != FIT_BITMAP)
{
    debug_err("圖像文件類(lèi)型不是位圖:" + string{ path_name });
    return nullptr;
}
//
vector<unsigned> mul_bpp{ 32, 24, 8 };
if (!Any::Equal(mul_bpp, bpp))
{
    debug_err(format("圖像文件不支持的色深({}):", bpp, path_name));
    return nullptr;
}
//
Image* ret = new Image;
ret->_size = { w, h };
size_t length = size_t(w * h);
ret->_buffer = new uint32[length];
//BGRA => ABGR(RGBA) 單個(gè)訪問(wèn)時(shí)有字節(jié)序問(wèn)題,需要反過(guò)來(lái)
if (bpp == 32)    
{    
    for (unsigned x = 0; x < w; ++x)
    {
        for (unsigned y = 0; y < h; ++y)
        {
            unsigned p0 = y * w + x;
            unsigned p1 = (h - 1 - y) * pitch + x * 4;
            char* p = (char*)&(ret->_buffer[p0]);
            p[0] = bits[p1 + 2];
            p[1] = bits[p1 + 1];
            p[2] = bits[p1 + 0];
            p[3] = bits[p1 + 3];
        }
    }
}
else if (bpp == 24)
{
    for (unsigned x = 0; x < w; x++)
    {
        for (unsigned y = 0; y < h; y++)
        {
            unsigned p0 = y * w + x;
            unsigned p1 = (h - 1 - y) * pitch + x * 3;
            char* p = (char*)&(ret->_buffer[p0]);
            p[0] = bits[p1 + 2];
            p[1] = bits[p1 + 1];
            p[2] = bits[p1 + 0];
            p[3] = (char)255;
        }
    }
}
else if (bpp == 8)
{
    for (unsigned x = 0; x < w; x++)
    {
        for (unsigned y = 0; y < h; y++)
        {
            unsigned p0 = y * w + x;
            unsigned p1 = (h - 1 - y) * pitch + x * 1;
            char* p = (char*)&(ret->_buffer[p0]);
            p[0] = bits[p1];
            p[1] = bits[p1];
            p[2] = bits[p1];
            p[3] = (char)255;
        }
    }
}
return ret;

導(dǎo)出圖像數(shù)據(jù)到文件:

string path_name_mb = String::cvt_u8_mb(path_name);
const char* filename = path_name_mb.c_str();
FREE_IMAGE_FORMAT file_format = FreeImage_GetFIFFromFilename(filename);
if (file_format == FIF_UNKNOWN)
{
    debug_err("不支持的圖像格式:" + string{ path_name });
    return false;
}
unsigned w = _size[0];
unsigned h = _size[1];
uint32_t* bits = new uint32_t[w * h];
//ABGR(RGBA)=> BGRA  單個(gè)訪問(wèn)時(shí)有字節(jié)序問(wèn)題,需要反過(guò)來(lái)
for (unsigned x = 0; x < w; ++x)
{
    for (unsigned y = 0; y < h; ++y)
    {
        unsigned index = y * w + x;
        char* p_dst = (char*)&(bits[index]);
        char* p = (char*)&(_buffer[index]);
        p_dst[0] = p[2];
        p_dst[1] = p[1];
        p_dst[2] = p[0];
        p_dst[3] = p[3];
    }
}
//
FIBITMAP* bitmap = FreeImage_ConvertFromRawBits((BYTE*)bits,
    w, h, w * 4, 32, 0, 0, 0, true);
delete[] bits;
FreeImage_Save(file_format, bitmap, filename);
//釋放
FreeImage_Unload(bitmap);
return true;

五、libpng

這里的代碼比較陳舊,用了win32的類(lèi)型,自行修改一下即可。加載代碼如下:

#include <png.h>
Image* img = new Image;
///從文件加載/
FILE* fp = NULL;
if (sys->GetFile(path, fp) == -1)
{
    debug_err(String(L"DND: Image::Create: 圖像文件打開(kāi)失敗: ") + path);
    return NULL;
}
//判斷是否問(wèn) png 文件
size_t number = 8;
png_bytep header = new png_byte[number];
fread(header, 1, number, fp);
bool is_png = !png_sig_cmp(header, 0, number);
if (!is_png)
{
    fclose(fp);
    debug_err(String(L"DND: Image::Create: 必須是png文件: ") + path);
    return NULL;
}
//初始化pnglib 
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
    NULL, NULL, NULL);
if (!png_ptr)
{
    fclose(fp);
    debug_err(L"DND: Image::Create: 初始化pnglib失敗!");
    return NULL;
}
//創(chuàng)建圖像信息 info
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
{
    fclose(fp);
    debug_err(L"DND: Image::Create: 創(chuàng)建png_info失?。?);
    return NULL;
}
//錯(cuò)誤處理
if (setjmp(png_jmpbuf(png_ptr)))
{
    fclose(fp);
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    debug_err(L"DND: Image::Create: pnglib出現(xiàn)錯(cuò)誤!");
    return NULL;
}
//設(shè)置數(shù)據(jù)源
png_init_io(png_ptr, fp);
//表明文件頭已處理
png_set_sig_bytes(png_ptr, number);
//讀png 這一步會(huì)實(shí)際分配內(nèi)存
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND, 0);
fclose(fp);
//從info查詢(xún)數(shù)據(jù)
unsigned w = png_get_image_width(png_ptr, info_ptr);        //獲得圖片寬度
unsigned h = png_get_image_height(png_ptr, info_ptr);        //獲得圖片高度
int color_type = png_get_color_type(png_ptr, info_ptr);        //獲得圖片顏色類(lèi)型
                                                                //賦值image
img->_size.w = w;
img->_size.h = h;
img->_buffer = new DWORD[w*h];
//從info 復(fù)制到 image
png_bytep *row_point = NULL;
row_point = png_get_rows(png_ptr, info_ptr);
int block_size = (color_type == 6 ? 4 : 3);
//(A)RGB
unsigned pos = 0;
for (unsigned x = 0; x < h; ++x)
    for (unsigned y = 0; y < w*block_size; y += block_size)
    {
        ((unsigned char*)img->_buffer)[pos + 0] = row_point[x][y + 2];//b;
        ((unsigned char*)img->_buffer)[pos + 1] = row_point[x][y + 1];//g
        ((unsigned char*)img->_buffer)[pos + 2] = row_point[x][y + 0];//r
        if (color_type == 6)
            ((unsigned char*)img->_buffer)[pos + 3] = row_point[x][y + 3];//a
        else
            ((unsigned char*)img->_buffer)[pos + 3] = 0xff;
        pos += 4;
    }
//釋放png內(nèi)存
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return img;

導(dǎo)出圖像數(shù)據(jù)到文件:

FILE* fp;
png_infop info_ptr;
char cpath[MAX_PATH] = { NULL };
path.GetMultiByteStr(cpath, MAX_PATH);
fopen_s(&fp, cpath, "wb");
if (fp == NULL)
{
	debug_err(L"DND: Image::SaveToPNG: 創(chuàng)建文件失敗!");
	return;
}
//初始化pnglib 
static png_structp png_ptr = NULL;
if (!png_ptr)
	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
		NULL, NULL, NULL);
if (!png_ptr)
{
	debug_err(L"DND: Image::SaveToPNG: 創(chuàng)建文件時(shí)初始化pnglib失??!");
	return;
}
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL)
{
	fclose(fp);
	debug_err(L"DND: Image::SaveToPNG: png_create_info_struct失?。?);
	return;
}
//錯(cuò)誤處理
if (setjmp(png_jmpbuf(png_ptr)))
{
	fclose(fp);
	png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
	debug_err(L"DND: Image::SaveToPNG: pnglib 出現(xiàn)錯(cuò)誤!");
	return;
}
unsigned bit_depth = 8;
unsigned pixel_byte = 4;
unsigned row_byte = _size.w * pixel_byte;
//設(shè)置輸出控制
png_init_io(png_ptr, fp);
//設(shè)置圖像屬性
png_set_IHDR(png_ptr, info_ptr, _size.w, _size.h, bit_depth,
	PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, //交錯(cuò)無(wú)
	PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
//寫(xiě)頭部
png_write_info(png_ptr, info_ptr);
//獲取行指針
png_bytepp row_pointers = (png_bytep*)malloc(_size.h*sizeof(png_bytep));
for (unsigned x = 0; x < _size.h; ++x)
{//分配一行
	row_pointers[x] = (png_bytep)malloc(row_byte);
	for (unsigned y = 0; y < row_byte; y += pixel_byte)
	{
		row_pointers[x][y + 2] = ((unsigned char*)_buffer)[x * row_byte + y + 0];
		row_pointers[x][y + 1] = ((unsigned char*)_buffer)[x * row_byte + y + 1];
		row_pointers[x][y + 0] = ((unsigned char*)_buffer)[x * row_byte + y + 2];
		row_pointers[x][y + 3] = ((unsigned char*)_buffer)[x * row_byte + y + 3];
		/*row_pointers[x][y + 2] =
			row_pointers[x][y + 1] =
			row_pointers[x][y + 0] =
			row_pointers[x][y + 3] = 0xff;*/
	}
}
//寫(xiě)入全部
png_write_image(png_ptr, row_pointers);
//寫(xiě)尾部
png_write_end(png_ptr, info_ptr);
//釋放png內(nèi)存
png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
/*	delete[] row_pointers;
delete[] image;*/
for (unsigned x = 0; x < _size.h; ++x)
{//釋放每行
	free(row_pointers[x]);
}
free(row_pointers);
fclose(fp);

到此這篇關(guān)于C++圖像加載之libpng、FreeImage、stb_image詳解的文章就介紹到這了,更多相關(guān)C++圖像加載內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 實(shí)例講解C語(yǔ)言編程中的結(jié)構(gòu)體對(duì)齊

    實(shí)例講解C語(yǔ)言編程中的結(jié)構(gòu)體對(duì)齊

    這篇文章主要介紹了C語(yǔ)言編程中的結(jié)構(gòu)體對(duì)齊,值得注意的是一些結(jié)構(gòu)體對(duì)齊的例子在不同編譯器下結(jié)果可能會(huì)不同,需要的朋友可以參考下
    2016-04-04
  • C語(yǔ)言之結(jié)構(gòu)體定義 typedef struct 用法詳解和用法小結(jié)

    C語(yǔ)言之結(jié)構(gòu)體定義 typedef struct 用法詳解和用法小結(jié)

    這篇文章主要介紹了C語(yǔ)言的結(jié)構(gòu)體定義typedef struct用法詳解和用法小結(jié),typedef是類(lèi)型定義,typedef struct 是為了使用這個(gè)結(jié)構(gòu)體方便,感興趣的同學(xué)可以參考閱讀
    2023-03-03
  • C語(yǔ)言詳細(xì)解析有符號(hào)數(shù)與無(wú)符號(hào)數(shù)的表示

    C語(yǔ)言詳細(xì)解析有符號(hào)數(shù)與無(wú)符號(hào)數(shù)的表示

    我們知道,在C語(yǔ)言中存在無(wú)符號(hào)數(shù)和有符號(hào)數(shù),但是對(duì)于計(jì)算機(jī)而言,其本身并不區(qū)別有符號(hào)數(shù)和無(wú)符號(hào)數(shù),因?yàn)樵谟?jì)算機(jī)里面都是O或者1,但是在我們的實(shí)際使用中有時(shí)候需要使用有符號(hào)數(shù)來(lái)表示一個(gè)整數(shù),因此我們規(guī)定,當(dāng)最高位為1的時(shí),表示為負(fù)數(shù),最高位為0時(shí),表示為正數(shù)
    2022-04-04
  • C++事件驅(qū)動(dòng)型銀行排隊(duì)模擬

    C++事件驅(qū)動(dòng)型銀行排隊(duì)模擬

    這篇文章主要為大家詳細(xì)介紹了C++事件驅(qū)動(dòng)型銀行排隊(duì)模擬,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-09-09
  • C++11新增的包裝器詳解

    C++11新增的包裝器詳解

    由于函數(shù)調(diào)用可以使用函數(shù)名、函數(shù)指針、函數(shù)對(duì)象或有名稱(chēng)的lambda表達(dá)式,可調(diào)用類(lèi)型太豐富導(dǎo)致模板的效率極低。包裝器用于解決效率低的問(wèn)題
    2022-08-08
  • 關(guān)于在MFC中將窗口最小化到托盤(pán)實(shí)現(xiàn)原理及操作步驟

    關(guān)于在MFC中將窗口最小化到托盤(pán)實(shí)現(xiàn)原理及操作步驟

    最小化的原理:首先要將窗口隱藏,然后在右下角繪制圖標(biāo);恢復(fù)的原理:將窗口顯示,再將托盤(pán)中的圖片刪除,接下來(lái)介紹實(shí)現(xiàn)方法,感興趣的朋友可以了解下啊,希望本文對(duì)你有所幫助
    2013-01-01
  • C語(yǔ)言函數(shù)指針詳解

    C語(yǔ)言函數(shù)指針詳解

    本文主要介紹 C語(yǔ)言函數(shù)指針的知識(shí),這里整理了詳細(xì)的資料及示例代碼以便大家學(xué)習(xí)參考,有需要學(xué)習(xí)此部分知識(shí)的朋友可以參考下
    2021-09-09
  • c++ 如何在libuv中實(shí)現(xiàn)tcp服務(wù)器

    c++ 如何在libuv中實(shí)現(xiàn)tcp服務(wù)器

    這篇文章主要介紹了c++ 如何在libuv中實(shí)現(xiàn)tcp服務(wù)器,幫助大家更好的理解和使用libuv,感興趣的朋友可以了解下
    2021-02-02
  • c++中const的使用詳解

    c++中const的使用詳解

    本篇文章是對(duì)c++中的const的應(yīng)用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C++?Cmake使用詳細(xì)教程(看這一篇就夠了!)

    C++?Cmake使用詳細(xì)教程(看這一篇就夠了!)

    CMake是一個(gè)比make更高級(jí)的編譯配置工具,它可以根據(jù)不同平臺(tái)、不同的編譯器,生成相應(yīng)的Makefile或者vcproj項(xiàng)目,下面這篇文章主要給大家介紹了關(guān)于C++?Cmake使用的相關(guān)資料,需要的朋友可以參考下
    2023-03-03

最新評(píng)論

新余市| 禄丰县| 宁安市| 宿松县| 常山县| 盐源县| 延津县| 互助| 朝阳市| 洞头县| 永善县| 嘉善县| 达孜县| 新干县| 堆龙德庆县| 马鞍山市| 阜宁县| 清新县| 五峰| 诏安县| 神农架林区| 望奎县| 闻喜县| 九江县| 蓝山县| 红原县| 甘肃省| 东辽县| 靖宇县| 深水埗区| 南和县| 恭城| 来宾市| 阿尔山市| 韶关市| 定陶县| 定兴县| 莱阳市| 阿图什市| 崇阳县| 潜山县|