Entwickler-Ecke

Multimedia / Grafik - JPEG verkleinern ohne Qualitätsverlust?


jackie05 - Fr 14.06.13 22:07
Titel: JPEG verkleinern ohne Qualitätsverlust?
Hallo,
ich habe ein Problem beim verkleinern von sehr große JPEG Dateien z.B. von (3872x2592) auf (272x272) Pixel, alles klappt zwar, nur ist es dann stark verpixelt, wenn ich es verkleiner.

Hier ist mal der Code:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
function ResizeJPEG(jpeg: TJpegImage; width, height: integer): TJpegImage;
var
  bmp:TBitmap;
begin
  try
    bmp:=TBitmap.Create;
    try
      bmp.width:=width;
      bmp.height:=height;

      bmp.canvas.StretchDraw(Rect(0,0,bmp.width,bmp.height),jpeg);
      jpeg.assign(bmp);
    finally
      bmp.free;
    end;
    jpeg.CompressionQuality := 100;
    jpeg.Compress;
    result := jpeg;
  finally

  end;
end;

procedure SavePNG(name: string; width: integer; height: integer);
var
  JPG:TJPEGImage;
  BMP:TBitmap;
  PNG:TPNGImage;
begin
  JPG:= TJPEGImage.Create;
  BMP:= TBitmap.Create;
  PNG:= TPngImage.Create;
  JPG.LoadFromFile('img/'+name);
  JPG := ResizeJPEG(JPG, width, height);
  //JPG.SaveToFile('img/'+name);
  BMP.Assign(JPG);
  PNG.Assign(BMP);
  PNG.SaveToFile(ChangeFileExt('img/'+name,'.png'));
end;


Wie kann ich TJpegImage so einstellen, das es noch weich gezeichnet wird?
Weil das Bild stark verpixelt ist, nachdem ich es verkleinert habe.

Ich bedanke mich schonmal im Voraus.

MfG


jaenicke - Fr 14.06.13 22:17

Dafür kannst du nach smooth resize suchen:
http://www.swissdelphicenter.ch/torry/showcode.php?id=1896


jackie05 - Fr 14.06.13 23:21

Ich danke Dir.

Das klappt irgendwie nicht.

Kann ich nicht irgendwie mein Code ausbessern um eine gute Qualität zu erzielen?

MfG


MeierZwoo - Sa 15.06.13 02:39

Grundsätzlich sollte es beim VERKLEINERN keine Artefakte geben - das passiert normal nur beim vergrößern.

Was ich nicht ganz verstehe, ist, weshalb Du erst auf eine BitMap zeichnest, dann aber der JPG die BitMap zuweist und dann die BitMap "wegwirfst" statt mit der BitMap weiter zu arbeiten. Dein Verpixeln entsteht wohl gerade an dieser Stelle, der Zuweisung einer BitMap an eine JPG. Dem Programm und auch dem Speicher und auch der Ausgabe ist es völlig egal, da beim Zeichnen eh eine BitMap gezeichnet wird, also die JPG wieder in RAW-Daten umgerechnet wird - denn eine JPG, GIF ... kann der Bildschirm (oder ein anderes pixelorientiertes Ausgabegerät) eh nicht darstellen.


jackie05 - Sa 15.06.13 20:07

Ich danke Dir.

Ich möchte ja eine JPEG Datei laden und diese verkleinern, anschließend möchte ich es dann als PNG speichern.

Wenn ich Bitmap entferne und nur mit JPEG und PNG arbeite:

Delphi-Quelltext
1:
2:
PNG.Assign(JPG);
PNG.SaveToFile(ChangeFileExt('img/'+name,'.png'));

dann bekomme ich folgende fehlermeldung:

Delphi-Quelltext
1:
TJPEGImage kann nicht zu TPNGImage zugewiesen werden.                    


Wie könnte ich das anders lösen?

MfG


MeierZwoo - Sa 15.06.13 20:19

Nochmal: Wieso entfernst Du denn die BitMap? Und wieso speicherst Du nicht die BitMap als PNG?

Es ist doch vollkommen egal, was für einen Grafiktyp Du lädst und als was Du speichern willst, das interne "Arbeits-Rohformat" (RAW) ist immer BitMap - von diesem Rohformat kann alles andere hergestellt werden. (Alternativ auch TIFF, weil TIFF nur ein encodetes Rohformat ist, welches durch decoden direkt wieder ins ursprüngliche Rohformat zurückgeführt werden kann und deshalb z.B. für Datenübertragung (z.B. zum Drucker) intern benutzt wird.)

Nachtrag:
Was ich auch nicht ganz verstehe, wieso man JPG läd um sie als PNG zu speichern.
a) Wenn man skalierbare Grafiken haben möchte. speichert man GLEICH als PNG (oder TIFF) und nicht als JPG - JPG ist als ENDformat gedacht und nicht zum weiteren skalieren, im Gegensatz zu PNG, welches zum skalieren gedacht ist.
b) macht man das nicht mit einem eigenen Tool, sondern benutzt fertige Tools, z.B. Irfan, die auch Batchbetrieb anbieten.


jackie05 - Sa 15.06.13 20:30

Danke Dir.

Das habe ich auch versucht, aber trotzdem ist das Bild dann verpixelt, wie es im anhang zusehen ist.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
bmp.width:=width;
bmp.height:=height;

bmp.canvas.StretchDraw(Rect(0,0,bmp.width,bmp.height),jpeg);
png.Assign(bmp);
png.SaveToFile('test.png');


Woran könnte es liegen?

MfG


MeierZwoo - Sa 15.06.13 21:06

LOL, also im Anhang kann man garnichts erkennen, selbst mit Lupe nicht - und da der Ursprung nicht bekannt ist, kann man auch nichts über verpixelt oder so aussagen.

Im allgemeinen wird überall berichtet, daß StretchDraw wohl allgemein eine Sauqualität abliefert. Ich selbst kann dazu nichts sagen, da ich es vermeide und Images VORHER auf Ausgabegröße anpasse bzw. wenn, nur Strich-Images damit skaliere (keine Graustufen, keine Farbe ..).

Aber eine Suche nach stretchdraw in den einschlägigen Delphi-Foren (auch hier) liefert genug Ergebnisse im Bezug auf die miese Qualität von stretchdraw. In den meisten Fällen wird auf Routinen von
http://graphics32.org/wiki//Main/HomePage
verwiesen.


WasWeißDennIch - Sa 15.06.13 21:53

Wenn man statt TCanvas.StretchDraw StretchBlt verwendet und vorher ggf. noch mit SetStretchBltMode den Modus umschaltet, bekommt man auch oft schon recht brauchbare Ergebnisse. Beispielcode findet sich z.B. hier: http://www.delphipraxis.net/1095307-post20.html


Delete - Sa 15.06.13 22:14

Folgender Code funktioniert sehr gut:

http://www.delphidabbler.com/tips/99
Note: to test this code you need to drop a TButton and a TOpenPictureDialog on a form and add the JPEG unit to the uses statement.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, JPEG, StdCtrls, ExtDlgs;

type
  TForm1 = class(TForm)
    OpenPictureDialog1: TOpenPictureDialog;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  bmp: TBitmap;
  jpg: TJpegImage;
  scale: Double;
begin
  if OpenPictureDialog1.execute then
  begin
    jpg := TJpegImage.Create;
    try
      jpg.Loadfromfile(OpenPictureDialog1.filename);
      if jpg.Height > jpg.Width then
        scale := 500 / jpg.Height  //org 50
      else
        scale := 500 / jpg.Width;  //org 50
      bmp := TBitmap.Create;
      try
        {Create thumbnail bitmap, keep pictures aspect ratio}
        bmp.Width := Round(jpg.Width * scale);
        bmp.Height:= Round(jpg.Height * scale);
        bmp.Canvas.StretchDraw(bmp.Canvas.Cliprect, jpg);
        {Draw thumbnail as control}
        Self.Canvas.Draw(10010, bmp);
        {Convert back to JPEG and save to file}
        jpg.Assign(bmp);
        jpg.SaveToFile(
          ChangeFileext(OpenPictureDialog1.filename, '_thumb.JPG'));
      finally
        bmp.free;
      end;
    finally
      jpg.free;
    end;
  end;
end;

end.


bummi - Sa 15.06.13 22:26

Wenn GDI+ eine Option für Dich ist, hier gibt es diverse Filter für das Scalieren.


Delete - So 16.06.13 08:16

Hier gibt es 3 Antialiasing-Programme - allerdings in spanisch...

http://neftali.clubdelphi.com/?p=296

http://neftali.clubdelphi.com/ejemplos_files/antialiasing_ej1.zip
http://neftali.clubdelphi.com/ejemplos_files/antialiasing_ej2.zip
http://neftali.clubdelphi.com/ejemplos_files/antialiasing_ej3.zip