Link to home
Start Free TrialLog in
Avatar of LeTay
LeTay

asked on

Reduce a JPEG image size with Delphi components

Hello
I use the following code to reduce the size (keeping the same proportion) of a picture stored in a JPEG file
Unfortunately, for many of them the result is ugly (seems "pixelazed")
Is there a better code for this ?
(PixelsPhoto is the number of pixels to obtain in the resulting file)
 
  BMP  := TBitmap.Create;
  JPEG := TJPEGImage.Create;
  Temp := TImage.Create(nil);                    
  Temp.Picture.LoadFromFile(Source);  // Load the JPEG file
  Zoom2 := ((Temp.Picture.Height * Temp.Picture.Width) / PixelsPhoto);
   if (Zoom2 < 1.0) then Zoom2 := 1.0;
   Zoom         := SQRT(Zoom2);                 // Calcul zoom d'après # de pixels totaux max
    try
     BMP.Height   := Round(Temp.Picture.Height / Zoom); // Zoom
     BMP.Width    := Round(Temp.Picture.Width / Zoom);
     BMP.Canvas.StretchDraw(Rect(0,0,BMP.Width,BMP.Height),Temp.Picture.Graphic);
     JPEG.CompressionQuality := 100;
     JPEG.Assign(BMP);
     JPEG.SaveToFile(Destination);
    finally
     BMP.Free;
     JPEG.Free;
     end;
   end;

Open in new window

Avatar of Manuel Lopez-Michelone
Manuel Lopez-Michelone
Flag of Mexico image

I do a reduce imagen procedure this way:

for i := 0 to Form1.Image1.Picture.width-1 do
  begin
    for j := 0 to Form1.Image1.Picture.height-1 do
    begin
          L := Form1.Image1.Canvas.Pixels[i,j];

          a := trunc(i * (SpinEdit1.Value / 100)); //50 is equal, for instace, a reduction of 50%
          b := trunc(j * (SpinEdit2.Value / 100));

          Form1.Image2.Canvas.Pixels[a,b] := L;
    end;
  end;
Avatar of LeTay
LeTay

ASKER

What is SpinEdit ?
Is the result satisfactory ?
Can you post the result on the attached file ?
The file is the original I also attached "my" (ugly) result
00052-1.jpg
52-1.jpg
SpinEdit is a component in the delphi palette with the purpose o enter a number between a range, for example, 0-100 (0-100%) in the case of using the component to enter the porcentage of reduction of the image. I took your original image. This is the result. Y reduce the original imagen in 50%
52-2.jpg
Avatar of LeTay

ASKER

I do not understand very well
I do not see how SpinEdit1 and SpinEdit2 are initialised
Also, when you write reduce in 50 %, do you mean the size in pixels X and Y (so in fact, surface reduced to 25 %) or the weight (in bytes) ?
SpinEdit is just a component to input a number within a range. But if you dont understand this just change spinedit for the value you want to reduce:

for i := 0 to Form1.Image1.Picture.width-1 do
  begin
    for j := 0 to Form1.Image1.Picture.height-1 do
    begin
          L := Form1.Image1.Canvas.Pixels[i,j];

          a := trunc(i * (50 / 100)); //50 is equal, for instance, a reduction of 50% in X coordinate
          b := trunc(j * 50 / 100)); //50 is equal, for instance, a reduction of 50% in Y coordinate

          Form1.Image2.Canvas.Pixels[a,b] := L;
    end;
  end;
lopem, pixel by pixel printing ? really ?

LeTay,
resizing only works well with bitmaps
first convert the jpeg to a bitmap
then resize/redraw on a secondary bitmap
then assign back to jpeg
then save

try this:
i used a spinedit to set the newwidth
you might need some extra magic to determine if you don't want to use the aspect ratio
or use the height as a determining factor

procedure TForm1.Button2Click(Sender: TObject);
var Source: TJPEGImage;
  Dest, Temp: TBitmap;
begin
  Source := TJpegImage.Create;
  try
    Dest := TBitmap.Create;
    try
      Temp := TBitmap.Create;
      try
        Source.LoadFromFile('D:\fotos\DSC01974.JPG');
        Source.DIBNeeded;
        Dest.Assign(Source);
        Temp.SetSize(seNewWidth.Value, Round(Source.Height * ( seNewWidth.Value / Source.Width)) );
        Temp.Canvas.StretchDraw(Rect(0, 0, seNewWidth.Value, Round(Source.Height * ( seNewWidth.Value / Source.Width)) ), Dest );

        Source.Assign(Temp);

        Source.SaveToFile('D:\fotos\DSC01974.TEST.JPG');
      finally
        Temp.Free;
      end;
    finally
      Dest.Free;
    end;
  finally
    Source.Free;
  end;
end;

Open in new window

Avatar of LeTay

ASKER

Will try all that
the clue is in the DIBNeeded
> or JPEGNeeded
Depends on which direction you are converting too

see methods of TJpegImage
Hi, Geert Gruwez,

I teach digital image processing at the university and of course, I am not concerning about the speed of the algorithm. Instead, I just gave a simple solution to a simple problem ;) But of course, you're right, my code is sooo sloooow

regards
Manuel
Avatar of LeTay

ASKER

Hello gentlemen, keep cool
I am not currently concerned by performance but ... by the visual QUALITY of  the resulting image !
An the StretcHDraw method (I used it) seems to be the guilty in that domain
I will try the iopem one, from which I already receidved my posted image reduced and looking fine
Avatar of LeTay

ASKER

I tried your code, Iopem, using as example 50 % for X and Y
But the result is a very very small picture, even if I use 90 % ?!
Where is the trick ?
I don't know. I just copied the code I show to my students. I load the original image you gave us and ran my program. I am showing my result. By the way, I first loaded a bmp version of your image and then I did the reduction. next, I saved it as a jpeg file.
Avatar of LeTay

ASKER

Sorry, think I did something wrong
Looking again ...
Avatar of LeTay

ASKER

I get now an error at execution on this :
           L := Form1.Image1.Canvas.Pixels[i,j];
Related to non existing bitmap or something like that
Can you show me the code where you load  the source file eetc...
Avatar of LeTay

ASKER

I have adapted the code of Iopem that failed
Using directly TBitmap component of the FMW.Objects library, not the VCL (no need to display it on a form)
The result is exactly the same as the second alternative, with the StrechDraw
I am not surprized : the "broken" line of the lamp is due to the rounding (of truncation) in the process
This is unavoidable using such method
However, my daughter reduced that image using PhotoShop and the result is much better
I suspect PhotoShop to "try" some kind of "vectorization" and so that line remains a line
Or maybe I missed something ?
Here is my code (reducing factor is 10 % both axis) :

procedure ReduireBitParBit(Source,Destination:string);
var
 Image1,Image2:TImage;
 I,J,L:integer;
 A,B:integer;
 H,W:integer;
 H2,W2:integer;
begin
 if (not FileExists(Source)) then Exit;
 Image1 := TImage.Create(nil);
 Image2 := TImage.Create(nil);
 Image1.Bitmap.LoadFromFile(Source);
 H  := Image1.Bitmap.Height - 1;
 W  := Image1.Bitmap.Width - 1;
 H2 := Round(H / 10);
 W2 := Round(W / 10);
 Image2.Bitmap.Create(W2,H2);
 for I := 0 to W do
  begin
  for J := 0 to H do
    begin
      L := Image1.Bitmap.Pixels[I,J];
      A := Round((I * 10) / 100);
      B := Round((J * 10) / 100);
      Image2.Bitmap.Pixels[A,B] := L;
    end;
  end;
 Image2.Bitmap.SaveToFile(Destination);
 Image2.Free;
 Image1.Free;
end;

Open in new window

In my program I have two images, one is the source one and the second is the processed image. So I read from one image and write in the second one.
Avatar of LeTay

ASKER

Gentlemen,
Delphi library for images is not the top.
Reducing images use a simple method, shown by both of you.
Keeping only bitmap points based on original
There is a much better solution, outside of Delphi standard
The Graphics32.org library provided transforms the bitmap in vectors, reduce the picture and put it back as compressed bitmap
The result has nothing to see with Delphi provided objects and methods.
I propose to give the points to Graphics32.org !
ASKER CERTIFIED SOLUTION
Avatar of Geert G
Geert G
Flag of Belgium image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of LeTay

ASKER

I do not teach anything in that domain !
Geert Gruwez,
of course I have better algorithms. In fact, in a first review of many filters, I am not worried about the fastest algorithm. I wanto the students to understand what are they doing, why the filter works, etc...

regards
Manuel
I think, Le Tay, you should gove the points to ther experts involved in your problem.
die you try playing around with smoothing and other properties ?

procedure TfrmPopup.Button1Click(Sender: TObject);
var Source: TJPEGImage;
  Dest, Temp: TBitmap;
  nw: integer;
  scale: double;
begin
  Source := TJpegImage.Create;
  try
    Dest := TBitmap.Create;
    try
      Temp := TBitmap.Create;
      try
        Source.LoadFromFile('d:\fotos\52-1.JPG');
        Source.DIBNeeded;
        Dest.Assign(Source);
        scale := 0.33;
        nw := Round(Source.Width * Scale);

        Temp.SetSize(nw, Round(Source.Height * ( nw / Source.Width)) );
        Temp.Canvas.StretchDraw(Rect(0, 0, nw, Round(Source.Height * ( nw / Source.Width)) ), Dest );

        Source.Assign(Temp);
        Source.Smoothing := True;
        Source.PixelFormat := jf24Bit;

        Source.SaveToFile('D:\fotos\52-test.jpg');
      finally
        Temp.Free;
      end;
    finally
      Dest.Free;
    end;
  finally
    Source.Free;
  end;
end;

Open in new window

i have you have the image as a vector graphic,
then you should and maintain the vector graphic as long as possible

only vector graphics allow for correct scaling
the rest is an algorithm with more or less loss of quality
Avatar of LeTay

ASKER

Points to nobody then
Geert Gruwez did a lot for you. I dont really care about the points but I think you're unfair. Every expert who try to help you deserves some recognition from you after all.
Avatar of LeTay

ASKER

Well, the problem I had was not to reduce an image, as my code does that since years.
The question was related to this statement I wrote : " Unfortunately, for many of them the result is ugly (seems "pixelazed")"
Geert will get the points anyway
LeTay,
that's just the point, there is no algorithm which doesn't have loss of image quality

you know, the movies where they do enhancements of number plates in police crime scenes ?
that's really a very good picture which gets reduced in quality and gets recorded into a film
and then they play that section backwards

there is no algorithm which can enhance course images
that would mean, you could reduce a 10x10 pixel image and enhance to a full blown picture

the smaller the size gets, the more quality and detail you loose
just a fact of life
i'd keep the pics to a size where you have good quality
and then stretchdraw them in an image frame on screen

in time, people get better displays with higher resolution,
and without doing anything, your on screen display will be better
Avatar of LeTay

ASKER

The library found at Graphics32.org is wonderful
The decompressed image in BitMap is first vectorized and then manipulated
Result is excellent
Avatar of LeTay

ASKER

Attached is the result I obtain now with the Graphics32 library, with the JPEG I posted
graphics32.jpg