アフターケア

ホーム What's New アフターケア ダウンロード よくあるご質問 More Secrets

最終更新日: 2009/3/30

目次

1. [書籍] P23 List 1-5-5 のコードがコンパイルエラーになる
2. [DHGL]  DrawRectangle で Canvas に矩形を描くと矩形の左の線が描かれない
3. [DHGL]、[書籍]  サンプルプログラム TextPrint のプレビュー表示がおかしい。 
4. [DHGL]、[書籍]  サンプルプログラム TextPrint2 でサンプルプログラムが強制終了する。
5. [DHGL]、[書籍]  P310 List 5-4-7 の誤り
6. [DHGL] DHGL.CNTの誤り
7 [DHGL]  メディアンカットによる減色が失敗する
8 [DHGL] C++Builder で NkMM, NkShareMemユニットを使う
9 [DHGL] DHGL は Delphi 7 Studio で使えます
10 [DHGL] PathUtilsユニットの DrawPath の不具合

1. [書籍] P23 List 1-5-5 のコードがコンパイルエラーになる。

List 1-5-5 のコードが間違っています。正しくは

procedure TForm1.Button4Click(Sender: TObject);
begin
  Canvas.Rectangle(10, 10, 30, 30);
end;
です。
先頭に戻る

2. [DHGL] DrawRectangle で Canvas に矩形を描くと矩形の線が一部描かれない

DHGLのヘルプには PathUtils ユニットのDrawRectangle は「単に Canvas 上に 矩形を描く手続としても使えますが、」と書かれていますが、これは誤りです。DrawRectangle はパスに矩形を描くための手続きで、図形を閉じるのに CloseFigure API を使っています。CloseFigure は BeginPath〜EndPath の間でしか機能しませんのでこのような現象が起きます。

DrawRectangle はパスの中に矩形を描くためだけに使用し、TCanvas に矩形を描く場合は TCanvas の Rectangle メソッドを使用してください。

同様の問題は、

DrawAngleChord
DrawChord
DrawEllipse
DrawAnglePie
DrawPie
DrawRoundRect

でも起こります。パスへではなく TCanvas に普通に図形を描く場合は、TCanvas のメソッドを使用してください。

DrawAngleArc
DrawArc

は問題ありません。

このヘルプファイルの誤りは DHGL 1.1 で修正しました。

先頭に戻る

3. [DHGL][書籍] サンプルプログラム TextPrint のプレビュー表示がおかしい。 

現象:

1
電子mail 12345@wombat.or.jp
12子34567891011121314151116

上記の単純なテキストファイル(テキスト.txt)を DHGL のサンプル Textprint の印刷プレビューで表示すると下図のように異常な表示になります。この問題は Windows 9X/ME ではおきますが、Windows NT4/2000/XP では起きません。また、たいていの場合は問題は起きないのですが、文字列パターンによって起きたり起きなかったりします。

原因

結論を先の申し上げますと、これは Windows 9X/ME のバグです。この問題は DHGL 1.1 で対処しましたが、どのような問題かを示すため、Textprint サンプルの問題を再現する最小限のコードを示します。
procedure TForm1.Button1Click(Sender: TObject);
var
  M1: TMetafile;
  M1C: TMetafileCanvas;

  M2: TMetafile;
  M2C: TMetafileCanvas;
  R: TRect;
  Text: string;
begin
  R := Rect(0, 0, Screen.Width, Screen.Height);
  M1 := TMetafile.Create;
  M1C := TMetafileCanvas.Create(M1, 0);
  M1C.Font.Size := 8;
  Text := '1'#13#10 +
          '尚子mail 12345@wombat.or.jp'#13#10 +
          '12子34567891011121314151116';
  // DrawText API で描画
  DrawText(M1C.Handle, PChar(Text), Length(Text), R,
           DT_WORDBREAK or DT_EXTERNALLEADING or DT_NOPREFIX);
  M1C.Free;

  Image1.Picture.Graphic := M1;  // 結果をイメージコントロールで表示

  M2 := TMetafile.Create;
  M2C := TMetafileCanvas.Create(M2, 0);
  M2C.Draw(0, 0, M1);
  M2C.Free;
  Image2.Picture.Graphic := M2;  // 結果をイメージコントロールで表示

  M1.SaveToFile('M1.emf');       // 結果をファイルに書き出す
  M2.SaveToFile('M2.emf');
  M2.Free;
  M1.Free;
end;

これを実行すると、下図のようにメタファイル M1 は正常ですが、メタファイル M1 を内容を描画して作成した メタファイルM2の表示が異常であることがわかります。


(左が メタファイル M1, 右がメタファイル M2 の表示)

つまり、メタファイルに DrawText API で描画すると、正常なメタファイルが作られますが、そのメタファイルをさらに別のメタファイルに描画すると文字がおかしくなるということです。これは Windows NT4/2000/XP では起きません。

出来上がった、メタファイルを分析すると、以下のようになっていました。

・M1.emf の文字表示の部分

EMR_EXTTEXTOUTA         レコード番号 = 7 タイプ = 83, 長さ = 84 Byte
  rclBounds                (0, 0, 5, 10)       
  グラフィックスモード       1                   
  スケーリング              (26.39, 26.39)      
  文字列の参照点            (0, 0)              
  描画枠                   (0, 0, 0, 0)        
  文字列                   1                   
  オプション                $00000000           
  文字間スペース           6                   
EMR_EXTTEXTOUTA         レコード番号 = 8 タイプ = 83, 長さ = 212 Byte
  rclBounds                (0, 11, 134, 21)    
  グラフィックスモード       1                   
  スケーリング              (26.39, 26.39)      
  文字列の参照点            (0, 11)             
  描画枠                   (0, 0, 0, 0)        
  文字列                   尚子mail 12345@wombat.or.jp
  オプション                $00000000           
  文字間スペース           0 11 0 11 8 5 2 2
                           3 6 6 6 6 6 7 7 6 
                        8 5 5 4 2 6 4 2 2 5 
EMR_EXTTEXTOUTA         レコード番号 = 9 タイプ = 83, 長さ = 212 Byte
  rclBounds                (0, 22, 160, 32)    
  グラフィックスモード       1                   
  スケーリング              (26.39, 26.39)      
  文字列の参照点            (0, 22)             
  描画枠                   (0, 0, 0, 0)        
  文字列                   12子34567891011121314151116
  オプション                $00000000           
  文字間スペース           6 6 0 11 6 6 6 6 6
                        6 6 6 6 6 6 6 6 6 6 
                        6 6 6 6 6 6 6 6 


M2.emf の文字表示の部分

EMR_EXTTEXTOUTA         レコード番号 = 17 タイプ = 83, 長さ = 84 Byte
  rclBounds                (0, 0, 1150, 10)    
  グラフィックスモード       1                   
  スケーリング              (26.39, 26.39)      
  文字列の参照点            (0, 0)              
  描画枠                    (0, 0, 0, 0)        
  文字列                   1                   
  オプション                $00000000           
  文字間スペース           6                   
EMR_EXTTEXTOUTA         レコード番号 = 18 タイプ = 83, 長さ = 212 Byte
  rclBounds                (0, 11, 1150, 21)   
  グラフィックスモード       1                   
  スケーリング              (26.39, 26.39)      
  文字列の参照点            (0, 11)             
  描画枠                   (0, 0, 0, 0)        
  文字列                   尚子mail 12345@wombat.or.jp
  オプション                $00000000           
  文字間スペース           0 11 0 1592 -32495 24759 952 128 
                        -32304 985 -32466 0 -32482 23880 
                           1065 2 -1 16597 0 144 -19822 -32526 
                        21917 128 1649 -32482 23581 
EMR_EXTTEXTOUTA         レコード番号 = 19 タイプ = 83, 長さ = 212 Byte
  rclBounds                (0, 22, 1150, 32)   
  グラフィックスモード       1                   
  スケーリング              (26.39, 26.39)      
  文字列の参照点            (0, 22)             
  描画枠                   (0, 0, 0, 0)        
  文字列                   12子34567891011121314151116
  オプション                $00000000           
  文字間スペース           6 6 0 -32552 24759 952 128 -32304 985 
                        -32466 0 -32481 23879 1065 2 -1 16597 
                        0 144 -19822 -32525 21916 128 1649 
                        -32482 23581 952 

この分析結果から判りますように、DrawTextAPI の出力は3つの ExtTextOut レコードでメタファイルに記録され、メタファイルからメタファイルへ描画を行うと、ExtTextOut レコードの文字間スペース(隣り合う文字の文字セルの間隔)が壊れてしまうことが判ります。

さらに解析を進めていった結果、この問題はメタファイルからメタファイルへ描画するときに起きる問題ではなく、メタファイルに ExtTextOut API で文字列を描画するときに起きる問題だとわかりました。メタファイルに文字列を描画すると、文字列は Windows 9X/ME ではExtTextOutA レコードで記録され、メタファイルの再生時は ExtTextOut API で描画されますので、Windows 9X/ME では

 

  1. メタファイルに ExtTextOut API で文字列を描くことはできない。
  2. 文字列を含むメタファイルを他のメタファイルに描画できない。

というとんでもない制限があることが判りました。但しこの現象は

ExtTextOut API で1文字の文字列を描くときは問題が起きない

ことが実験から判りました。

対処:

そこで、メタファイルに含まれる文字列(ExtTextOutA レコード)を1文字の ExtTextOutA レコードの列に直す関数 FixMetafileFor9X を開発しました。この関数で文字列を含むメタファイルを変換すると、文字列が1文字の ExtTextOutA レコードの列に変換されます。

この変換は、ExtTextOut API のオプションパラメータ、文字列描画時の背景モード、文字の傾きを考慮したかなり複雑なものになっています。詳細は DHGL 1.1 のソースコード(MetafileUtilsユニット)をご覧ください。

例えば、下記のように OrgMeta というメタファイルを他のメタファイルのキャンバス(MetaCanvas)に描く場合、

var MetaTemp: TMetafile;
  :
  :
MetaTemp := FixMetafileFor9x(OrgMeta, Printer.Handle);
try
  MetaCanvas.Draw(PaperInfo.LeftMargin+50, PaperInfo.TopMargin+50,
  MetaTemp);
finally
  MetaTemp.Free;
end;

というように描画すれば、問題は起きなくなります。

FixMetafileFor9X関数は DHGL 1.1 で、MetafileUtils ユニットに追加されました。

FixMetafileFor9X は Windows NT4/2000/XP 上ではメタファイルを変換せず、元と全く同じメタファイルを返します。

書籍の修正:

P292 List 5-2-4 を以下のように修正いたします。太字が修正部分です。

---------- List 5-2-4 ----------

function MakePreviewImage(OrgMeta: TMetafile; Ratio: Double): TMetafileEx;
var
  PaperInfo: TPaperInfo;
  Meta: TMetafileEx;
  MetaCanvas: TMetafileCanvas;
{$IFNDEF ORIGINAL} // 2002.5.22 (Ver. 1.1)
  MetaTemp: TMetafile;
{$ENDIF}
begin
  PaperInfo := GetPaperInfo;

  Meta := TMetafileEx.Create;
  try
    // 紙より大き目のメタファイルを作る
    Meta.Width := PaperInfo.PaperSize.Width + 150;
    Meta.Height := PaperInfo.PaperSize.Height + 150;
    MetaCanvas := TMetafileCanvas.Create(Meta, Printer.Handle);
    try
      // 紙のドロップシャドウを描く
      MetaCanvas.Brush.Color := clDkGray;
      MetaCanvas.FillRect(Rect(100, 100,
                               PaperInfo.PaperSize.Width+100,
                               PaperInfo.PaperSize.Height+100));
      // 紙を描く
      MetaCanvas.Brush.Color := clWhite;
      MetaCanvas.Rectangle(50, 50,
                           PaperInfo.PaperSize.Width+50,
                           PaperInfo.PaperSize.Height+50);

      // 印刷可能領域の描く
      MetaCanvas.Pen.Style := psDot;
      MetaCanvas.Rectangle(
        PaperInfo.LeftMargin+50, PaperInfo.TopMargin+50,
        PaperInfo.LeftMargin + 50 + PaperInfo.PrintableArea.Width,
        PaperInfo.TopMargin + 50 + PaperInfo.PrintableArea.Height);
      MetaCanvas.Pen.Style := psSolid;

      // 印刷可能領域にページイメージを描く
      {$IFDEF ORIGINAL} // 2002.5.22(Ver. 1.1)
      MetaCanvas.Draw(PaperInfo.LeftMargin+50, PaperInfo.TopMargin+50,
                      OrgMeta);
      {$ELSE}
      MetaTemp := FixMetafileFor9x(OrgMeta, Printer.Handle);
      try
        MetaCanvas.Draw(PaperInfo.LeftMargin+50, PaperInfo.TopMargin+50,
                        MetaTemp);
      finally
        MetaTemp.Free;
      end;
      {$ENDIF}
    finally
      MetaCanvas.Free;
    end;
    // 描画の大きさがスクリーンデバイスを基準にするようにする(Inch<>0)
    Meta.Inch := 1;
    // 描画サイズを指定に合わせる
    Meta.Width := Round(Meta.Width * Ratio);
    Meta.Height := Round(Meta.Height * Ratio);
    Result := Meta;
  except
    MEta.Free;
    raise;
  end;
end;

DHGLの修正:

Chpter5\5-2\TextPrint の MainFormU.pas を上記の書籍の修正にあわせて修正しました。この修正は DHGL 1.1 に MetafileUtils.pas の修正とともに入っています。

また MetafileUtils.pas に FixMetafileFor9X を追加しました。

4. [DHGL][書籍]  サンプルプログラム TextPrint2 でサンプルプログラムが強制終了する。

現象:

サンプル TextPrint2 で比較的大きなテキストを印刷プレビューすると、アプリケーションが異常終了する。

原因: 

この問題は Windows 9X/ME のバグのようです。Windows 9X/ME は ExtTextOutW API をサポートしており、スクリーンやプリンタへの文字列描画に問題なく使えますが、ExtTextOutW API を使ってメタファイルに文字列を大量に描画すると、アプリケーションが強制終了されてしまいます。この現象は TextOutW API でも発生します。

この現象はExtTExtOutW API を使ってメタファイルに文字列を描くだけの単純なプログラムを使って、複数の Windows 98 のマシン、WIndows ME のマシンで確認しました。

対処:

この問題を避けるには、メタファイルへの文字列の描画時、 ExtTextOutW の使用を避けるしか有りません。ところがアフターケアの4番で述べましたように ExtTextOut API をメタファイルの描画に代わりに使うことはできません。

アフターケアの4番で述べたように、ExtTextOut API で一文字づつ文字を描けば問題はおきません。

そこで ExtTextOutW API と同等のパラメータを受け取り、ExtTextOutA を使って一文字ずつ文字を描く DHGLExtTextOutW を開発いたしました。メタファイルへ文字列を描画するとき、ExtTextOutW を使うべきところに DHGLExtTextOutW を使えば問題は起きなくなります。

書籍の修正:

P369 List 6-3-3 の ExttextOutW を使っているところを

          {$IFDEF ORIGINAL} // 2002.5.22(Ver. 1.1)
          ExtTextOutW(PrintPreview1.Canvas.Handle,
                      LeftMargin - PaperInfo.LeftMargin + Offset,
                      TopMargin - PaperInfo.TopMargin +
                      WrittenLines * LineSpace,
                      0, Nil, PWideChar(WS), FittedChars, PInteger(DXs));
          {$ELSE}
          DHGLExtTextOutW(PrintPreview1.Canvas.Handle,
                      LeftMargin - PaperInfo.LeftMargin + Offset,
                      TopMargin - PaperInfo.TopMargin +
                      WrittenLines * LineSpace,
                      0, Nil, PWideChar(WS), FittedChars, PInteger(DXs));
          {$ENDIF}

に修正します。

DHGLの修正:

Chpter6\6-3\TextPrint2 の MainFormU.pas を上記の書籍の修正にあわせて修正しました。この修正は DHGL 1.1 に MetafileUtils.pas の修正とともに入っています。

また MetafileUtils.pas に DHGLExtTextOut と DHGLExtTextOutW を追加しました。

DHGLExtTextOut は 1文字の ExtTextOut API で描画する ExtTextOut API 互換ルーチン、DHGLExtTExtOutW は 1文字の ExtTextOut API で描画する ExtTextOutW API の互換ルーチンです。

尚、両ルーチンとも Windows NT/2000/XP では DHGLExtTextOut は ExtTextOut API に、 DHGLExtTextOutW は ExtTextOutW API にパラメータを渡して実行するだけです。

5. [DHGL]、[書籍] P310 List 5-4-7 の誤り

P310 List 5-4-7(DHGL サンプルの Chapter5\5-4\ColorCopiesCollateDemo)に誤りがありました。以下に修正を示します。太字が修正部分です。

procedure TMainForm.FormCreate(Sender: TObject);
var
  Settings: TPrinterSettings;
  MaxCopies: Integer;
begin
  // プリンタ設定を得る
  Settings := GetPrinterSettings;
  try
    if (Settings.pDev.dmFields and DM_COLOR) = 0 then
    begin
      // カラー印刷がサポートされていなければ、チェックボックスを
      // Disable する。
      ColorCheckBox.Enabled:= True;
    end;
    {$IFDEF ORIGINAL}
    if (Settings.pDev.dmFields and DM_COPIES) = 0 then
    {$ELSE}
    if (Settings.pDev.dmFields and DM_COPIES) <> 0 then
    {$ENDIF}
    begin
      // 部数がサポートされている場合は最大部数を取得する。
      MaxCopies := DeviceCapabilities(Settings.Device, Settings.Port,
                                      DC_COPIES, Nil,
                                      Settings.pDev);
      MaxCopiesLabel.Caption := IntToStr(MaxCopies);

      // UpDown コントロールの範囲を 1〜最大部数にする。
      CopiesUpDown.Min := 1;
      CopiesUpDown.Max := MaxCopies;
    end
    else
    begin
      {$IFDEF ORIGINAL}
      MaxCopiesLabel.Caption := '99999';
      // UpDown コントロールの範囲を 1〜最大部数にする。
      CopiesUpDown.Min := 1;
      CopiesUpDown.Max := MaxCopies;
      {$ELSE}
      MaxCopiesLabel.Caption := '9999';
      // UpDown コントロールの範囲を 1〜最大部数にする。
      CopiesUpDown.Min := 1;
      CopiesUpDown.Max := 9999;
      {$ENDIF}
    end;
  finally
    // プリンタの設定を捨てる
    SetPrinterSettings(Settings, False);
  end;
end;

この修正は DHGL 1.1 に入っています。

6. [DHGL] DHGL.cnt の誤り

DHGL1.1 のヘルプを Delphi に組み込み、Delphiのヘルプを開くと、下図のように目次に余分な項目が表示されてしまいます。これは DHGL 1.1 の DHGL.cnt のリリースミスです。

特に害はありませんが、見苦しいとお思いの方は、申し訳ありませんが、以下の手順で削除してください。

1) 適当なエディタで DHGL.cnt を開き、下記の赤字の部分を削除してください。

:Base DHGL.hlp>Main
:Title Delphi High-Level Graphic Library(DHGL 1.1)
:Index DHGL=DHGL.hlp
1 Delphi High-Level Graphic Library(DHGL 1.1)
2 はじめに = APH_00002
2 DHGL のインストール方法 = APH_00136
2 このヘルプのインストール方法 = APH_00135
2 更新履歴 = APH_00131
2 BigBitmap ユニット
3 TBigBitmap クラス = TBigBitmap
2 BitmapEx ユニット
3 TBitmapEx クラス = APH_00058
2 BitmapUtils ユニット
3 AffineTransformBitmap 関数 = APH_00062
3 BitmapFilter 関数 = APH_00068
3 Enlarge 関数 = APH_00065
3 HorzMirrorBitmap 関数 = APH_00063
3 RotateBitmap 関数 = APH_00061
3 Shrink 関数 = APH_00066
3 Stretch 関数 = APH_00067
3 StretchBitmap 関数 = APH_00060
3 TransformBitmap 関数 = APH_00059
3 TTriple レコード型 = APH_00091
3 TTripleArray 配列型 = APH_00092
3 VertMirrorBitmap 関数 = APH_00064
2 DIBUtils ユニット
3 Convert4BitRLETo4BitRGB 手続き = APH_00086
3 Convert8BitRLETo8BitRGB 手続き = APH_00088
3 CreatePaletteFromDIB 関数 = APH_00090
3 DIB32_16ToDIB24 手続き = APH_00089
3 LoadDIBFromStream 手続き = APH_00069
3 SaveDIBToStream 手続き = APH_00085
3 TSepDIB レコード = APH_00087
2 ErrDef ユニット
3 ErrorDefusion 関数 = APH_00070
3 TQuantizeColor 抽象クラス = APH_00093
2 Gradation ユニット
3 TGradation クラス = APH_00071
2 GradationControl ユニット
3 GradationControl コントロール = APH_00072
2 IconEx ユニット
3 TIconEx クラス = APH_00073
2 MedianCut ユニット
3 ReduceColorsByMedianCut 関数 = APH_00094
3 ReduceColorsByMedianCutV 関数 = APH_00095
3 ReduceColorsByMedianCutED 関数 = APH_00096
3 ReduceColorsByMedianCutVED 関数 = APH_00097
3 TMedianCut クラス = APH_00074
2 MetafileEx ユニット
3 TMetafileEx クラス = APH_00075
2 MetafileUtils ユニット
3 AdjustFont 手続き = APH_00076
3 AdjustPhysicalInch 手続き = APH_00098
3 DHGLExtTextOut 関数(DHGL 1.1 で追加) = APH_00138
3 DHGLExtTextOutW 関数(DHGL 1.1 で追加) = APH_00139
3 FixMetafileFor9X 関数(DHGL 1.1 で追加) = APH_00137
2 NkMM ユニット、NkShareMem ユニット
3 説明 = APH_00134
2 Octree ユニット
3 ReduceColorsByOctree 関数 = APH_00099
3 TOctree クラス = APH_00077
2 PathUtils ユニット
3 DrawArc 手続 = APH_00101
3 DrawAngleArc 手続き = APH_00102
3 DrawAngleChord 手続き = APH_00106
3 DrawAnglePie 手続き = APH_00104
3 DrawChord 手続き = APH_00105
3 DrawEllipse 手続き = APH_00108
3 DrawFigure 手続き = APH_00109
3 DrawPath 手続き = APH_00110
3 DrawPie 手続き = APH_00103
3 DrawRectangle 手続き = APH_00107
3 DrawRoundRect 手続き = APH_00130
3 TPointInfo レコード = APH_00100
3 TPath クラス = APH_00078
2 PrinterUtils ユニット
3 GetPaperInfo 関数 = APH_00079
3 GetPaperNames 手続き = APH_00113
3 GetPaperNumbers 手続き = APH_00112
3 GetPaperSizes 手続き = APH_00114
3 GetPrinterSettings 関数 = APH_00115
3 SetPrinterSettings 手続き = APH_00117
3 TPaperInfo レコード = APH_00111
3 TPrinterSettings レコード = APH_00116
2 PrintPreview ユニット
3 PrintPreview コンポーネント = PrintPreview
2 RegionUtils ユニット
3 TRgnFillMode 列挙型 = APH_00127
3 TRegion クラス = APH_00081
3 TRgnOperartion 列挙型 = APH_00126
2 ROPUtils ユニット
3 ModifyDIBForROP 手続き = APH_00082
2 StaticErrDef ユニット
3 StaticErrorDefusion 関数 = APH_00083
2 TextUtils ユニット
3 GetTextAAdjust 関数 = APH_00084
3 GetTextCAdjust 関数 = APH_00128
3 GetTextPosition 関数 = APH_00129
1 プロパティ
2 TBigBitmap.Canvas プロパティ = TBigBitmap.Canvas
2 TBigBitmap.DrawMode プロパティ = TBigBitmap.DrawMode
2 TBigBitmap.Empty プロパティ = TBigBitmap.Empty
2 TBigBitmap.Height プロパティ = TBigBitmap.Height
2 TBigBitmap.Modified プロパティ = TBigBitmap.Modified
2 TBigBitmap.Palette プロパティ = TBigBitmap.Palette
2 TBigBitmap.PaletteModified プロパティ = TBigBitmap.PaletteModified
2 TBigBitmap.PixelFormat プロパティ = TBigBitmap.PixelFormat
2 TBigBitmap.Preview プロパティ = TBigBitmap.Preview
2 TBigBitmap.Scanline プロパティ = TBigBitmap.Scanline
2 TBigBitmap.Transparent プロパティ = TBigBitmap.Transparent
2 TPrintPreview.Canvas プロパティ = TPrintPreview.Canvas
2 TPrintPreview.PageCount プロパティ = TPrintPreview.PageCount
2 TPrintPreview.Pages プロパティ = TPrintPreview.Pages
1 メソッド
2 TBigBitmap.Assign メソッド = TBigBitmap.Assign
2 TBigBitmap.Create メソッド = TBigBitmap.Create
2 TBigBitmap.Destroy メソッド = TBigBitmap.Destroy
2 TBigBitmap.LoadFromClipboardFormat メソッド = TBigBitmap.LoadFromClipboardFormat
2 TBigBitmap.LoadFromFile メソッド = TBigBitmap.LoadFromFile
2 TBigBitmap.SaveToClipboardFormat メソッド = TBigBitmap.SaveToClipboardFormat
2 TBigBitmap.LoadFromStream メソッド = TBigBitmap.LoadFromStream
2 TBigBitmap.SaveToFile メソッド = TBigBitmap.SaveToFile
2 TBigBitmap.SaveToStream メソッド = TBigBitmap.SaveToStream
2 TPrintPreview.BeginDoc メソッド = TPrintPreview.BeginDoc
2 TPrintPreview.EndDoc メソッド = TPrintPreview.EndDoc
2 TPrintPreview.NewPage メソッド = TPrintPreview.NewPage
1 イベント
2 TBigBitmap.OnChange イベント = TBigBitmap.OnChange
2 TBigBitmap.OnProgress イベント = TBigBitmap.OnProgress
1 2次ウィンドウ
2 TBigBitmap プロパティ = APH_00025
2 TBigBitmap メソッド = APH_00032
2 TBigBitmap イベント = APH_00057
2 PrintPreview コンポーネントのプロパティ = APH_00118
2 PrintPreview コンポーネントのメソッド = APH_00123

2) Administrator でログオンして、<Delphi をインストールしたフォルダ>\bin にある OH.EXE を起動してください。runas コマンドや、エクスプローラで[別のユーザとして実行]を使って Administrator として OH.EXE を立ち上げても結構です。(Windows 9X/ME をお使いの方は単に OH.EXE を立ち上げるだけでけっこうです)。

3) OH.EXE で <Delphiをインストールしたフォルダ>\Help にある delphi6.ohp(Delphi 6 の場合), 又は delphi5.ohp(Delphi 5 の場合)を開いてください。

 

4) タブページ[目次]を選び、DHGL.cnt を削除して、再追加してください。そして[ファイル(F)}→[プロジェクトを上書き保存(A)]を選ぶと Delphi のヘルプの目次が更新されます。

このミスは DHGL 1.2 で修正されています。

7 [DHGL] メディアンカットによる減色が失敗する

MedianCut ユニットのメディアンカットによる減色ルーチン

function ReduceColorsByMedianCut(Bitmap: TBitmap; Depth: Integer)
: TBitmap; overload;

function ReduceColorsByMedianCutV(Bitmap: TBitmap; Depth: Integer)
: TBitmap; overload;

function ReduceColorsByMedianCutED(Bitmap: TBitmap;
Depth: Integer): TBitmap; overload;

function ReduceColorsByMedianCutVED(Bitmap: TBitmap;
Depth: Integer): TBitmap; overload;


function ReduceColorsByMedianCut(Bitmap: TBigBitmap; Depth: Integer)
: TBigBitmap; overload;

function ReduceColorsByMedianCutV(Bitmap: TBigBitmap; Depth: Integer)
: TBigBitmap; overload;

function ReduceColorsByMedianCutED(Bitmap: TBigBitmap;
Depth: Integer): TBigBitmap; overload;

function ReduceColorsByMedianCutVED(Bitmap: TBigBitmap;
Depth: Integer): TBigBitmap; overload;

は 減色するビットマップが8Mピクセル以上で、ビットマップの色が特定の明るい色に偏っている場合(例えばビットマップの背景が白1色の場合)、減色がうまく行かず、変な色のビットマップを生成してしまいます。

これはTMedianCut クラスの、色の重心を計算する処理で、整数演算のオーバーフローが起きているためです。

MedianCut.pas の 

procedure TMedianCut.CutCubes 内の色の積算処理を

    // 各色を積算する
    {$IFDEF ORIGINAL} 
    RAve := RAve + R * Cubes[i].NumPixels;
    GAve := GAve + G * Cubes[i].NumPixels;
    BAve := BAve + B * Cubes[i].NumPixels;
    {$ELSE}
    RAve := RAve + Int64(R) * Cubes[i].NumPixels;
    GAve := GAve + Int64(G) * Cubes[i].NumPixels;
    BAve := BAve + Int64(B) * Cubes[i].NumPixels;
    {$ENDIF}
  end;

procedure TMedianCut.CutCubesByVariance 内の色の積算処理を

    {$IFDEF ORIGINAL} 
    // 各色を積算する
    RAve := RAve + R * Cubes[i].NumPixels;
    GAve := GAve + G * Cubes[i].NumPixels;
    BAve := BAve + B * Cubes[i].NumPixels;
    {$ELSE}
    // 各色を積算する
    RAve := RAve + Int64(R) * Cubes[i].NumPixels;
    GAve := GAve + Int64(G) * Cubes[i].NumPixels;
    BAve := BAve + Int64(B) * Cubes[i].NumPixels;
    {$ENDIF}

に変更してください。これで 585Mピクセルまでのビットマップを問題なく減色できるようになります。

尚、この修正は DHGL 1.2 に反映されています。 

8 C++Builder で NkMM, NkShareMemユニットを使う

Delphi Graphic Secrets では DHGL を使う際、Delphiのメモリマネージャのバグに対処するため独自のメモリマネージャ NkMM, NkMemMgr を使うことになっています。同様の問題が C++Builder にもありますが、Delphi Graphic Secrets では触れていませんでした。また C++Builder で NkMM, NkMemMgrを使うには、若干ソース修正が必要なことがわかりました。以下に C++Builder で NkMM, NkMemMgr を使う方法を記述します。

1. ソース修正

まず、NkMM.pas と NkShareMem.pas の先頭の部分を以下のように修正してください。

 

unit NkMM;

interface

function SysGetMem(Size: Integer): Pointer;
function SysFreeMem(P: Pointer): Integer;
function SysReallocMem(P: Pointer; Size: Integer): Pointer;

type
TNkMMStatus = record
  AllocatedFromMM: LongWord;
  OSMemoryUsedByMM: LongWord;
end;

procedure GetMMStatus(var mms: TNkMMStatus);

procedure InitMM;  // この行を追加

implementation

 

unit NkShareMem;

interface

function SysGetMem(Size: Integer): Pointer;
function SysFreeMem(P: Pointer): Integer;
function SysReallocMem(P: Pointer; Size: Integer): Pointer;

type
  TNkMMStatus = record
  AllocatedFromMM: LongWord;
  OSMemoryUsedByMM: LongWord;
end;

procedure InitMemoryManager;  // この行を追加

procedure GetMMStatus(var mms: TNkMMStatus);


implementation

2. NkMM を EXE 又は DLL で使う方法

NkMMユニットを EXE で使う場合は、プロジェクトに NkMM.pas を加え、プロジェクトソースに以下の記述を加えてください。

#include <NkMM.hpp>

void InitializeMemoryManager(void)
{
  #pragma startup InitializeMemoryManager 0
  Nkmm::InitMM();
}

NkMMユニットをDLLで使う場合は、プロジェクトに NkMM を加え、DLLのメインのソースファイル(DLLEnttryPointが記述されているファイル)に上の記述を追加してください。

EXEの場合も DLL の場合もプロジェクトのリンカオプションで、「共有 RTL DLL を使う」のチェックを外してからコンパイルしてください。これはメモリマネージャとして BorlandMM.dll が使われるのを防ぐためです。

3. NkShareMem を EXE 又は DLL で使う方法

共有メモリマネージャ NkMemMgr.dll を使い、EXE と DLL がメモリマネージャを共有する場合は NkShareMem.pas を使います。Delphi Graphic Secrets には NkMemMgr.dll は付属していますが、インポートライブラリが付属していません。まずコマンドラインから

    implib NkMemMgr.lib NkMemMgr.dll

としてインポートライブラリを作ってください。

NkShareMem.pasを EXE でつかう場合は、プロジェクトに NkShareMem.pas と上で作ったインポートライブラリ(NkMemMgr.lib)を加え、プロジェクトソースに以下の記述を加えてください。

#include <NkShareMem.hpp>

void InitializeMemoryManager(void)
{
  #pragma startup InitializeMemoryManager 0
  Nksharemem::InitMemoryManager();
}

NkMMユニットをDLLで使う場合は、プロジェクトに NkShareMem と上で作ったインポートライブラリ(NkMemMgr.lib)を加え、DLLのメインのソースファイル(DLLEnttryPointが記述されているファイル)に上の記述を追加してください。

EXEの場合も DLL の場合もプロジェクトのリンカオプションで、「共有 RTL DLL を使う」のチェックを外してからコンパイルしてください。

9. DHGL は Delphi 7 Studio で使えます

DHGL 1.0, 1.1, 1.2 を Delphi 7 Studio を試験したところ全く問題はありませんでした。

DHGLは Delphi 7 Studio で問題なくご利用いただけます。

尚、DHGL 1.2 のドキュメントに Delphi 7 Studio で使えることを加えた DHGL 1.2 を新たに公開しました。ドキュメント以外中身は全く同じなので バージョンは DHGL 1.2 のままです。

10. PathUtilsユニットのDrawPath の不具合

DHGL 1.0, 1.1, 1.2 の PathUtils ユニットのDrawPath手続きはパスの座標数が2以下の場合、無限ループに陥ります。下記のように DrawPath手続きを修正してください。赤色の文字が修正個所です。修正内容は DHGL 1.0, 1.1, 1.2 とも同じです。

本問題は DHGL 1.3 で修正済みです。

procedure DrawPath(Path: TPath; ACanvas: TCanvas;
                   Color: TColor; Width: Integer;
                   PenStyle: array of Double;
                   Cap: TCapStyle = csFlat);
var
  FirstIndex: Integer;  // 図形の先頭座標のインデックス
  LastIndex: Integer;   // 図形の最終座標の次の座標のインデックス
  Points: array of TPoint;
  i: Integer;
begin
  LastIndex := 0;

{$IFDEF ORIGINAL} // 2003.5.3 修正 DHGL 1.3
  while LastIndex < Path.Count do  // パスが終わるまで
{$ELSE}
  while LastIndex < Path.Count -1 do  // パスが終わるまで
{$ENDIF}
  begin
    // 図形情報を取り出す
    FirstIndex := LastIndex;
{$IFDEF ORIGINAL}
    if FirstIndex + 1 < Path.Count-1 then
    begin
{$ENDIF}
      LastIndex := FirstIndex+1;
      // 図形の末尾(パスの終わり or MoveToまで)
      while (LastIndex < Path.Count) and
            (Path.Points[LastIndex].Figure <> ptMoveTo) do
        Inc(LastIndex);

      // 図形の座標(折れ線)を取り出す
      if LastIndex - FirstIndex >= 2 then
        // 閉じた図形なら折れ線に元に戻る線も加える
        if Path.Points[LastIndex-1].CloseFigure then
        begin
          SetLength(Points, LastIndex - FirstIndex +1);
          for i := FirstIndex to LastIndex-1 do
            Points[i-FirstIndex] := Path.Points[i].Point;
          Points[LastIndex-FirstIndex] := Path.Points[FirstIndex].Point;
        end
        else
        // 開いた図形なら座標をコピーするだけ
        begin
          SetLength(Points, LastIndex - FirstIndex);
          for i := FirstIndex to LastIndex-1 do
            Points[i - FirstIndex] := Path.Points[i].Point;
        end;
      // 折れ線を指定されたスタイルで描く
      DrawFigure(Points, ACanvas, Color, Width, PenStyle, Cap);
{$IFDEF ORIGINAL} // 2003.5.3 修正 DHGL 1.3
    end;
{$ENDIF}
  end;
end;

inserted by FC2 system