2017-02-14 115 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