What I have done is the following:

[pascal]procedure TForm1.Button1Click(Sender: TObject);
Var
F : TFileStream;
M,M2 : TMemoryStream;
J,J1 : TJPEGImage;
X,Y,Z : Integer;
begin
J := TJPEGImage.Create;
J.LoadFromFile('C:\cairnsgames\letter.jpg'); // Load an Image
X := 100;
M := TMemoryStream.Create;
M2 := TMemoryStream.Create;
M.Write(X,SizeOf(Integer)); // Write Tag Information
J.SaveToStream(M2);
X := M2.Size; // Calculate the size of the JPEG
M2.Free;
M.Write(X,SizeOf(Integer)); // Write Size
J.SaveToStream(M); // Write Image
J1 := TJPEGImage.Create; // Create a New Image
M.Seek(0,soBeginning); // Move to start of stream
M.Read(Y,SizeOf(Integer)); // Load Tag Information
M.Read(Z,SizeOf(Integer)); // Load Size Information
J1.LoadFromStream(M); // Load JPEG
J1.SaveToFile('C:\cairnsgames\letter1.jpg'); // Write Out (to compare vs Original)
ShowMessage(IntToStr(Z)); // Display Size info
J1.Free;
J.Free;
end;[/pascal]

And it works fine

I think I understand what it is doing. As JPEGs allow additional information such as who took the photo, commetns and even a thumbnail of the image the load from stream seems to read from the current position in the stream until the end, but only uses the JPEG information it needs to recreate the image in memory. Therefore when you add information at the end of the stream the LoadFromStream reads right past the JPEG size and over tha additional information.

Hope this helps.