DWG プレビューイメージ DwgThumbnail (2017/08/20)

DWG ファイルに格納されているプレビューイメージ (BITMAP, PNG) を取り出します。


unit DwgThumbnailUnit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, FileCtrl, ExtCtrls, PNGImage;

type
  TDWGHeader = record
    ImKind: Byte;
    StAddr: DWord;
    ImSize: DWord;
  end;

// プロトタイプ
function DwgThumbnail(const dwgname: TFileName; bmp : TBitmap): boolean;

implementation

function DwgThumbnail(const dwgname: TFileName; bmp: TBitmap): boolean;
var
  DWGHeader : TDWGHeader;
  Offset    : Longint;
  Images    : Byte;
  BitmapFileHeader : TBitmapFileHeader;
  BitmapInfoHeader : TBitmapInfoHeader;
  DwgF    : TFileStream;
  Tempmem : TMemoryStream;
  buf     : array [0..3] of Ansichar;
  vernum  : integer;
  PngImage: TPngImage;
begin
  result := True;
  try
    // DWG ファイルストリーム
    DwgF:= TFileStream.Create(DwgName, fmOpenRead);
    try
      // DWG Version の取得
      // 'AC10xx' の'AC' を読み飛ばす
      DwgF.Seek($02, soFromBeginning);
      // 'AC10xx' の数字部分 '10xx' を取得
      DwgF.ReadBuffer(buf, 4);
      vernum := StrToIntDef(string(buf), 0);

      if (vernum > 1012) then begin
        // ファイル先頭から 13byte
        DwgF.Seek($0D, soFromBeginning);
        // オフセット
        DwgF.ReadBuffer(Offset, 4);
        DwgF.Seek($14 + Offset, soFromBeginning);
        // ブロックイメージの数
        DwgF.ReadBuffer(Images, 1);
        DwgF.Seek($1E + Offset, soFromBeginning);
        // 格納イメージの種類
        DwgF.ReadBuffer(DWGHeader.ImKind, 1);
        // データブロックの開始アドレス
        DwgF.ReadBuffer(DWGHeader.StAddr, 4);
        // データのサイズ(バイト数)
        DwgF.ReadBuffer(DWGHeader.ImSize, 4);
        //------------------------------------------------------BITMAP
        if (DWGHeader.ImKind = 2) then begin
          //ビットマップのヘッダーを取得
          DwgF.Seek(DWGHeader.StAddr, soFromBeginning);
          DwgF.ReadBuffer(BitmapInfoHeader, 40);
          with BitmapFileHeader do begin
            // "BM"
            bfType     := $4D42;
            // ファイルサイズ
            bfSize      := 14 + DWGHeader.ImSize;
            bfReserved1 := 0;
            bfReserved2 := 0;
            // イメージへのオフセット
            //bfOffBits  := bfSize - BitmapInfoHeader.biSizeimage;
            bfOffBits  := 14 + 40 + 4 * 256; // = 1078
          end;

          Tempmem := TMemoryStream.Create;
          try
            Tempmem.Write(BitmapFileHeader, 14);
            DwgF.Seek(DWGHeader.StAddr, soFromBeginning);
            Tempmem.CopyFrom(DwgF, DWGHeader.ImSize);
            Tempmem.Seek(0, 0);
            try
              bmp.LoadFromStream(Tempmem);
            except
              Abort;
            end;
          finally
            Tempmem.Free;
          end;
        end
        //------------------------------------------------------PNG
        else if DWGHeader.ImKind = 6 then begin
          // ストリームの先頭に
          DwgF.Seek(DWGHeader.StAddr, soFromBeginning);
          Tempmem := TMemoryStream.Create;
          try
            // コピー
            Tempmem.CopyFrom(DwgF, DWGHeader.ImSize);
            Tempmem.Seek(0, 0);
            try
              PngImage := TPngImage.Create;
              PngImage.LoadFromStream(Tempmem);
              bmp.Assign(PngImage);
              PngImage.Free;
            except
              Abort;
            end;
          finally
            Tempmem.Free;
          end;
        end;
      end;
    finally
      DwgF.Free;
    end;
  except
    result := false;
    Abort;
  end;
end;

end.