2017-02-14 120 views
3

我使用Delphi XE和TWICImage類進行圖像處理。 我想知道是否有任何方式設置JPEG圖片壓縮質量?TWICImage,如何設置jpeg壓縮質量?

procedure TfrmMain.Button2Click(Sender: TObject); 
var 
    wic: TWICImage; 
begin 
    wic := TWICImage.Create; 
    try 
    wic.LoadFromFile('sample-BMP.bmp'); 
    wic.ImageFormat := wifJpeg; 
    // ... before saving I want to set low compression quality 
    wic.SaveToFile('sample-JPG.jpg'); 
    finally 
    wic.Free; 
    end; 
end; 
+1

我認爲你需要創建一個'TJPegImage'並分配'TWICImage'它,使用'CompressionQuality'財產,最後保存圖像'設置壓縮質量TJPegImage.SaveToFile ('sample-JPG.jpg');' – RepeatUntil

+2

我非常懷疑這一點。我希望這個想法完全避免TJpegImage。 –

回答

4

WIC的VCL包裝是有限的。它不提供任何方法來指定圖像質量。我將對該代碼中完全沒有錯誤檢查視而不見。 Ergh!

我想你將需要使用原始的COM API滾動自己的代碼。它可能是這個樣子:

uses 
    System.SysUtils, 
    System.Variants, 
    System.Win.ComObj, 
    Winapi.Windows, 
    Winapi.Wincodec, 
    Winapi.ActiveX, 
    Vcl.Graphics; 

procedure SaveBitmapAsJpeg(Bitmap: TBitmap; ImageQuality: Single; FileName: string); 
const 
    PROPBAG2_TYPE_DATA = 1; 
var 
    ImagingFactory: IWICImagingFactory; 
    Width, Height: Integer; 
    Stream: IWICStream; 
    Encoder: IWICBitmapEncoder; 
    Frame: IWICBitmapFrameEncode; 
    PropBag: IPropertyBag2; 
    PropBagOptions: TPropBag2; 
    V: Variant; 
    PixelFormat: TGUID; 
    Buffer: TBytes; 
    BitmapInfo: TBitmapInfo; 
    hBmp: HBITMAP; 
    WICBitmap: IWICBitmap; 
    Rect: WICRect; 
begin 
    Width := Bitmap.Width; 
    Height := Bitmap.Height; 

    OleCheck(
    CoCreateInstance(CLSID_WICImagingFactory, nil, CLSCTX_INPROC_SERVER 
     or CLSCTX_LOCAL_SERVER, IUnknown, ImagingFactory) 
); 

    OleCheck(ImagingFactory.CreateStream(Stream)); 
    OleCheck(Stream.InitializeFromFilename(PChar(FileName), GENERIC_WRITE)); 
    OleCheck(ImagingFactory.CreateEncoder(GUID_ContainerFormatJpeg, GUID_NULL, Encoder)); 
    OleCheck(Encoder.Initialize(Stream, WICBitmapEncoderNoCache)); 
    OleCheck(Encoder.CreateNewFrame(Frame, PropBag)); 

    PropBagOptions := Default(TPropBag2); 
    PropBagOptions.pstrName := 'ImageQuality'; 
    PropBagOptions.dwType := PROPBAG2_TYPE_DATA; 
    PropBagOptions.vt := VT_R4; 
    V := VarAsType(ImageQuality, varSingle); 
    OleCheck(PropBag.Write(1, @PropBagOptions, @V)); 
    OleCheck(Frame.Initialize(PropBag)); 
    OleCheck(Frame.SetSize(Width, Height)); 
    if Bitmap.AlphaFormat=afDefined then begin 
    PixelFormat := GUID_WICPixelFormat32bppBGRA 
    end else begin 
    PixelFormat := GUID_WICPixelFormat32bppBGR; 
    end; 
    Bitmap.PixelFormat := pf32bit; 
    SetLength(Buffer, 4*Width*Height); 
    BitmapInfo := Default(TBitmapInfo); 
    BitmapInfo.bmiHeader.biSize := SizeOf(BitmapInfo); 
    BitmapInfo.bmiHeader.biWidth := Width; 
    BitmapInfo.bmiHeader.biHeight := -Height; 
    BitmapInfo.bmiHeader.biPlanes := 1; 
    BitmapInfo.bmiHeader.biBitCount := 32; 
    hBmp := Bitmap.Handle; 
    GetDIBits(Bitmap.Canvas.Handle, hBmp, 0, Height, @Buffer[0], BitmapInfo, 
    DIB_RGB_COLORS); 
    OleCheck(ImagingFactory.CreateBitmapFromMemory(Width, Height, PixelFormat, 
    4*Width, Length(Buffer), @Buffer[0], WICBitmap)); 
    Rect.X := 0; 
    Rect.Y := 0; 
    Rect.Width := Width; 
    Rect.Height := Height; 
    OleCheck(Frame.WriteSource(WICBitmap, @Rect)); 
    OleCheck(Frame.Commit); 
    OleCheck(Encoder.Commit); 
end; 

傳遞0和1之間的圖像質量值,0爲最低質量(高壓縮)和1爲最高質量(最低壓縮)。

我已經廣泛使用的兩個問題和答案在這裏找到:How to create a lossless jpg using WIC in Delphi

我也從VCL源寬鬆借來的代碼來創建IWICBitmap。如果您想繼續使用TWICBitmap,則可以這樣做,並使用其Handle屬性獲取IWICBitmap。這會產生這樣的代碼:

uses 
    System.Variants, 
    System.Win.ComObj, 
    Winapi.Windows, 
    Winapi.Wincodec, 
    Winapi.ActiveX, 
    Vcl.Graphics; 

procedure SaveWICImageAsJpeg(WICImage: TWICImage; ImageQuality: Single; 
    FileName: string); 
const 
    PROPBAG2_TYPE_DATA = 1; 
var 
    ImagingFactory: IWICImagingFactory; 
    Width, Height: Integer; 
    Stream: IWICStream; 
    Encoder: IWICBitmapEncoder; 
    Frame: IWICBitmapFrameEncode; 
    PropBag: IPropertyBag2; 
    PropBagOptions: TPropBag2; 
    V: Variant; 
    PixelFormat: TGUID; 
    Rect: WICRect; 
begin 
    Width := WICImage.Width; 
    Height := WICImage.Height; 
    ImagingFactory := WICImage.ImagingFactory; 
    OleCheck(ImagingFactory.CreateStream(Stream)); 
    OleCheck(Stream.InitializeFromFilename(PChar(FileName), GENERIC_WRITE)); 
    OleCheck(ImagingFactory.CreateEncoder(GUID_ContainerFormatJpeg, GUID_NULL, Encoder)); 
    OleCheck(Encoder.Initialize(Stream, WICBitmapEncoderNoCache)); 
    OleCheck(Encoder.CreateNewFrame(Frame, PropBag)); 
    PropBagOptions := Default(TPropBag2); 
    PropBagOptions.pstrName := 'ImageQuality'; 
    PropBagOptions.dwType := PROPBAG2_TYPE_DATA; 
    PropBagOptions.vt := VT_R4; 
    V := VarAsType(ImageQuality, varSingle); 
    OleCheck(PropBag.Write(1, @PropBagOptions, @V)); 
    OleCheck(Frame.Initialize(PropBag)); 
    OleCheck(Frame.SetSize(Width, Height)); 
    Rect.X := 0; 
    Rect.Y := 0; 
    Rect.Width := Width; 
    Rect.Height := Height; 
    OleCheck(Frame.WriteSource(WICImage.Handle, @Rect)); 
    OleCheck(Frame.Commit); 
    OleCheck(Encoder.Commit); 
end; 
+0

Yupp,這幾乎涵蓋了它。我剛剛嘗試了一種使用TWICImage和IWICBitmapEncoder的方法,但是冰塊從此變得很薄,並且Delphi沒有提供安全線。最好只是像大衛一樣跳入COM來展示。 – Sherlock70

+0

神聖莫里!這不是我認爲的一行代碼:)大衛,你是最偉大的! – LuFang