如何在Delphi中使用WIC创建无损的jpg [英] How to create a lossless jpg using WIC in Delphi
问题描述
我有以下代码可以使用默认选项从IWICBitmapSource创建一个jpg文件:
函数SaveWICBitmapToJpgFile(WICFactory :IWICImagingFactory;
WICBitmap:IWICBitmapSource; SrcRect:TRect; FileName:string):HRESULT;
var
hr:HRESULT;
编码器:IWICBitmapEncoder;
框架:IWICBitmapFrameEncode;
PropBag:IPropertyBag2;
S:IWICStream;
PixelFormatGUID:WICPixelFormatGUID;
R:WICRect;
begin
hr:= WICFactory.CreateStream(S);
如果成功(hr)然后开始
hr:= S.InitializeFromFilename(PChar(FileName),GENERIC_WRITE);
结束
如果成功(hr)然后开始
hr:= WICFactory.CreateEncoder(GUID_ContainerFormatJpeg,GUID_NULL,
Encoder);
结束
如果成功(hr)然后开始
hr:= Encoder.Initialize(S,WICBitmapEncoderNoCache);
结束
如果成功(hr)然后开始
hr:= Encoder.CreateNewFrame(Frame,PropBag);
结束
如果成功(hr)然后开始
hr:= Frame.Initialize(PropBag);
结束
如果成功(hr)然后开始
hr:= Frame.SetSize(SrcRect.Width,SrcRect.Height);
结束
如果成功(hr)然后开始
PixelFormatGUID:= GUID_WICPixelFormat24bppBGR;
hr:= Frame.SetPixelFormat(PixelFormatGUID);
结束
如果成功(hr)然后开始
hr:= IfThen(PixelFormatGUID = GUID_WICPixelFormat24bppBGR,S_OK,E_FAIL);
结束
如果成功(hr)然后开始
R.X:= SrcRect.Left;
R.Y:= SrcRect.Top;
R.Width:= SrcRect.Width;
R.Height:= SrcRect.Height;
Frame.WriteSource(WICBitmap,@R);
结束
如果成功(hr)然后开始
hr:= Frame.Commit;
结束
如果成功(hr)然后开始
hr:= Encoder.Commit;
结束
结果:= hr;
end;
我想更改编解码器选项以产生无损的jpg。当我明白我在MSDN中阅读的内容时,我必须使用IPropertyBag2来实现这一点。尽管没有一个关于如何做的线索,我尝试在框架创建和框架初始化之间插入这个代码:
var
[...]
PropBagOptions:TPropBag2;
V:变体;
[...]
如果成功(hr)然后开始
FillChar(PropBagOptions,SizeOf(PropBagOptions),0);
PropBagOptions.pstrName:='ImageQuality';
V:= 1.0;
hr:= PropBag.Write(1,@PropBagOptions,@V);
结束
它没有工作:hr = 0x88982F8E(WINCODEC_ERR_PROPERTYUNEXPECTEDTYPE)。 MSDN说 here ImageQuality属性的类型是VT_R4,但是由于我以前从未使用过Variant,我不知道如何写。而且我甚至不确定压缩确实是无损的。
如何修改我的代码,使其产生质量1.0的JPG,并且它将是无损的?
我没有这方面的经验,但这里是我阅读您链接到的文档的最佳建议。 / p>
首先,我想你需要指定更多的 PropBagOptions
的成员:
-
dwType
需要设置为PROPBAG2_TYPE_DATA
。 -
vt
需要设置为VT_R4
。
您还需要确保变体真的是 VT_R4
。这是一个4字节的真实的,在Delphi中,类型为 varSingle
的变体。
V:= VarAsType(1.0,varSingle);
我认为应该完成。
将它放在一起,看起来像这样:
FillChar(PropBagOptions,SizeOf(PropBagOptions),0);
PropBagOptions.pstrName:='ImageQuality';
PropBagOptions.dwType:= PROPBAG2_TYPE_DATA;
PropBagOptions.vt:= VT_R4;
V:= VarAsType(1.0,varSingle);
hr:= PropBag.Write(1,@PropBagOptions,@V);
关于JPEG质量1.0是否无损, 不是这样。这是一个已经很好地涵盖的问题:当质量是Jpeg无损时设置为100?
I have the following code working to create a jpg file out of a IWICBitmapSource with defaults options:
function SaveWICBitmapToJpgFile(WICFactory: IWICImagingFactory;
WICBitmap: IWICBitmapSource; SrcRect: TRect; FileName: string): HRESULT;
var
hr: HRESULT;
Encoder: IWICBitmapEncoder;
Frame: IWICBitmapFrameEncode;
PropBag: IPropertyBag2;
S: IWICStream;
PixelFormatGUID: WICPixelFormatGUID;
R: WICRect;
begin
hr := WICFactory.CreateStream(S);
if Succeeded(hr) then begin
hr := S.InitializeFromFilename(PChar(FileName), GENERIC_WRITE);
end;
if Succeeded(hr) then begin
hr := WICFactory.CreateEncoder(GUID_ContainerFormatJpeg, GUID_NULL,
Encoder);
end;
if Succeeded(hr) then begin
hr := Encoder.Initialize(S, WICBitmapEncoderNoCache);
end;
if Succeeded(hr) then begin
hr := Encoder.CreateNewFrame(Frame, PropBag);
end;
if Succeeded(hr) then begin
hr := Frame.Initialize(PropBag);
end;
if Succeeded(hr) then begin
hr := Frame.SetSize(SrcRect.Width, SrcRect.Height);
end;
if Succeeded(hr) then begin
PixelFormatGUID := GUID_WICPixelFormat24bppBGR;
hr := Frame.SetPixelFormat(PixelFormatGUID);
end;
if Succeeded(hr) then begin
hr := IfThen(PixelFormatGUID = GUID_WICPixelFormat24bppBGR, S_OK, E_FAIL);
end;
if Succeeded(hr) then begin
R.X := SrcRect.Left;
R.Y := SrcRect.Top;
R.Width := SrcRect.Width;
R.Height := SrcRect.Height;
Frame.WriteSource(WICBitmap, @R);
end;
if Succeeded(hr) then begin
hr := Frame.Commit;
end;
if Succeeded(hr) then begin
hr := Encoder.Commit;
end;
Result := hr;
end;
I would like to change the codec options to produce a lossless jpg. As I understood what I read in MSDN, I have to use IPropertyBag2 to achieve this. Despite not having a clue on how to do it, I tried inserting this code between the Frame creation and the Frame initialization:
var
[...]
PropBagOptions: TPropBag2;
V: Variant;
[...]
if Succeeded(hr) then begin
FillChar(PropBagOptions, SizeOf(PropBagOptions), 0);
PropBagOptions.pstrName := 'ImageQuality';
V := 1.0;
hr := PropBag.Write(1, @PropBagOptions, @V);
end;
It did not work: hr = 0x88982F8E (WINCODEC_ERR_PROPERTYUNEXPECTEDTYPE). MSDN says here that the type of the "ImageQuality" property is VT_R4, but as I never used a Variant before, I am not sure how to write that. And I am not even sure that the compression will indeed be lossless.
How could I modify my code to make it produce a quality 1.0 jpg, and will it be lossless?
I've no experience of this, but here's my best suggestions based on reading the documentation that you have linked to.
First of all, I think you need to specify more of the members of PropBagOptions
:
dwType
needs to be set toPROPBAG2_TYPE_DATA
.vt
needs to be set toVT_R4
.
You also need to make sure that the variant really is VT_R4
. That's a 4 byte real, in Delphi terms a variant of type varSingle
.
V := VarAsType(1.0, varSingle);
I think that should get it done.
Putting it all together, it looks like this:
FillChar(PropBagOptions, SizeOf(PropBagOptions), 0);
PropBagOptions.pstrName := 'ImageQuality';
PropBagOptions.dwType := PROPBAG2_TYPE_DATA;
PropBagOptions.vt := VT_R4;
V := VarAsType(1.0, varSingle);
hr := PropBag.Write(1, @PropBagOptions, @V);
As regards whether or not JPEG quality 1.0 is lossless, it is not. That's a question already well covered here: Is Jpeg lossless when quality is set to 100?
这篇关于如何在Delphi中使用WIC创建无损的jpg的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!