Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Saving to /Loading From a TFileStream a TJpegImage object

1,055 views
Skip to first unread message

John Cadei

unread,
May 7, 2001, 5:29:50 AM5/7/01
to
Hello,

On my version of Delphi (D4 Standard) the TJpegImage class is almost totally
undocumented in the on-line help. However the following methods compile all
right:

procedure TJpegImage.LoadFromStream(FileStream: TFileStream);

procedure TJpegImage.SaveToStream(FileStream: TFileStream);

The SaveToStream method appears to work properly. Successive calls of the
method cause the JPegImages to be appended to the stream, as inspection of
the FileStream.Position after each call seems to confirm.

However the LoadFromStream method appears not to work properly. When the
file contains multiple TJPegImage objects, the method does not appear to
stop at the end of the JPeg object being read, but continues scanning to the
end of the file. In other words, after the first call to LoadFromStream,
FileStream.Position value equals FileStream.Size, rather than the position
in the stream at the end of writing the same JPeg object.

Can you shed any light on what is happening and how I can read multiple JPeg
objects from a single binary file?

Many thanks,

John

Peter Below (TeamB)

unread,
May 7, 2001, 3:47:07 PM5/7/01
to
In article <3af66af7_1@dnews>, John Cadei wrote:
> procedure TJpegImage.LoadFromStream(FileStream: TFileStream);
> procedure TJpegImage.SaveToStream(FileStream: TFileStream);
>
> The SaveToStream method appears to work properly. Successive calls of the
> method cause the JPegImages to be appended to the stream, as inspection of
> the FileStream.Position after each call seems to confirm.
>
> However the LoadFromStream method appears not to work properly.

It works but is has a prerequisite: the stream must contain only one JPG file.
This is the same limitation TBitmap.Loadfromstream has. The reason is that
these routines are designed to read and write single JPG or BMP images. To be
compatible to other programs that read/write these files the streaming code
cannot add any additional information (like the file size) to the stream. And
it is by no means easy to figure out the total size of a streamed image from
the images raw data, at least not in a foolproof way.

If you write a kind of storage system for images you don't have this same
limitation, so write the image file size to the stream before you write the
image. For reading images back you read the size, copy the indicated number of
bytes to a memory stream and load the image from that.


Peter Below (TeamB) 10011...@compuserve.com)
No e-mail responses, please, unless explicitly requested!
Note: I'm unable to visit the newsgroups every day at the moment,
so be patient if you don't get a reply immediately.

John Cadei

unread,
May 9, 2001, 1:27:17 PM5/9/01
to
Peter,

Thanks for your advice. You may be interested to know that what I was
attempting to do with Jpeg objects did in fact work with Bitmaps, i.e. I was
able to write and read multiple bitmaps from a single stream, simply using
TBitmap.SaveToStream, and TBitmap.LoadFromStream.

Returning to Jpegs, how does one reference the size and byte array of a
TJpegImage object?

Regards,

John

Peter Below (TeamB)

unread,
May 12, 2001, 11:52:25 AM5/12/01
to
In article <3af97d91$1_2@dnews>, John Cadei wrote:
> Returning to Jpegs, how does one reference the size and byte array of a
> TJpegImage object?
>

You have to look at the source of the JPEG unit and as it is just a
wrapper around a C obj file if memory servers that may not get you
anywhere. If you don't need access to the innards for another purpose
than saving the thing stream it to a TMemoryStream and look at its Size
property afterwards.

John Cadei

unread,
May 16, 2001, 7:17:15 AM5/16/01
to
"Peter Below (TeamB)" <10011...@compuXXserve.com> wrote in message
news:VA.00006ff...@antispam.compuserve.com...

> You have to look at the source of the JPEG unit and as it is just a
> wrapper around a C obj file if memory servers that may not get you
> anywhere. If you don't need access to the innards for another purpose
> than saving the thing stream it to a TMemoryStream and look at its Size
> property afterwards.
>

Peter,

Thanks for the above.

By trial and error I've discovered that it is possible to stream multiple
pictures, be they Jpegs or otherwise, to a single file by a simpler method
than the ones discussed thus far in this thread. The solution is to save the
picture graphic type identifiers as well as the graphic objects. To read a
graphic object from stream, first the type identifier is read, then an
graphic object of the appropriate type is created, and finally the
LoadFromStream method for that object is called. This approach works for
multiple as well as single graphics objects.

The following two procedures exemplifying the above can be called repeatedly
without problem:

procedure SavePictureToStream(var F: TFileStream; Picture: TPicture);
begin
SaveStringToStream(F, Picture.Graphic.ClassName);
Picture.Graphic.SaveToStream(F);
end;

procedure LoadPictureFromStream(var F: TFileStream; var Picture: TPicture);
var
GraphicType: string;
begin
{If necessary create a TPicture object:}
if Picture=nil then
Picture:= TPicture.Create;
{Read graphics file type:}
LoadStringFromStream(F, GraphicType);
{Create appropriate TGraphic descendent:}
if GraphicType= TBitmap.Classname then
Picture.Graphic:= TBitmap.Create
else if GraphicType= TIcon.Classname then
Picture.Graphic:= TIcon.Create
else if GraphicType= TMetafile.Classname then
Picture.Graphic:= TMetafile.Create
else if GraphicType= TJpegImage.Classname then
Picture.Graphic:= TJPegImage.Create
else
Exception.Create('Supported graphics object not found');
{Read graphic object:}
Picture.Graphic.LoadFromStream(F);
end;

I suspect that it may be possible to make the read procedure more succinct
by using class references and a for loop in place of the nested if
statements.

John

John Cadei

unread,
May 20, 2001, 10:55:36 AM5/20/01
to
Folks,

I refer to my previous message in which I reported a method which seems to
solve the problem of writing multiple Jpeg files to a single binary file. I
have since become increasingly puzzled about why it works, because I have
discovered the Jpeg.pas file, and it indicates that the
TJpegImage.LoadFromStream method is :

procedure TJPEGImage.LoadFromStream(Stream: TStream);
begin
ReadStream(Stream.Size - Stream.Position, Stream);
end;

This seems to indicate that all the data between the current position and
the end of the stream is read, which is not what appears to be actually
happening.

However in the same unit there is another method:

procedure TJPEGImage.ReadData(Stream: TStream);
var
Size: Longint;
begin
Stream.Read(Size, SizeOf(Size));
ReadStream(Size, Stream);
end;

which first reads the size of the data then the data, which is what appears
to be actually happening. However I cannot find where the method is called
in the chain of methods called from the TJpegImage.LoadFromStream method.

I note that in my code I call Picture.Graphic.LoadFromStream(F), where
Picture.Graphic has been created as a TJpegImage object. I therefore infer
that it is calling the TJpegImage.LoadFromStream method.

Can anyone explain what is actually going on?

Thanks in advance.

John

"John Cadei" <jm...@maunsl18.demon.co.uk> wrote in message
news:3b02626c_2@dnews...

0 new messages