ImageEn for Delphi and C++ Builder ImageEn for Delphi and C++ Builder

 

ImageEn Forum
Profile    Join    Active Topics    Forum FAQ    Search this forumSearch
Forum membership is Free!  Click Join to sign-up
Username:
Password:
Save Password
Forgot your Password?

 All Forums
 ImageEn Library for Delphi, C++ and .Net
 ImageEn and IEvolution Support Forum
 JPEGs go large when I resize
 New Topic  Reply to Topic
Author Previous Topic Topic Next Topic  

Jonathon

United Kingdom
2 Posts

Posted - May 10 2013 :  00:59:31  Show Profile  Reply
Hi!

I have a problem whereby I need to load up existing JPEG files, put a border around them then save them again. The following code works fine for loading and saving, and the output stream is the same size as the input stream:

var
img:TImageEnView;
ms,imgStream:TMemoryStream;
begin
// setup of streams here
img.IO.LoadFromStreamJpeg(imgStream);
Log( format('Input Image size in bytes: %d' ,[imgstream.Size]));
// ** need to add a border here
img.IO.SaveToStreamJPEG(ms);
Log(Format('Saved to memory stream, size=%d',[ms.Size]));
// tear down and tidy up
end;

But if I add this line in after the second comment (i.e.: after the loadfromstream but before the save to stream)
img.Proc.ImageResize(img.IEBitmap.Width+10,img.IEBitmap.Height+10,iehCenter,ievCenter);

- Then the output JPEG size increases massively. I've played with the JPEG_Smooth and JPEG_Quality but in order to get back to around the original size I have to degrade the image quality massively (JPEG_Quality=20).

I actually do more than this, I add a border, then add a header and footer area and write metadata text to those regions; however the core issue boils down to the above. If I write text to the canvas without resizing it I don't seem to get the same issues.

I guess there is some kind of conversion or resampling going on.

Is there any way to resize the image canvas without getting this effect?

Thanks

Jonathon

w2m

USA
1990 Posts

Posted - May 10 2013 :  05:58:36  Show Profile  Reply
I do not see a large increase in stream size that you describe. Perhaps it is caused by not setting the memory stream positions?
Before loading a memory stream its position must be set to 0. Are you doing this?
procedure TForm1.Button1Click(Sender: TObject);
var
  img: TImageEnView;
  ms, imgStream: TMemoryStream;
begin
  if Assigned(cxPageControl1.ActivePage) then
  begin
    ImageEnView := TImageEnView(cxPageControl1.ActivePage.Controls[0]);
    if Assigned(ImageEnView) then
    begin
      img := TImageEnView.Create(nil);
      try
        ms := TMemoryStream.Create;
        try
          imgStream := TMemoryStream.Create;
          try
            ImageEnView.IO.SaveToStreamJPEG(imgStream);
            imgStream.Position := 0;  // Important
            img.IO.LoadFromStreamJpeg(imgStream);
            ShowMessage(Format('Input Image size in bytes: %d', [imgstream.Size]));
            img.Proc.ImageResize(ImageEnView.IEBitmap.Width + 10, ImageEnView.IEBitmap.Height +
              10, iehCenter,
              ievCenter);
            img.IO.SaveToStreamJPEG(ms);
            ms.Position := 0; // Important
            ShowMessage(Format('Saved to memory stream, size=%d', [ms.Size]));
            ImageEnView.IO.LoadFromStreamJpeg(ms);
            ImageEnView.Update;
            UpdateStatusBar;
          finally
            imgStream.Free;
          end;
        finally
          ms.Free;
        end;
      finally
        img.Free;
      end;
    end;
  end;
end;

William Miller
Email: w2m@frontiernet.net
EBook: http://www.imageen.com/ebook/
Apprehend: http://www.frontiernet.net/~w2m/index.html
Go to Top of Page

Jonathon

United Kingdom
2 Posts

Posted - May 11 2013 :  17:49:19  Show Profile  Reply
Hi William, thanks for your attention!

It wasn't that (I do lots of stuff with streams), but your assurance that you don't see a similar effect gave me the confidence to do more investigation.

I was able to reproduce the effect with a simple test block of code:

ImageEn1.IO.Params.JPEG_DCTMethod:=ioJPEG_ISLOW;
ImageEn1.IO.LoadFromFileJpeg('c:\test.jpg');
ImageEn1.Proc.ImageResize(imageen1.IEBitmap.width+10,imageEn1.IEBitmap.height+10,iehCenter,ievCenter);
ImageEn1.IO.Params.JPEG_Quality:=(IECalcJpegFileQuality('c:\test.tif'));
Imageen1.IO.SaveToFileJpeg('c:\test2.jpg');

- and it appears that this issue was to do with re-compression and MCU boundaries. I have discovered that I can minimise the effect (and prevent obvious re-compression) by keeping my borders etc a multiple of 1 MCU - which is pretty much always 16x16 for the library I have to modify.

So, when I run the above code to add a 16 pixel border to an existing file the filesize grows from 102KB to 104KB - which is fair enough. Pixel-peeping reveals that there has been no visible recompression (artefacts appear identical). If I add a 10 pixel border (as I was) the filesize grows from 102KB to 122KB and the resulting image has been obviously (visibly) re-compressed with a consequent (significant) loss in image quality and increase in visible artefacts. Some images I was testing with, which were 600KB in size, would grow to over 1 MB so it is obviously (as I would expect with JPEG's) content dependent.

Different size borders give differing results, always falling to minimums on multiples of 16 pixels.

So, by choosing multiples of 16 bytes I can minimise the impact on the image but still add a border and top/bottom annotations, which is great.

Oddly enough there must be some recompression going on because the JPEG_Quality has an impact if I play with it, but on the whole - as long as it is not visible - I don't care!

Thanks for the hint!

Regards

Jonathon



Go to Top of Page
  Previous Topic Topic Next Topic  
 New Topic  Reply to Topic
Jump To: