Entwickler-Ecke

Algorithmen, Optimierung und Assembler - Bildabmessungen berechnen


Dude566 - Mi 28.09.11 15:18
Titel: Bildabmessungen berechnen
Hallo Community,

ich bin gerade dabei mir eine kleine Applikation zu schreiben, die mir Bilder verkleinert.
Dabei kann der Benutzer den Maximalwert der Breite und der Höhe angeben, herauskommen sollen dann nur noch Bilder die diese Maße nicht überschreiten, natürlich sollte dabei das Seitenverhältnis der Bilder nicht zerstört werden.

Ich habe das ganze auf die schnelle so gelöst (siehe Code), jenachdem wie ich die Maximalwerte wähle wird das Bild jedoch verzerrt da eine Seite direkt den Maximalwert annimmt und die andere weiter verzerrt wird.

Wie kann ich den Algorithmus abändern das es ein gutes Ergebnis herauskommt?


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:
64:
65:
66:
67:
68:
procedure TfrmMain.btnResizeClick(Sender: TObject);
var
  NewWidth, NewHeight : integer;
  OldWidth, OldHeight : integer;
  TempWidth, TempHeight : integer;
  gap : integer;
  percentage : integer;
  Jpeg : TJpegImage;
  path : string;
begin
  try
    try
      NewWidth := seWidth.Value;
      NewHeight := seHeight.Value;
    except
      ShowMessage('Fehler beim Wählen der neuen Größe.');
    end;
    Jpeg := TJpegImage.Create;
    try
      Jpeg.LoadFromFile(FFile);
      OldWidth := Jpeg.Width;
      OldHeight := Jpeg.Height;
    except
      ShowMessage('Fehler beim Laden der Bilddatei.');
    end;
    // Algorithmmus zum Ändern der Auflösung
    while((OldWidth > NewWidth) or (OldHeight > NewHeight)) do
    begin
      // Breite muss geändert werden
      if(OldWidth >= NewWidth) then
      begin
        gap := OldWidth - NewWidth;
        // Prozentsatz der Differenz berechnen
        percentage := (gap * 100div OldWidth;
        OldWidth := NewWidth;
        // Neue Höhe nach dem Prozentsatz berechnen
        TempHeight := (OldHeight div 100) * percentage;
        OldHeight := OldHeight - TempHeight;
      end;
      // Höhe muss geändert werden
      if(OldHeight >= NewHeight) then
      begin
        gap := OldHeight - NewHeight;
        // Prozentsatz der Differenz berechnen
        percentage := (gap * 100div OldHeight;
        OldHeight := NewHeight;
        // Neue Breite nach dem Prozentsatz berechnen
        TempWidth := (OldWidth div 100) * percentage;
        OldWidth := OldWidth - TempWidth;
      end;
    end;
    try
      ResizeJpegImage(Jpeg, OldWidth, OldHeight);
    except
      ShowMessage('Fehler beim erstellen des neuen Bilds.');
    end;
    try
      path := ExtractFilePath(FFile) + FDestinationFileName;
      Jpeg.SaveToFile(path);
      ShellExecute(Handle, 'open', PChar(path),nil,nil,SW_SHOWNORMAL);
      ShowMessage('Bild erfolgreich erstellt.');
    except
      ShowMessage('Fehler beim Speichern des neues Bilds.');
    end;
  finally
    Jpeg.Free;
  end;
end;


Ich stehe gerade auf der Leitung und hoffe, dass ihr mir runterhelfen könnt. :D

Schöne Grüße,
Dude566

Edit: Habe den Fehler scheinbar gefunden, denn jetzt läuft es. Fehlende stellen ergänzt und markiert.
Ihr könnt aber trotzdem noch Tipps zur Optimierung oder anderen Verbesserungen geben. ;)


Christian S. - Mi 28.09.11 15:27

Hi!

Ich habe das mal so gelöst, ist zwar Prism, sollte aber einfach zu übernehmen sein:

Delphi-Prism-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:
method BiggestSide.GetDimensions(oldHeight, oldWidth : Integer; out newHeight, newWidth : Integer); 
begin
  var ratio := Double(oldHeight) / Double(oldWidth);
  
  newWidth := oldWidth;
  newHeight := oldHeight;
  
  //Bild kleiner als die Maximalwerte?
  if (oldHeight <= fMaxHeight) and (oldWidth <= fMaxWidth) then
  begin
    if not Fscale then exit//Sollen zu kleine Bilder nicht hochskaliert werden?
    
    if Math.Abs(oldWidth - fMaxWidth) > Math.Abs(oldHeight - fMaxHeight) then //Welche Seite wird beim Hochskalieren eher "anstoßen"
    begin
      newHeight := fMaxHeight;
      newWidth := (fMaxHeight / ratio).RoundToInt32;      
    end else
    begin
      newWidth := fMaxWidth;
      newHeight := (fMaxWidth * ratio).RoundToInt32;
    end;
  end;
  
  //Erst eine Seite runterrechnen (falls nötig), ...
  if newWidth > fMaxWidth > 0 then
  begin
    newWidth := fMaxWidth;
    newHeight := (fMaxWidth * ratio).RoundToInt32;
  end;

  //... dann die andere, falls das noch nötig ist.
  if newHeight > fMaxHeight > 0 then
  begin
    newHeight := fMaxHeight;
    newWidth := (fMaxHeight / ratio).RoundToInt32;
  end;
end;


Grüße,
Christian