C++ Builder 顯示蘋果 HEIC 圖片及轉(zhuǎn)換為 jpg 等圖片格式

  • 顯示蘋果 HEIC 圖片的實現(xiàn)原理
  • 一個最簡單的顯示程序
  • 高品質(zhì)顯示效果,保持縱橫比縮放
  • 轉(zhuǎn)為 jpg 格式,指定 jpg 的品質(zhì)效果
  • 本文例子源碼下載

1. 顯示蘋果 HEIC 圖片的實現(xiàn)原理

CopyTrans HEIC for Windows 是一個解碼器插件,可以免費家庭使用。官網(wǎng)下載地址:https://www.copytrans.net/copytransheic/

這個軟件沒有界面,安裝之后可以在 Windows 資源管理器、系統(tǒng)自帶的照片、及其他看圖軟件 (IrfanView 等) 顯示蘋果 HEIC 圖片。

C++ Builder 可以通過 Graphics::TWICImage 調(diào)用解碼器插件顯示圖片,不僅僅是剛安裝的 HEIC,還可以顯示其他 Windows 支持的格式

2. 一個最簡單的顯示程序

新建一個項目:HEIC 測試 1
在 Form 上放置控件:
Image1:用于顯示圖片;
Label1,LabelFile:用于顯示文件名;
OpenDialog1:用于選擇打開文件;
ButtonLoad:點擊這個按鈕執(zhí)行打開文件。

在 Form 上放置控件

按鈕 ButtonLoad 的點擊事件:

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());
    }
}

點擊 ButtonLoad 選擇一個 HEIC 圖片,可以看到顯示在 Image1 里面了

執(zhí)行結(jié)果

HEIC 測試 1 的顯示效果并不理想,因為和看圖軟件相比,顯得太粗糙了。
上面截圖↑是這個測試程序的效果,下面截圖↓是看圖軟件的效果

看圖軟件的效果

3. 高品質(zhì)顯示效果,保持縱橫比縮放

  • 發(fā)現(xiàn)問題:經(jīng)過測試發(fā)現(xiàn)顯示效果差的原因是使用 Canvas->StretchDraw 進行縮放引起的,其他環(huán)節(jié)都沒有問題。
  • 解決方法:通過 API 函數(shù) SetStretchBltMode 把縮放設(shè)為 HALFTONE 模式,使用 StretchBlt 縮放可以進行高品質(zhì)顯示。

新建一個項目:HEIC 測試 2

在 Form 上放置控件
控件 描述 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ì)滑動條 ?akLeft ?akRight ?akBottom
ButtonLoad 點擊這個按鈕加載圖片 ?akRight ?akBottom
ButtonToJpg 點擊這個按鈕轉(zhuǎn)為 jpg 文件 ?akRight ?akBottom
OpenDialog1 選擇打開圖片的對話框 ?
SaveDialog1 選擇保存圖片的對話框 ?
Anchors 屬性

打開 Form 的頭文件:
在類的 private: 里面添加一個位圖的定義,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 的實現(xiàn);
添加 PaintBox1 的 OnPaint 畫圖事件的實現(xiàn);
添加 ButtonLoad 的 OnClick 點擊事件的實現(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();
    }
}
//---------------------------------------------------------------------------

為了提高效率,使用一個位圖保存解碼之后的圖片,每次刷新顯示只需要把這個位圖縮放到合適比例顯示到 PaintBox1 里面,而不是每次顯示都重新讀取文件和解碼。顯示的時候,使用了 SetStretchBltMode 和 StretchBlt 替換 Canvas->StretchDraw 來提高顯示效果。

運行結(jié)果:
以下截圖為 HEIC 測試 2 的運行效果。

HEIC 測試 2 運行結(jié)果
HEIC 測試 2 運行結(jié)果
HEIC 測試 2 運行結(jié)果

4. 轉(zhuǎn)為 jpg 格式,指定 jpg 的品質(zhì)效果

TJPEGImage 的 CompressionQuality 為生成的 jpg 文件的品質(zhì)效果,可以設(shè) 0 到 100 之間的數(shù)值,數(shù)值越大效果越好,文件也越大;數(shù)值越小效果越差,文件也越小?;瑒訔l TrackBarQuality 的范圍,即 Min 和 Max 屬性設(shè)為 0 和 100,PageSize 和 Frequency 屬性設(shè)為 10,LineSize 屬性設(shè)為 1。

以下代碼為 TrackBarQuality 的 OnChange 事件和 ButtonToJpg 的 OnClick 事件。
TrackBarQuality 的 OnChange 事件里面只是顯示了滑動條的位置,ButtonToJpg 的 OnClick 事件里面把解碼之后的位圖 bmp 按照滑動條的位置設(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"請先加載圖片");
        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
(這個備份在我上傳時是最新版,但是你看到這篇文章時就不一定是最新版了)


C++ Builder 基礎(chǔ)知識
C++ Builder 編程技巧
C++ Builder 參考手冊

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容