#1 2010-10-15 09:53:45

esmondb
Member
From: London
Registered: 2010-07-20
Posts: 299

image dimensions

Would it be worth building in some routines to get the dimensions from image files? It seems slight overkill to use GDI+. I've put an example of what I mean below which seems more efficient. The JPEG dimensions routine is based on something posted on www.delphi3000.com

constructor TPdfImage.CreateJpegDirect(aDoc: TPdfDocument; JpegFileName: TFileName;
     var W, H: integer);  //overridden in decl
var
  ms : TMemoryStream;
  b : byte;
begin
  inherited Create(aDoc,true);
  FAttributes.AddItem('Type','XObject');
  FAttributes.AddItem('Subtype','Image');
  FFilter.RemoveName('FlateDecode');
  FFilter.AddItem(TPdfName.Create('DCTDecode'));
  FWriter.Save; // flush to allow direct access to fDestStream
  W:=0; H:=0;
  ms := TMemoryStream.Create;
  try
    ms.LoadFromFile(JpegFileName);
    GetJpegSize(ms,W,H,b);
    FWriter.Add(ms.Memory, ms.Size);
  finally
    ms.Free;
  end;
  FWriter.fDestStreamPosition := FWriter.fDestStream.Seek(0,soFromCurrent);
  FAttributes.AddItem('Width',W);
  FAttributes.AddItem('Height',H);
  if b = 24 then
    FAttributes.AddItem('ColorSpace','DeviceRGB')
  else if b = 8 then
    FAttributes.AddItem('ColorSpace','DeviceGray');
  FAttributes.AddItem('BitsPerComponent',8);
end;

function GetJpegSize(ms: TMemoryStream; var width, height: integer; var BitDepth: byte): boolean;
var
  n : int64;
  i : integer;
  b, bb : byte;
begin
  n := ms.Size - 8;
  result := false;
  ms.Position := 0;
  if n > 0 then begin
    ms.ReadBuffer(b,1);
    if (b = $FF) then begin
      ms.ReadBuffer(b,1);
      if b = $D8 then
        ms.Read(b,1)
      else exit;
    end else exit;
  end else exit;
  while (ms.Position < n) and (b = $FF) do begin
    ms.ReadBuffer(b,1);
    case b of
      $C0 .. $C3:
        begin
          ms.Seek(3,soCurrent);
          ms.Read(b,1);
          ms.Read(bb,1);
          height := b * 256 + bb;
          ms.Read(b,1);
          ms.Read(bb,1);
          width := b * 256 + bb;
          ms.Read(b,1);
          BitDepth := b * 8;
          Result := True;
          exit;
        end;
      $FF:
        ms.Read(b,1);
      $D0 .. $D9, $01:
        begin
          ms.Seek(1,soCurrent);
          ms.Read(b,1);
        end;
      else begin
        ms.Read(b,1);
        ms.Read(bb,1);
        i :=  b * 256 + bb -2 ;
        ms.Seek(i, soCurrent);
        ms.Read(b,1);
      end;
    end;
  end;
end;

Offline

#2 2010-10-15 10:00:15

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,659
Website

Re: image dimensions

I don't think the overhead of using GDI+ is very big.

It could be a good idea to have pure Delphi code for that.
The trick of GetJpegSize() is a bit verbose (some pointers would be better than TStream.Read methods).

Perhaps a dual decicated constructors, one using a TMemoryStream, another using a file.

Offline

#3 2010-10-15 14:08:26

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,659
Website

Re: image dimensions

I've uploaded two dedicated constructors to the main source code repository http://synopse.info/fossil

Offline

Board footer

Powered by FluxBB