zoukankan      html  css  js  c++  java
  • GdiPlus[55]: 图像(七) 图像编码的参数


    通过 IGPImage.GetEncoderParameterList 可以获取指定编码格式的参数列表;

    通过此列表可以遍历出各参数的指针: PGPNativeEncoderParameter(TGPNativeEncoderParameter 的指针);

    TGPNativeEncoderParameter 是一个结构体:
    TGPNativeEncoderParameter = record
      Guid: TGUID;                              { 参数标识 }
      NumberOfValues: ULONG;                    { 参数数组的元素数 }
      ValueType: TGPEncoderParameterValueType;  { 参数类型 }
      Value: Pointer;                           { 参数数据指针 }
    end;
    
    //其中的 TGPEncoderParameterValueType 是个枚举, 枚举值有:
    EncoderParameterValueTypeByte          = 1 { 字节数组 }
    EncoderParameterValueTypeASCII         = 2 { PAnsiChar }
    EncoderParameterValueTypeShort         = 3 { Word }
    EncoderParameterValueTypeLong          = 4 { Cardinal }
    EncoderParameterValueTypeRational      = 5 { Cardinal/Cardinal; 第一个数是分子, 第二个数是分母 }
    EncoderParameterValueTypeLongRange     = 6 { 一对 Cardinal, 表示一个数值范围 }
    EncoderParameterValueTypeUndefined     = 7 { 可包含任何数据类型的字节数组 }
    EncoderParameterValueTypeRationalRange = 8 { 四个整数: Cardinal/Cardinal, Cardinal/Cardinal }
    EncoderParameterValueTypePointer       = 9 { 指针 }
    
    //EncoderParameterValueTypeRationalRange 中的四个整数通过分数运算得到的两个值: 最小值...最大值.
    

    每个编码器的参数肯定会有区别, 下面代码获取了 JPEG 编码器所能支持的参数信息:
    uses GdiPlus;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      Image: IGPImage;
      Parameters: IGPEncoderParameters;
      Param: PGPNativeEncoderParameter;
    begin
      Image := TGPBitmap.Create(1, 1);
      Parameters := Image.GetEncoderParameterList(TGPImageFormat.Jpeg.CodecId);
    
      Memo1.Clear;
      for Param in Parameters do with Memo1.Lines do
      begin
        Add(Format('Guid: %s', [GUIDToString(Param.Guid)]));
        Add(Format('NumberOfValues: %d', [Param.NumberOfValues]));
        Add(Format('ValueType: %d', [Ord(Param.ValueType)]));
        Add(Format('Value: $%p', [Param.Value]));
        Add(EmptyStr);
      end;
    end;
    (* 结果:
      Guid: {8D0EB2D1-A58E-4EA8-AA14-108074B7B6F9}
      NumberOfValues: 5
      ValueType: 4
      Value: $00AD8190
    
      Guid: {1D5BE4B5-FA4A-452D-9CDD-5DB35105E7EB}
      NumberOfValues: 1
      ValueType: 6
      Value: $00AD81A4
    
      Guid: {EDB33BCE-0266-4A77-B904-27216099E717}
      NumberOfValues: 0
      ValueType: 3
      Value: $00AD81AC
    
      Guid: {F2E455DC-09B3-4316-8260-676ADA32481C}
      NumberOfValues: 0
      ValueType: 3
      Value: $00AD81AC
    *)
    

    IGPImage.GetEncoderParameterList 方法得到的类型是: IGPEncoderParameters;

    IGPImage.Save 方法就有一个 IGPEncoderParameters 类型的默认参数, 通过它可以传入编码参数.

    编码参数有很多类型, 譬如 EncoderQuality 是决定图片压缩比率的.

    下面的例子在保存 JPG 文件时使用了三种不同的质量参数(压缩级别):



    uses GdiPlus;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      Prams: IGPEncoderParameters;
      Image: IGPImage;
      Graphics: IGPGraphics;
      Quality: Integer;
    begin
      ChDir('C:\GdiPlusImg\');
      Image := TGPImage.Create('GrapeBunch.bmp');
    
      Prams := TGPEncoderParameters.Create;
      Quality := 1;
      Prams.Add(EncoderQuality, Quality);
      Image.Save('GrapeBunch_1.jpg', TGPImageFormat.Jpeg, Prams);
    
      Prams.Clear;
      Quality := 50;
      Prams.Add(EncoderQuality, Quality);
      Image.Save('GrapeBunch_50.jpg', TGPImageFormat.Jpeg, Prams);
    
      Prams.Clear;
      Quality := 100;
      Prams.Add(EncoderQuality, Quality);
      Image.Save('GrapeBunch_100.jpg', TGPImageFormat.Jpeg, Prams);
    
      //显示
      Graphics := TGPGraphics.Create(Handle);
      Image := TGPImage.Create('GrapeBunch_1.jpg');
      Graphics.DrawImage(Image, 10, 10);
    
      Graphics.TranslateTransform(Image.Width + 10, 0);
      Image := TGPImage.Create('GrapeBunch_50.jpg');
      Graphics.DrawImage(Image, 10, 10);
    
      Graphics.TranslateTransform(Image.Width + 10, 0);
      Image := TGPImage.Create('GrapeBunch_100.jpg');
      Graphics.DrawImage(Image, 10, 10);
    end;
    

    IGPEncoderParameters 的成员:
    IGPEncoderParameters.GetEnumerator;
    IGPEncoderParameters.Clear;
    IGPEncoderParameters.Add();
    IGPEncoderParameters.Count;
    IGPEncoderParameters.Param[];
    IGPEncoderParameters.NativeParams;
    
    //其中的 Add 方法有多种重载, 这便于添加各种类型的数据; 参数类型常数:
    EncoderCompression      { 压缩 }
    EncoderColorDepth       { 颜色深度 }
    EncoderScanMethod       { 扫描方法 }
    EncoderVersion          { 版本 }
    EncoderRenderMethod     { 呈现方法 }
    EncoderQuality          { 质量 }
    EncoderTransformation   { 转换 }
    EncoderLuminanceTable   { 亮度表 }
    EncoderChrominanceTable { 色度表 }
    EncoderSaveFlag         { 保存标志 }
    CodecIImageBytes        {  }
    { 下面是 GDI+1.1 才开始支持的: }
    EncoderColorSpace       {  }
    EncoderImageItems       {  }
    EncoderSaveAsCMYK       {  }
    

    五种编码器(BMP、JPEG、GIF、TIFF、PNG)分别能支持哪些 "参数类型" 呢?
    支持的参数类型的参数又是什么格式的呢? 尽管 Add 方法已准备好了多种重载, 用哪个呢?

    下面的程序列出了各种编码器的参数信息:

    uses GdiPlus;
    
    const
      ParamValueTypeArr: array[1..9] of string = (
        'ValueTypeByte',
        'ValueTypeASCII',
        'ValueTypeShort',
        'ValueTypeLong',
        'ValueTypeRational',
        'ValueTypeLongRange',
        'ValueTypeUndefined',
        'ValueTypeRationalRange',
        'ValueTypePointer'
      );
    
    //自定义函数
    function GetGuidName(g: TGUID): string;
    var
      s: string;
    begin
      s := EmptyStr;
      if IsEqualGUID(g, EncoderCompression) then s := 'EncoderCompression';
      if IsEqualGUID(g, EncoderColorDepth) then s := 'EncoderColorDepth';
      if IsEqualGUID(g, EncoderScanMethod) then s := 'EncoderScanMethod';
      if IsEqualGUID(g, EncoderVersion) then s := 'EncoderVersion';
      if IsEqualGUID(g, EncoderRenderMethod) then s := 'EncoderRenderMethod';
      if IsEqualGUID(g, EncoderQuality) then s := 'EncoderQuality';
      if IsEqualGUID(g, EncoderTransformation) then s := 'EncoderTransformation';
      if IsEqualGUID(g, EncoderLuminanceTable) then s := 'EncoderLuminanceTable';
      if IsEqualGUID(g, EncoderChrominanceTable) then s := 'EncoderChrominanceTable';
      if IsEqualGUID(g, EncoderSaveFlag) then s := 'EncoderSaveFlag';
      if IsEqualGUID(g, CodecIImageBytes) then s := 'CodecIImageBytes';
      {$IF (GDIPVER >= $0110)}
      if IsEqualGUID(g, EncoderColorSpace) then s := 'EncoderColorSpace';
      if IsEqualGUID(g, EncoderImageItems) then s := 'EncoderImageItems';
      if IsEqualGUID(g, EncoderSaveAsCMYK) then s := 'EncoderSaveAsCMYK';
      {$IFEND}
      Result := s;
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      Image: IGPImage;
      Parameters: IGPEncoderParameters;
      Param: PGPNativeEncoderParameter;
      Encoder: IGPImageCodecInfo;
    begin
      Image := TGPBitmap.Create(1, 1);
    
      Memo1.Clear;
      for Encoder in TGPImageCodecInfo.GetImageEncoders do with Memo1.Lines do
      begin
        Parameters := Image.GetEncoderParameterList(Encoder.ClsId);
    
        Add('----------------------');
        Add(Format('编码器类型: %s', [Encoder.FormatDescription]));
        if Parameters.Count = 0 then
        begin
          Add('无参数');
          Add(EmptyStr);
          Continue;
        end;
    
        Add(Format('参数个数: %d', [Parameters.Count]));
        for Param in Parameters do
        begin
          Add(Format('参数类型: %s', [GetGuidName(Param.Guid)]));
          Add(Format('参数值类型: %s', [ParamValueTypeArr[Ord(Param.ValueType)]]));
          Add(Format('参数值个数: %d', [Param.NumberOfValues]));
          Add(Format('参数值指针: $%p', [Param.Value]));
          Add(EmptyStr);
        end;
      end;
    end;
    (* 显示结果:
      ----------------------
      编码器类型: BMP
      无参数
    
      ----------------------
      编码器类型: JPEG
      参数个数: 4
      参数类型: EncoderTransformation
      参数值类型: ValueTypeLong
      参数值个数: 5
      参数值指针: $00AD8190
    
      参数类型: EncoderQuality
      参数值类型: ValueTypeLongRange
      参数值个数: 1
      参数值指针: $00AD81A4
    
      参数类型: EncoderLuminanceTable
      参数值类型: ValueTypeShort
      参数值个数: 0
      参数值指针: $00AD81AC
    
      参数类型: EncoderChrominanceTable
      参数值类型: ValueTypeShort
      参数值个数: 0
      参数值指针: $00AD81AC
    
      ----------------------
      编码器类型: GIF
      无参数
    
      ----------------------
      编码器类型: TIFF
      参数个数: 3
      参数类型: EncoderCompression
      参数值类型: ValueTypeLong
      参数值个数: 5
      参数值指针: $00AD8190
    
      参数类型: EncoderColorDepth
      参数值类型: ValueTypeLong
      参数值个数: 5
      参数值指针: $00AD81A4
    
      参数类型: EncoderSaveFlag
      参数值类型: ValueTypeLong
      参数值个数: 1
      参数值指针: $00AD81B8
    
      ----------------------
      编码器类型: PNG
      无参数
    *)
    

    从上面例子可以看出:

    BMP、GIF、PNG 三种编码器没有编码参数(GIF 在 GDI+1.1 中是不是支持还没有测试).

    JPEG 支持:
    EncoderTransformation (转换)
    EncoderQuality (质量)
    EncoderLuminanceTable (亮度表)
    EncoderChrominanceTable (色度表)

    TIFF 支持:
    EncoderCompression (压缩)
    EncoderColorDepth (颜色深度)
    EncoderSaveFlag (保存标志)

    进而可以得知:

    JPEG 编码的参数类型 EncoderTransformation 的可选值是:
    TGPEncoderValue(13): EncoderValueTransformRotate90
    TGPEncoderValue(14): EncoderValueTransformRotate180
    TGPEncoderValue(15): EncoderValueTransformRotate270
    TGPEncoderValue(16): EncoderValueTransformFlipHorizontal
    TGPEncoderValue(17): EncoderValueTransformFlipVertical

    JPEG 编码的参数类型 EncoderQuality 的可选值是: 0..100

    TIFF 编码的参数类型 EncoderCompression 的可选值是:
    TGPEncoderValue(2): EncoderValueCompressionLZW
    TGPEncoderValue(3): EncoderValueCompressionCCITT3
    TGPEncoderValue(4): EncoderValueCompressionCCITT4
    TGPEncoderValue(5): EncoderValueCompressionRle
    TGPEncoderValue(6): EncoderValueCompressionNone

    TIFF 编码的参数类型 EncoderColorDepth 的可选值是: 1,4,8,24,32

    这些值可以从下面程序获取:

    uses GdiPlus;
    
    var
      Image: IGPImage;
      Parameters: IGPEncoderParameters;
      p: PCardinal;
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      Image := TGPBitmap.Create(1, 1);
    end;
    
    {$PointerMath On}
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      Parameters := Image.GetEncoderParameterList(TGPImageFormat.Jpeg.CodecId);
      p := Parameters[0].Value; { EncoderTransformation }
      ShowMessageFmt('%d,%d,%d,%d,%d', [p[0],p[1],p[2],p[3],p[4]]); { 13,14,15,16,17 }
    end;
    
    procedure TForm1.Button2Click(Sender: TObject);
    begin
      Parameters := Image.GetEncoderParameterList(TGPImageFormat.Jpeg.CodecId);
      p := Parameters[1].Value; { EncoderQuality }
      ShowMessageFmt('%d..%d', [p[0],p[1]]); { 0..100 }
    end;
    
    procedure TForm1.Button3Click(Sender: TObject);
    begin
      Parameters := Image.GetEncoderParameterList(TGPImageFormat.Tiff.CodecId);
      p := Parameters[0].Value; { EncoderCompression }
      ShowMessageFmt('%d,%d,%d,%d,%d', [p[0],p[1],p[2],p[3],p[4]]); { 2,3,5,4,6 }
    end;
    
    procedure TForm1.Button4Click(Sender: TObject);
    begin
      Parameters := Image.GetEncoderParameterList(TGPImageFormat.Tiff.CodecId);
      p := Parameters[1].Value; { EncoderColorDepth }
      ShowMessageFmt('%d,%d,%d,%d,%d', [p[0],p[1],p[2],p[3],p[4]]); { 1,4,8,24,32 }
    end;
    

    下面例子通过设置 JPEG 的 EncoderTransformation 编码参数, 保存了旋转后的图片:



    uses GdiPlus;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      Graphics: IGPGraphics;
      Prams: IGPEncoderParameters;
      Image: IGPImage;
    begin
      ChDir('C:\GdiPlusImg\');
      Image := TGPImage.Create('Grapes.jpg');
    
      Prams := TGPEncoderParameters.Create;
      Prams.Add(EncoderTransformation, EncoderValueTransformRotate90);
      Image.Save('Grapes_Rotate90.jpg', TGPImageFormat.Jpeg, Prams);
    
      Graphics := TGPGraphics.Create(Handle);
      Graphics.DrawImage(Image, 10, 10, Image.Width, Image.Height);
    end;
    
    //为什么只有 JPEG 提供这种编码参数呢? 因为 jpg 文件在自动保存过程中会降低品质, 通过这种变换则不会.
    

    另外:

    1、编码参数值类型很多是 Cardinal, 这都是官方资料上的; 但 Add 函数中要的是 Integer 类型.

    2、从上面获取的信息可以知道, GDI+1.0 还无法写入 gif 动画; GDI+1.1 能不能还没有测试.

    3、通过设置 TIFF 编码器的 EncoderSaveFlag 类型参数可保存多页的 TIFF 文件, 下次接上.
  • 相关阅读:
    快速实现一个带后端服务的 Vue 项目,用云开发Vue插件!
    做好内容安全检测,和风险说「再见」(下)!
    新能力|云调用支持微信支付啦!
    获奖结果公布|2020腾讯犀牛鸟云开发校园技术布道师养成计划
    SpringMVC原理及流程解析
    Mysql梳理-关于索引/引擎与锁
    写在庚子年之前
    Spring的BeanPostProcessor后置处理器与bean的生命周期
    AQS系列(六)- Semaphore的使用及原理
    AQS系列(五)- CountDownLatch的使用及原理
  • 原文地址:https://www.cnblogs.com/del/p/1635265.html
Copyright © 2011-2022 走看看