M Schenkel
M Schenkel

Reputation: 6364

Problem converting bmp to jpg using TJpegImage Component

I have a bmp file and am trying to convert it to jpeg format. The jpeg created using the following code loses a lot of clarity. I have tried tweaking many settings to no avail.

Does anyone have a function which will convert a bmp file to a jpeg?

var
  Bmp: TBitmap;
  Jpg: TJPEGImage;
begin
  Bmp := TBitmap.Create;
  Jpg := TJPEGImage.Create;
  try
    Bmp.LoadFromFile(BmpFileName);
    Jpg.Assign(Bmp);
    jpg.PixelFormat    :=jf24bit;  // or jf8bit
    Jpg.CompressionQuality := 100;
    Jpg.ProgressiveDisplay := False;
    Jpg.ProgressiveEncoding := False;

    Jpg.SaveToFile(JpgFileName);
  finally
    Jpg.Free;
    Bmp.Free;
  end;
end;

Update II A lot of people have responded that jpeg is not the graphic type to use in this case. Understood. Not to beat a dead horse, but I have been able to use other programs (i.e. Photoshop) and convert this to a nice looking jpeg. And the tool I am using to create the chart (fusioncharts) is able to export it to a nice looking jpeg too (see below). What is the difference?

Upvotes: 5

Views: 8470

Answers (6)

Sergey  Chechulin
Sergey Chechulin

Reputation: 11

You just need to call Compress method after assignment bmp to jpeg. This is necessary for the CompressionQuality parameter to take effect. When Delphi performs Jpg.Assign(Bmp) it only assigns TJPEGImage.FBitmap field.

var
  Bmp: TBitmap;
  Jpg: TJPEGImage;
begin
  Bmp := TBitmap.Create;
  Jpg := TJPEGImage.Create;
  try
    Bmp.LoadFromFile(BmpFileName);
    Jpg.Assign(Bmp);
    
    Jpg.CompressionQuality := 100;
    Jpg.Compress; //!!!

    Jpg.SaveToFile(JpgFileName);
  finally
    Jpg.Free;
    Bmp.Free;
  end;
end;

Upvotes: 1

Kryvich
Kryvich

Reputation: 421

I had the same problem as you. It's my solution.

1) Use TsdJpegGraphic class from the NativeJPG library instead of Delphi's TJPEGImage. It's free and open source.

2) The code:

var
  Bmp: TBitmap;
  Jpg: TsdJpegGraphic;
begin
  Bmp := TBitmap.Create;
  Jpg := TsdJpegGraphic.Create;
  try
    Bmp.LoadFromFile(BmpFileName);
    Jpg.CompressionQuality := 100; // !!!
    Jpg.Assign(Bmp);
    Jpg.SaveToFile(JpgFileName);
  finally
    Jpg.Free;
    Bmp.Free;
  end;
end;

It's important to set the CompressionQuality property before you assign the bitmap to Jpg! If you put this command after the assigning then the library will use the default value (=80%) for CompressionQuality.

Upvotes: 2

Dejan Stanič
Dejan Stanič

Reputation: 797

I don't think just setting jpg.CompressionQuality alone is enough. You should also call jpg.Compress() afterwards to actually compress image...

Something like:

jpg := TJPEGImage.Create(); jpg.LoadFromFile('foo.jpg'); jpg.DIBNeeded(); jpg.CompressionQuality := 25; jpg.Compress(); jpg.SaveToFile('bar.jpg'); jpg.Free();

HTH, Dejan

Upvotes: 0

Roddy
Roddy

Reputation: 68114

As others have said, JPEG is simply the wrong format for that kind of image - and with the high-frequency chroma edges, you have possibly one of the worst-case images for JPEG!

I recommend you get a copy of Paint.Net, and try saving/previewing images in different formats (PNG, JPEG, GIF, BMP, etc) and get a feel for the trade-offs between image size, quality and performance yourself.

I've tried saving your test image with Paint.net as JPEG, and get exactly the same quality as Delphi gives you, so there's nowt wrong with what you (or Delphi) are doing...

UPDATE: According to Wikipedia...

There is an optional lossless mode defined in the JPEG standard; however, that mode is not widely supported in products.

I'd guess that FusionCharts and Photoshop have a way of specifying this mode. It's not normally used, because JPEG is usually considered synonymous with LOSSY compression.

In summary, while JPEG files can support lossless compression, JPEG is not an ideal format to because it's not widely supported. If you want lossless, PNG remains a better choice. The PNG-compressed version of your image is 30% smaller than the losslessly compressed JPEG one (71K vs 101K)

Upvotes: 1

Andreas Rejbrand
Andreas Rejbrand

Reputation: 109158

If you want to loose as little quality as possible, then you should compress as little as possible, i.e. set CompressionQuality := 100.

Update

The JPG image format is designed to be used with photographs and similar raster pictures. JPG employs destructive compression to reduce the file size. However, the visual effect of this compression is negligible for large quality values (> ~80) because photographs do not contain large areas of the same colour, very regular shapes, etc.

The JPG format should never be used for anything other than photographic pictures. For instance, diagrams, screenshots, etc, that do contain large areas of the exact same colour, very regular shapes, etc, will display clear artefacts when JPG compressed. For this type of raster images, use PNG. PNG is also a compressed format (a very, very good format too!), but the compression is non-destructive.

So please do not use JPG for your diagram! Use PNG!

Upvotes: 4

Chris Thornton
Chris Thornton

Reputation: 15817

As Andreas said, jack up the CompressionQuality to 100. If you'd like to try another example, Dr. Bob (frequent SO contributor) has a nice writeup here:
https://web.archive.org/web/1/http://articles.techrepublic%2ecom%2ecom/5100-10878_11-5031886.html#

He has code that uses a stream approach. I would expect the same result, but you never know. Here's the code:
https://web.archive.org/web/1/http://techrepublic%2ecom%2ecom/html/tr/sidebars/5031886-1.html

Upvotes: 1

Related Questions