- 顯示蘋果 HEIC 圖片的實(shí)現(xiàn)原理
- 一個(gè)最簡(jiǎn)單的顯示程序
- 高品質(zhì)顯示效果,保持縱橫比縮放
- 轉(zhuǎn)為 jpg 格式,指定 jpg 的品質(zhì)效果
- 本文例子源碼下載
1. 顯示蘋果 HEIC 圖片的實(shí)現(xiàn)原理
CopyTrans HEIC for Windows 是一個(gè)解碼器插件,可以免費(fèi)家庭使用。官網(wǎng)下載地址:https://www.copytrans.net/copytransheic/
這個(gè)軟件沒有界面,安裝之后可以在 Windows 資源管理器、系統(tǒng)自帶的照片、及其他看圖軟件 (IrfanView 等) 顯示蘋果 HEIC 圖片。
C++ Builder 可以通過 Graphics::TWICImage 調(diào)用解碼器插件顯示圖片,不僅僅是剛安裝的 HEIC,還可以顯示其他 Windows 支持的格式
2. 一個(gè)最簡(jiǎn)單的顯示程序
新建一個(gè)項(xiàng)目:HEIC 測(cè)試 1
在 Form 上放置控件:
Image1:用于顯示圖片;
Label1,LabelFile:用于顯示文件名;
OpenDialog1:用于選擇打開文件;
ButtonLoad:點(diǎn)擊這個(gè)按鈕執(zhí)行打開文件。
按鈕 ButtonLoad 的點(diǎn)擊事件:
void __fastcall TForm1::ButtonLoadClick(TObject *Sender)
{
OpenDialog1->Filter = L"圖片文件|*.jpg;*.jpeg;*.png;*.gif;*.tif;*.tiff;*.heic;*.bmp";
if(OpenDialog1->Execute(Handle))
{
std::auto_ptr<Graphics::TWICImage> wic(new Graphics::TWICImage);
wic->LoadFromFile(OpenDialog1->FileName);
LabelFile->Caption = OpenDialog1->FileName;
Image1->Canvas->StretchDraw(TRect(0,0,Image1->Width,Image1->Height),wic.get());
}
}
點(diǎn)擊 ButtonLoad 選擇一個(gè) HEIC 圖片,可以看到顯示在 Image1 里面了
HEIC 測(cè)試 1 的顯示效果并不理想,因?yàn)楹涂磮D軟件相比,顯得太粗糙了。
上面截圖↑是這個(gè)測(cè)試程序的效果,下面截圖↓是看圖軟件的效果
3. 高品質(zhì)顯示效果,保持縱橫比縮放
- 發(fā)現(xiàn)問題:經(jīng)過測(cè)試發(fā)現(xiàn)顯示效果差的原因是使用 Canvas->StretchDraw 進(jìn)行縮放引起的,其他環(huán)節(jié)都沒有問題。
- 解決方法:通過 API 函數(shù) SetStretchBltMode 把縮放設(shè)為 HALFTONE 模式,使用 StretchBlt 縮放可以進(jìn)行高品質(zhì)顯示。
新建一個(gè)項(xiàng)目:HEIC 測(cè)試 2
控件 | 描述 | Anchors | …… | …… | …… |
---|---|---|---|---|---|
PaintBox1 | 顯示圖片 | ?akLeft | ?akTop | ?akRight | ?akBottom |
Label1 | "文件:" | ?akLeft | ?akBottom | ||
Label2 | "JPEG 畫質(zhì)" | ?akLeft | ?akBottom | ||
LabelFile | 顯示文件名 | ?akLeft | ?akBottom | ||
LabelQuality | JPEG 畫質(zhì)值 | ?akRight | ?akBottom | ||
TrackBarQuality | JPEG 畫質(zhì)滑動(dòng)條 | ?akLeft | ?akRight | ?akBottom | |
ButtonLoad | 點(diǎn)擊這個(gè)按鈕加載圖片 | ?akRight | ?akBottom | ||
ButtonToJpg | 點(diǎn)擊這個(gè)按鈕轉(zhuǎn)為 jpg 文件 | ?akRight | ?akBottom | ||
OpenDialog1 | 選擇打開圖片的對(duì)話框 | ? | |||
SaveDialog1 | 選擇保存圖片的對(duì)話框 | ? |
打開 Form 的頭文件:
在類的 private: 里面添加一個(gè)位圖的定義,public: 里面添加析構(gòu)函數(shù):
private: // User declarations
Graphics::TBitmap *bmp;
public: // User declarations
__fastcall TForm1(TComponent* Owner);
__fastcall ~TForm1();
打開 Form 的 cpp 文件:
在構(gòu)造函數(shù) TForm1::TForm1 里面添加內(nèi)容;
添加析構(gòu)函數(shù) TForm1::~TForm1 的實(shí)現(xiàn);
添加 PaintBox1 的 OnPaint 畫圖事件的實(shí)現(xiàn);
添加 ButtonLoad 的 OnClick 點(diǎn)擊事件的實(shí)現(xiàn):
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
LabelFile->Caption = L"";
bmp = new Graphics::TBitmap;
}
//---------------------------------------------------------------------------
__fastcall TForm1::~TForm1()
{
delete bmp;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::PaintBox1Paint(TObject *Sender)
{
if(bmp->Width>0 && bmp->Height>0)
{
int iPaintW = PaintBox1->Width;
int iPaintH = PaintBox1->Height;
TRect r(0,0,iPaintW,iPaintH);
int iRatioW = iPaintH * bmp->Width / bmp->Height;
int iRatioH = iPaintW * bmp->Height / bmp->Width;
if(iRatioW < iPaintW) // 為了保證縱橫比,需要減少寬度
{
r.Left = (iPaintW - iRatioW) / 2;
r.Right = r.Left + iRatioW;
}
if(iRatioH < iPaintH) // 為了保證縱橫比,需要減少高度
{
r.Top = (iPaintH - iRatioH) / 2;
r.Bottom = r.Top + iRatioH;
}
// PaintBox1->Canvas->StretchDraw(r,bmp); // StretchDraw():低品質(zhì)縮放
::SetStretchBltMode(PaintBox1->Canvas->Handle, HALFTONE); // 設(shè)定 ::StretchBlt() 模式:高品質(zhì)縮放
::SetBrushOrgEx(PaintBox1->Canvas->Handle, 0, 0, NULL); // MSDN: SetBrushOrgEx must be called after setting the HALFTONE mode to avoid brush misalignment.
::StretchBlt(PaintBox1->Canvas->Handle, r.Left,r.Top,r.Width(),r.Height(), bmp->Canvas->Handle, 0,0,bmp->Width,bmp->Height, SRCCOPY);
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ButtonLoadClick(TObject *Sender)
{
OpenDialog1->Filter = L"圖片文件|*.jpg;*.jpeg;*.png;*.gif;*.tif;*.tiff;*.heic;*.bmp";
if(OpenDialog1->Execute(Handle))
{
std::auto_ptr<Graphics::TWICImage> wic(new Graphics::TWICImage);
wic->LoadFromFile(OpenDialog1->FileName);
LabelFile->Caption = OpenDialog1->FileName;
bmp->Assign(wic.get());
PaintBox1->Invalidate();
}
}
//---------------------------------------------------------------------------
為了提高效率,使用一個(gè)位圖保存解碼之后的圖片,每次刷新顯示只需要把這個(gè)位圖縮放到合適比例顯示到 PaintBox1 里面,而不是每次顯示都重新讀取文件和解碼。顯示的時(shí)候,使用了 SetStretchBltMode 和 StretchBlt 替換 Canvas->StretchDraw 來提高顯示效果。
運(yùn)行結(jié)果:
以下截圖為 HEIC 測(cè)試 2 的運(yùn)行效果。
4. 轉(zhuǎn)為 jpg 格式,指定 jpg 的品質(zhì)效果
TJPEGImage 的 CompressionQuality 為生成的 jpg 文件的品質(zhì)效果,可以設(shè) 0 到 100 之間的數(shù)值,數(shù)值越大效果越好,文件也越大;數(shù)值越小效果越差,文件也越小?;瑒?dòng)條 TrackBarQuality 的范圍,即 Min 和 Max 屬性設(shè)為 0 和 100,PageSize 和 Frequency 屬性設(shè)為 10,LineSize 屬性設(shè)為 1。
以下代碼為 TrackBarQuality 的 OnChange 事件和 ButtonToJpg 的 OnClick 事件。
TrackBarQuality 的 OnChange 事件里面只是顯示了滑動(dòng)條的位置,ButtonToJpg 的 OnClick 事件里面把解碼之后的位圖 bmp 按照滑動(dòng)條的位置設(shè)為生成 jpg 文件的品質(zhì)效果,轉(zhuǎn)為 jpg 格式存盤。
void __fastcall TForm1::TrackBarQualityChange(TObject *Sender)
{
LabelQuality->Caption = IntToStr(TrackBarQuality->Position) + L"%";
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ButtonToJpgClick(TObject *Sender)
{
if(LabelFile->Caption == L"")
{
ShowMessage(L"請(qǐng)先加載圖片");
return;
}
SaveDialog1->DefaultExt = L"jpg";
SaveDialog1->Filter = L"JPEG 圖片|*.jpg";
SaveDialog1->Options = SaveDialog1->Options << ofOverwritePrompt;
if(SaveDialog1->Execute())
{
std::auto_ptr<Imaging::Jpeg::TJPEGImage> jpg(new Imaging::Jpeg::TJPEGImage);
jpg->CompressionQuality = TrackBarQuality->Position; // 1 - 100
jpg->Assign(bmp);
jpg->SaveToFile(SaveDialog1->FileName);
ShowMessage(L"成功保存文件:" + SaveDialog1->FileName);
}
}
//---------------------------------------------------------------------------
要注意的是,直接用 Assign 把 Graphics::TWICImage 轉(zhuǎn)為 Imaging::Jpeg::TJPEGImage 無法指定生成 jpg 文件的品質(zhì)效果,只有先解碼為位圖 Graphics::TBitmap,然后再轉(zhuǎn)為 jpg 才可以指定生成 jpg 的品質(zhì)效果。
如果要轉(zhuǎn)為 bmp 可以直接把解碼之后的 bmp 存盤,其他格式可以使用 TPngImage 、TGIFImage 等,和 TJPEGImage 的代碼類似,只要有了解碼之后的位圖,就可以保存為 C++ Builder 支持的其他格式。
本文例子源碼下載:heic-display-convert-to-jpg-src-cbuilder.rar
解碼器推薦官網(wǎng)下載:https://www.copytrans.net/copytransheic/
解碼器網(wǎng)盤備份:CopyTransHEICforWindowsv1.009.rar
(這個(gè)備份在我上傳時(shí)是最新版,但是你看到這篇文章時(shí)就不一定是最新版了)
C++ Builder 基礎(chǔ)知識(shí)
C++ Builder 編程技巧
C++ Builder 參考手冊(cè)