如何在Delphi中使用WIC创建无损的jpg [英] How to create a lossless jpg using WIC in Delphi

查看:159
本文介绍了如何在Delphi中使用WIC创建无损的jpg的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码可以使用默认选项从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 to PROPBAG2_TYPE_DATA.
  • vt needs to be set to VT_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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆