Extracting a Bitmap from a Memory Stream from Abbrevia

Hi All,

In the past have successfully extracted ascii data into a TStringlist using streams. I would like to do the same from a bitmap. I have never understood Streams but that has not stopped me using them.

The function below is my first attempt . it compiles but fails on execution with a error say Bitmap not valid. (I current do have a similar function working that saves the bitmap to the file system before loading it into the StringList.

Where am I going wrong?

function ExtractAllFilesToListByExtensionUsingStreams(aSourceZipFile: string; aExt: String; var List: TStringList): boolean;
var
  i: integer;
  z: TAbZipKit;
  MemStream: TMemoryStream;
  f: TAbArchiveItem;
  tmpstr, FoundFileName, myext: string;
  tmpList: TStringList;
  Bitmap: TBitMap;
begin
  // how do we load a Bitmap
  result := false;
  z := TAbZipKit.Create(nil);
  try
    z.OpenArchive(aSourceZipFile);
    try
      MemStream := TMemoryStream.Create;
      try
        f := z.Items[i];
        z.ExtractToStream(f.FileName, MemStream);
        MemStream.Position := 0;
        Bitmap := TBitMap.Create;
        Bitmap.LoadFromStream(MemStream);
        List.AddObject(f.FileName, Bitmap);
      finally
        MemStream.Free;
      end;

      if List.Count > 0 then
        result := True;
    finally
      z.CloseArchive;
    end;
  finally
    z.Free;
  end;
end;
1 Like

Hi Brian

Looks like i is not set. The function name suggests you’re missing a for i loop iterating over all items in the zip file

Richard

Woops, here is the corrected code - but I still get the bitmap is invalid error

function ExtractAllFilesToListByExtensionUsingStreams(aSourceZipFile: string; aExt: String; var List: TStringList): boolean;
var
i: integer;
z: TAbZipKit;
MemStream: TMemoryStream;
f: TAbArchiveItem;
tmpstr, FoundFileName, myext: string;
tmpList: TStringList;
Bitmap: TBitMap;
begin
// how do we load a Bitmap
result := false;
z := TAbZipKit.Create(nil);
try
z.OpenArchive(aSourceZipFile);
try
for i := 0 to z.Count - 1 do
begin
MemStream := TMemoryStream.Create;
try
f := z.Items[i];
z.ExtractToStream(f.FileName, MemStream);
MemStream.Position := 0;
Bitmap := TBitMap.Create;
Bitmap.LoadFromStream(MemStream);
List.AddObject(f.FileName, Bitmap);
finally
MemStream.Free;
end;
end;

if List.Count > 0 then
result := True;
finally
z.CloseArchive;
end;

finally
z.Free;
end;
end;

Are you sure it is a bitmap? (maybe it’s some other sort of image file)

Try saving to a file first and looking at it to see what it really is?

Brian,

You might have solved your problem, but if not…

It’s a long time since I did this, but I looked at some old code I wrote in the early 2000’s and in it I did

  1. img := TImage.Create(nil);
  2. img.picture.LoadFromFile(fn);
  3. img.AutoSize := true;

(I know you don’t have or want a file, but continuing…)
I then did some drawing on the img and finally

  1. bmp := TBitmap.Create;
  2. bmp.Assign(img.Picture.Graphic);

so I could place the bitmap in a TRichview. I don’t know why I had to create the TImage, but maybe that allocates/manages memory…

As Mark suggests I’d suggest you first manually unzip the zip file and check you can open the bitmaps in say MS Paint.
Then I’d split your code: Unzip and save the bitmaps to files and check you can open those bitmap files again using MSPaint
Then you can get back to your memory stream.

Hope this helps, Richard

Hi again Brian

Following on from this morning… here’s what works for me - create a new project and add a single button to the form (I was given TForm7 / unit7 so alter the code accordingly) and paste in the following :

unit Unit7;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
System.Zip, Vcl.StdCtrls, Vcl.ExtCtrls;

type
TForm7 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
function ExtractFiles(aSourceZipFile: string): boolean;
public
end;

var
Form7: TForm7;

implementation

{$R *.dfm}

function TForm7.ExtractFiles(aSourceZipFile: string): boolean;
var
z: TZipFile;
MemStream: TMemoryStream;
stream: TStream;
hdr: TZipHeader;
img : TImage;
i: Integer;
begin
z := TZipFile.Create;
z.Open(aSourceZipFile, zmRead);
for i := 0 to z.FileCount - 1 do
begin
z.Read(i, stream, hdr); // the header will tell us what each zipped file is --- I assume each zipped file is a bitmap..
MemStream := TMemoryStream.Create;
MemStream.CopyFrom(stream, 0);

img := TImage.Create(nil);
img.Picture.Graphic := TBitmap.Create;
MemStream.Position := 0;
img.Picture.Graphic.LoadFromStream(MemStream);

// do what you want with the bitmap (in .Graphic) here
// I'm choosing to save it to a file
img.Picture.Graphic.SaveToFile('.\' + z.FileNames[i]);

MemStream.Free;
img.Free;
end;
z.Free;
Result := true;
end;

procedure TForm7.Button1Click(Sender: TObject);
begin
ExtractFiles('.\test_bmp.zip');
end;

end.

Zip together a few .bmp’s into a file named test_bmp.zip and place it alongside the compiled exe. This example saves each bitmap to file after it is loaded from the memory stream. Note this uses the “built-in” TZipFile since I don’t have Abbrevia. The above code uses the TZipFile streaming Read method.

Somebody might be able to improve this and avoid the need to use a TImage as a “container”. And add some error handling!

Cheers Richard

1 Like