![]() |
Resample oder Resize mit GDI+
Hallo,
ich möchte gern größere Bilder mithilfe der Funktionen aus der GDI+ -Bibliothek verkleinern. Leider habe ich keine Ahnung, wie ich das so recht anstellen soll. Auch möchte ich, um Resourcen zu schonen, auf fertige Units verzichten. Ich bin soweit, dass ich die GDI+ initialisiert, Bitmaps angelegt und deren Speicher wieder freigegeben habe. Ich finde aber nichts genaues, mit welchen Funktionen ich ein Resample erreichen kann. Aufgrund meiner Recherchen vermute ich, dass ich die Größenänderung mit mit
Delphi-Quellcode:
hinbekommen könnte. Mein Plan sieht so aus:
GdipDrawImageRect()
Ich denke auch, dass ich kein zweites TBitmap brauchte. Ich finde aber keine Funktion, mit der ich einfach so ohne Bezug zur (normalen) GDI ein GDI+ Bitmap erstellen kann. Auch insoweit wäre ich für Hilfe dankbar. Ich möchte das ganze später in einem von TBitmap abgeleiteten Object unterbringen und würde mir gern das Hilfsbitmap sparen. Gruß, Alex |
AW: Resample oder Resize mit GDI+
Hallo,
erstens würde ich Dir dringend dazu raten, fertige Klassen für GDI+ zu verwenden, z. B. die von Progdigy. Damit ersparst Du Dir jede Menge Ärger, und die Größe Deines Programms sollte doch heutzutage nicht mehr ausschlaggebend sein, oder? Zweitens, So musst Du vorgehen:
//Edit: Ach ja, ohne Zweitbitmap geht es nicht, und natürlich kannst Du auch einfach direkt ein GDI+ Bitmap erstellen. Gruß xaromz |
AW: Resample oder Resize mit GDI+
Ich schließe mich meinem Vorredner an:thumb:
|
AW: Resample oder Resize mit GDI+
Danke. Das bringt mich schon einmal auf Kurs!
Ich möchte keine fertige Klasse verwenden. Und ja, die Größe spielt bei uns eine Rolle, weil mein fertiges Programm aus bestimmten Gründen regelmäßig neu geladen und gestartet werden muss. Bei uns hängen mehrere Leute an einem VPN. Wenn ich die Datei größer mache, gibt es mit denen Ärger. Außerdem experimentiere ich gern :lol: Zitat:
Könntest Du mir bitte die Funktion verraten. Das würde mir sehr helfen. ![]() Dann würde ich mich noch freuen, wenn jemand bestätigen oder dementieren könnte, dass ich mit
Delphi-Quellcode:
die Größenänderung machen kann.
GdipDrawImageRect()
Zitat:
Danke, Alex |
AW: Resample oder Resize mit GDI+
Hallo,
ein Bitmap bekommst Du mit
Delphi-Quellcode:
Danach steckt in bitmap Dein GDI+ Bitmap.
var bitmap: Pointer;
... bitmap := nil; lastResult := GdipCreateBitmapFromScan0(width, height, 0, pixelFormat, nil, bitmap); Ein Bitmap malst Du mit
Delphi-Quellcode:
, wobei graphics das Graphikobjekt Deines Quellbitmaps ist.
GdipDrawImageRect(graphics, soucre, x, y, width, height);
Gruß xaromz |
AW: Resample oder Resize mit GDI+
ein Fetzen Code sagt mehr als 1000 Worte :)
muß nichts installiert werden
Delphi-Quellcode:
unit ExGraphicUtils;
//2010 Thomas Wassermann www.explido-software.de interface uses Windows, Classes, Sysutils, Graphics,GDIPAPI,GDIPOBJ, StdCtrls, jpeg, ActiveX; procedure SetCanvasZoomFactor(Canvas: TCanvas; AZoomFactor: Integer); Procedure SetCanvasZoomAndRotation(ACanvas:TCanvas;Zoom:Double;Angle:Double;CenterpointX,CenterpointY:Double); Procedure ScaleImage(source:String;dest:TCanvas;DestRect:Trect;Center:Boolean=true);overload; Procedure ScaleImage(source:TGraphic;dest:TCanvas;DestRect:Trect;Center:Boolean=true);overload; function CreateGraphicFromFile(const Filename: string): TGraphic; procedure MirrorBitmap(Bmp, MBmp: TBitmap;Horizonal:Boolean=true); implementation Procedure ScaleImage(source:String;dest:TCanvas;DestRect:Trect;Center:Boolean=true);overload; var graphics : TGPGraphics; image: TGPImage; width, height: Integer; faktor:Double; X, Y:Double; begin image:= TGPImage.Create(source); try width := image.GetWidth; height := image.GetHeight; if ((DestRect.Right - DestRect.Left) / width) < ((DestRect.Bottom -DestRect.Top)/Height) then faktor := (DestRect.Right - DestRect.Left) / width else faktor:= ((DestRect.Bottom -DestRect.Top)/Height); Faktor := ABS(Faktor); if Center then begin X := ((Destrect.Right - Destrect.Left) - faktor * width ) / 2; Y := ((Destrect.Bottom - Destrect.Top) - faktor * Height ) / 2; end else begin X := Destrect.Left; Y := Destrect.Top; end; graphics := TGPGraphics.Create(dest.Handle); try graphics.SetInterpolationMode(InterpolationModeHighQualityBicubic); graphics.DrawImage( image, MakeRect(X, Y , faktor * width, faktor * height), 0, 0, width, height, UnitPixel); finally graphics.Free; end; finally image.Free; end; end; Procedure ScaleImage(source:TGraphic;dest:TCanvas;DestRect:Trect;Center:Boolean=true);overload; var graphics : TGPGraphics; image: TGPImage; width, height: Integer; faktor:Double; STR : TMemoryStream; X, Y:Double; begin STR := TMemoryStream.Create; source.SaveToStream(STR); STR.Position := 0; image:= TGPImage.Create(TStreamAdapter.Create(Str)); try width := image.GetWidth; height := image.GetHeight; if ((DestRect.Right - DestRect.Left) / width) < ((DestRect.Bottom -DestRect.Top)/Height) then faktor := (DestRect.Right - DestRect.Left) / width else faktor:= ((DestRect.Bottom -DestRect.Top)/Height); Faktor := ABS(Faktor); if Center then begin X := ((Destrect.Right - Destrect.Left) - faktor * width ) / 2; Y := ((Destrect.Bottom - Destrect.Top) - faktor * Height ) / 2; end else begin X := Destrect.Left; Y := Destrect.Top; end; graphics := TGPGraphics.Create(dest.Handle); try graphics.SetInterpolationMode(InterpolationModeHighQualityBicubic); graphics.DrawImage( image, MakeRect(X, Y , faktor * width, faktor * height), 0, 0, width, height, UnitPixel); finally graphics.Free; end; finally STR.Free; image.Free; end; end; |
AW: Resample oder Resize mit GDI+
|
AW: Resample oder Resize mit GDI+
Zitat:
Aus diesem Grunde bin ich ja auch dazu gekommen, dass ich keine fette Unit für das Resizen brauche, sondern mir das ganze selbst schlank und schnell zusammen bauen kann. Aus schnell ist - wie man an diesem Thema sieht - nichts geworden. Aber ich habe keine andere Wahl. Denn im Moment mache ich das Scaling mit der GDI-Funktion (ohne "+")
Delphi-Quellcode:
und da leidet die Lesbarkeit unserer Dokumente erheblich. Beim Vergrößern (z.B. beim Ausdrucken mittels Printer.Canvas) ist das kein Problem. Aber wenn ich z.B. mit 300 oder 400 dpi eingescannte Bilder anwendungskonform auf 200 dpi bringen will, habe ich wirklich ein Problem.
StretchBlt()
|
AW: Resample oder Resize mit GDI+
Hast Du mal versucht, vorher den StretchBltMode auf HALFTONE zu setzen? Damit habe ich recht gute Erfahrungen gemacht.
|
AW: Resample oder Resize mit GDI+
Zitat:
Cool. Ich sehe grad, dass ich mich dann vermutlich bloß noch wegen des Speicherns als png-Datei mit GDI+ rumschlagen muss. Aber geschadet hat es trotzdem nichts und ich bleibe mal dran: womöglich sind die Ergebnisse mit GDI+ noch besser ;-) |
AW: Resample oder Resize mit GDI+
Folgender Code funktioniert bei mir:
Delphi-Quellcode:
Leider hatte ich am Wochenende wenig Zeit und den Code über GDI+ (noch) nicht zum Laufen bekommen. Ich scheitere im Moment daran, dass mir
Procedure TBitmapEx.StretchGDI(Const NewWidth, NewHeight: Integer);
Var ScaleDown : Boolean; W, H : Integer; oldW, oldH : Integer; Begin If (self.Empty) Or ((NewWidth = 0) And (NewHeight = 0)) Or ((NewWidth = self.Width) And (NewHeight = self.Height)) Then Exit; W:=NewWidth; H:=NewHeight; oldW:=self.Width; oldH:=self.Height; If (W = 0) Then W:=H * self.Width Div self.Height; If (H = 0) Then H:=W * self.Height Div self.Width; ScaleDown:=True; If (W < self.Width) Or (H < self.Height) Then SetStretchBltMode(self.Canvas.Handle, Halftone) Else Begin ScaleDown:= False; self.Width:= W; self.Height:=H; End; StretchBlt(self.Canvas.Handle, 0, 0, W, H, self.Canvas.Handle, 0, 0, oldW, oldH, SRCCOPY); If (ScaleDown) Then Begin self.Width:= W; self.Height:=H; End; End;
Delphi-Quellcode:
erklärt, ich würde falsche Parameter übergeben. Dabei ist
GdipSetInterpolationMode(Dest, 4);
Delphi-Quellcode:
und 4 sollte eigentlich
Type Dest: Pointer
Delphi-Quellcode:
sein. Letztere sollte auch anstelle von
Type InterpolationModeBicubic: Integer
Delphi-Quellcode:
laufen, wie es wiederum in der uGDIUnit von Cardinal Emil Weiss definiert ist.
Cardinal
Dazu wieder 2 Fragen:
Gruß & Dank, Alex |
AW: Resample oder Resize mit GDI+
Hallo,
Zitat:
(2) Genau, der Unterschied ist, dass Du einmal Float und einmal Integer verwenden kannst. (3) Image und Graphics sind zwei völlig unterschiedliche Klassen. Das ist quasi Bitmap und Canvas in der VCL. Ein Image hat immer ein Graphics, welches zum Manipulieren der Bitmapdaten dient. Ich vermute, dass deshalb Deine Interpolation fehlschlägt, weil Du der Funktion das Image übergibst, und nicht das entsprechende Graphics-Objekt. Gruß xaromz |
AW: Resample oder Resize mit GDI+
Danke für diesen wertvollen Hinweis!
Zitat:
Delphi-Quellcode:
Was mache in denn da falsch?
Function GdipSetInterpolationMode(Out graphics: GdipImage;
interpolationMode: GdipInterpolationMode): GdipStatus; Stdcall; External Gdip; // GdipImage = Pointer; GdipInterpolationMode = Integer Procedure TBitmapEx.StretchGdip(Const NewWidth, NewHeight: Integer; Const PreserveAspectRatio: Boolean = True); Var Source : GdipImage; // = Pointer Dest : GdipGraphics; // = Pointer Stat : GdipStatus; Begin If (Self.Empty) Then Exit; If (GdipCreateBitmapFromHBITMAP(self.Handle, self.Palette, Source) = Ok) Then Begin If (GdipGetImageGraphicsContext(Source, Dest) = Ok) Then Begin // Bis hierhin ist alles OK! Stat:=GdipSetInterpolationMode(Dest, 4); // Hier kommt der Hinweis auf falsche Parameter; leider nicht genau welcher der beiden möglichen... ShowMessage(GdipStatusMessage[Stat]); End; GdipDisposeImage(Source); End; End; Ich scheitere nun schon seit letzter Woche an
Delphi-Quellcode:
. Ich habe alle möglichen Deklarationen angefangen von GDIPlus über IGDIPlus bis hin zu dem Uhr-Beispiel von EWeiss probiert. Im Grunde fehlen doch nur noch 3 Zeilen ((1)Interpolation Mode setzen (2) Bild zeichnen mit Draw und (3) ggf. auf das TBitmap zurückschieben).
GdipSetInterpolationMode()
|
AW: Resample oder Resize mit GDI+
Die Vorgehensweise ist folgende..
1. Ein graphic obj erstellen
Code:
2. Setzen der Optimierungsmodis
GdipCreateFromHDC(Hdc, graphics);
Verschiedene modis die du verwenden kannst. Smoothing, Interpolation, PixelOffset, CompositingMode..
Code:
wobei InterpolationModeHighQualityBicubic den Wert 7 enthält..
GdipSetInterpolationMode(graphics, InterpolationModeHighQualityBicubic);
QualityModeHigh := 2; InterpolationModeHighQualityBicubic := QualityModeHigh + 5; erst dann die Bilddatei als solche öffnen! EDIT: Zitat:
Du kannst ein img nicht in ein graphic object konvertieren.. Source und Destination müssen von typ graphics sein. Zitat:
Aber davon abgesehen ist es bei MS auch ein Cardinal .. "Pointer of Cardinal" Bei mir gehts siehe Picture :) gruss |
AW: Resample oder Resize mit GDI+
Hier der Source zum Bild!
Vielleicht hilft es dir ja weiter :) gruss |
AW: Resample oder Resize mit GDI+
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Delphi-Quellcode:
aufgerufen.
GdipCreateFromHDC(TBitmap.Canvas.Handle, graphics);
Zitat:
Ich übergebe jetzt graphics mit
Delphi-Quellcode:
, wobei gilt:
GdipSetInterpolationMode(graphics, 7)
Delphi-Quellcode:
Ich habe jetzt mal aus lauter Verzweiflung einen kurzen Testcode beigefügt mit der GdipAPI.inc, die ich selbst gebastelt und bislang benutzt habe. Vielleicht sieht ja jemand auf Anhieb meinen Fehler.
Type
GdipGraphics = Pointer; GdipInterpolationMode = Integer; Function GdipSetInterpolationMode(Out graphics: GdipGraphics; interpolationMode: GdipInterpolationMode): GdipStatus; Stdcall; External Gdip; [EDIT] Mist! Du warst schneller ;-) [/EDIT] Gruß, Alex |
AW: Resample oder Resize mit GDI+
Siehe mein Source ;)
gruss |
AW: Resample oder Resize mit GDI+
Schmeiss mal das shit OUT aus "Out graphics: GdipGraphics" raus.
Dann funktioniert es auch. gruss |
AW: Resample oder Resize mit GDI+
Liste der Anhänge anzeigen (Anzahl: 1)
@Eweiss
Hi, Ich hatte Ihn so verstanden daß er ein bestehenden GraphicObject direkt skalieren will ohne Umweg über ein File. Ich habe mal eine Prozedur:
Delphi-Quellcode:
in Deinen Code mit eingebaut, erfordert allerdings Classes,ActiveX wg.
function DrawImageFromGraphic(source:TGraphic;
DrawHdc: HDC; Percent: Integer; Interpolation: InterpolationMode = InterpolationModeDefault; Smoothing : SmoothingMode = SmoothingModeNone; PixelOffset : PixelOffsetMode = PixelOffsetModeNone; CompositingQuality: CompositingQualityMode = CompositingQualityDefault; CompositingMode: CompositingModeMode = CompositingModeSourceOver): Boolean; function GdipLoadImageFromStreamICM(stream: ISTREAM; out image: Cardinal): Integer; stdcall; {$EXTERNALSYM GdipLoadImageFromStreamICM} ist nur eine Quickhack, Du darfst falls Du es brauchen kannst das ganze gern optimieren. |
AW: Resample oder Resize mit GDI+
@Bummi
Zitat:
Das Problem war aber eher das setzen des InterpolationMode Die übergebenen Parameter müssen identisch sein sonst klappt das nicht :) Er kann nicht bei Out graphis nicht einfach einen Pointer graphics übergeben ... Wenn schon dann bitte das OUT entfernen dann funktioniert das auch. gruss |
AW: Resample oder Resize mit GDI+
Zitat:
Delphi-Quellcode:
verkleinere.
StretchBlt()
Außerdem drucken wir auch. Die Drucker arbeiten alle mit 600 dpi, so dass das Bild vergrößern muss. Und da ich "Blut geleckt habe", möchte ich auch die Vergrößerung optimieren. Ansonsten wäre ich mit StretchBlt() und Halftone schon fertig gewesen. Das sieht nämlich ganz passabel aus und geht (auch) schnell. Zitat:
|
AW: Resample oder Resize mit GDI+
Wieder eine gute Tat für Heute :)
Heheheeee.. gruss |
AW: Resample oder Resize mit GDI+
So. Ich habe mir jetzt mal ausgehend von
![]() ![]()
Delphi-Quellcode:
Das Verkleinern funktioniert insoweit einwandfrei. Das vergrößern denknotwendiger Weise nicht. Denn ich muss vor dem Vergrößern den notwendigen Platz schaffen, indem ich Width und Height schon setze. Dann vergrößert er aber nichts mehr und ich habe weiter den weißen Rand, was auch logisch ist.
Procedure StretchGdip(Var Bitmap: TBitmap; Const NewWidth, NewHeight: Integer;
Smoothing : SmoothingMode = SmoothingModeNone; Interpolation: InterpolationMode = InterpolationModeDefault; PixelOffset : PixelOffsetMode = PixelOffsetModeNone; CompositingQuality: CompositingQualityMode = CompositingQualityDefault; CompositingMode: CompositingModeMode = CompositingModeSourceOver); Var ScaleDown : Boolean; W, H : Single; oldW, oldH : Single; graphics : Cardinal; str : TStream; image : Cardinal; Begin If (Bitmap.Empty) Or ((NewWidth = 0) And (NewHeight = 0)) Or ((NewWidth = Bitmap.Width) And (NewHeight = Bitmap.Height)) Then Exit; W:=NewWidth; H:=NewHeight; oldW:=Bitmap.Width; oldH:=Bitmap.Height; If (W = 0) Then W:=H * oldW / oldH; If (H = 0) Then H:=W * oldH / oldW; ScaleDown:=((W < oldW) Or (H < oldH)); If GdipCreateFromHDC(Bitmap.Canvas.Handle, graphics) = 0 Then Begin GdipSetSmoothingMode( graphics, Smoothing); GdipSetInterpolationMode( graphics, Interpolation); GdipSetPixelOffsetMode( graphics, PixelOffset); GdipSetCompositingQuality( graphics, CompositingQuality); GdipSetCompositingMode( graphics, CompositingMode); str:=TMemoryStream.Create; Try Bitmap.SaveToStream(str); str.Position:=0; If (Not ScaleDown) Then Begin Bitmap.Width:= Round(W); Bitmap.Height:=Round(H); End; If GdipLoadImageFromStreamICM(TStreamAdapter.Create(str), image) = 0 Then GdipDrawImageRect(graphics, image, 0, 0, W, H); If (ScaleDown) Then // überflüssige Ränder abschneiden Begin Bitmap.Width:= Round(W); Bitmap.Height:=Round(H); End; Finally str.Free; End; GdipDeleteGraphics(graphics); End; End; Ich wollte aber für die Ausgabe auf dem 600dpi-Drucker die 200dpi-Bilder entsprechend vergrößern. Bei meiner Version mit GDI (ohne "+") gibt es da keine Probleme, weil ich über
Delphi-Quellcode:
die alte und neue Größe angeben kann.
StretchBlt(self.Canvas.Handle,
0, 0, W, H, self.Canvas.Handle, 0, 0, oldW, oldH, SRCCOPY); Ich komme mit den weiteren Parametern bei
Delphi-Quellcode:
nicht klar. Gibt es dafür noch irgend eine Alternative?
GdipDrawImageRectRect
Gruß, Alex |
AW: Resample oder Resize mit GDI+
Du mußt graphics vorher neu erstellen
und dann kenn ich nur GdipDrawImageRectRectI :) Sample!
Delphi-Quellcode:
EDIT:
if GdipCreateFromHDC(hDCdest, Graphics) = 0 then
begin GdipCreateBitmapFromHBITMAP(hBM2, 0, Pointer(Img)); GdipSetInterpolationMode(Graphics, 2); GdipDrawImageRectRectI(Graphics, Img, xDest, yDest, xWidth, yHeight, 0, 0, xDiv, yDiv, 2, nil, False, nil); GdipDeleteGraphics(Graphics); GdipDisposeImage(Img); end; skDeleteObject(hBM2); DeleteDC(hDC2); Definition von GdipDrawImageRectRectI ist.. GdipDrawImageRectRectI Graphics, Img, 0, 0, newwidth, newheight, 0, 0, origwidth, origheight, UnitPixel gruss |
AW: Resample oder Resize mit GDI+
Daß Du hier nach Printer.BeginDoc
direkt auf auf das Printercanvas gehen kannst weißt Du schon, oder?
Delphi-Quellcode:
GdipCreateFromHDC(Printer.Canvas.Handle .....
|
AW: Resample oder Resize mit GDI+
@Schwedenbitter:
Auch wenn das Ganze schon uralt ist. Der oben abgebildete Source Code funktioniert so nur bedingt. Sobald die Ergebnis-Bitmap größer als die Ursprungs-Bitmap wird, bekommt man eine schöne Windows Exception präsentiert. Das liegt daran, dass die Routine GdipDrawImageRect nicht prüft, ob die Destination auch genügend Speicherplatz bietet. Eine möglich Lösung wäre: 1. Zuerst das Image GDI Objekt erstellen 2. Bitmap mit SetSize entsprechend der Ergebnisgröße setzen 3. Erst danach dipDrawImageRect(graphics, image, 0, 0, W, H) aufrufen! Gruß, Katte |
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:58 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz