The VCL wrapper of WIC is somewhat limited. It doesn't offer you any means to specify the image quality. And I'm going to turn a blind eye to the total absence of error checking in that code. Ergh!
I think you are going to need to roll your own code, using the raw COM API. It might look something like this:
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;
Pass an image quality value between 0 and 1, with 0 being the lowest quality (highest compression) and 1 being the highest quality (lowest compression).
I have made extensive use of both the question and answer found here: How to create a lossless jpg using WIC in Delphi
I have also borrowed liberally from the VCL source for the code to create the IWICBitmap
. If you wished to continue to use TWICBitmap
you could do so and use its Handle
property to obtain the IWICBitmap
. That would yield code like this:
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;