ein PNGImage Umwandlung in Graustufen unter Verwendung von Delphi
Frage
Hallo zusammen hier ist mein Code:
procedure TForm4.Button1Click(Sender: TObject);
var
png: TPNGImage;
data: PRGBQarray;
p: ^tagRGBQuad;
i, o: integer;
begin
png := TPNGImage.Create;
try
png.LoadFromFile('C:\Untitled.png');
for o := 1 to 100 do
begin
data:=png.Scanline[o];
for I := 1 to 400 do
begin
p := @data^[i];
p.rgbGreen := p.rgbBlue;
p.rgbRed := p.rgbGreen;
end;
end;
img.picture.Assign(png);
finally
png.Free;
end;
end;
es funktioniert nicht und es macht das Bild unordentlich, ich bin sicher, dass wegen der rgbReserved es ist. Was soll ich tun?
Lösung
Dies ist, wie ein Bitmap greyify. (Und ja, wenn Sie eine PNG greyify wollen, müssen Sie zuerst die Bitmap-Daten aus ihm heraus zu bekommen. Ich denke, die VCL wird dies für Sie tun.)
type
PRGB32Array = ^TRGB32Array;
TRGB32Array = packed array[0..MaxInt div SizeOf(TRGBQuad)-1] of TRGBQuad;
procedure MakeGrey(Bitmap: TBitmap);
var
w, h: integer;
y: Integer;
sl: PRGB32Array;
x: Integer;
grey: byte;
begin
Bitmap.PixelFormat := pf32bit;
w := Bitmap.Width;
h := Bitmap.Height;
for y := 0 to h - 1 do
begin
sl := Bitmap.ScanLine[y];
for x := 0 to w - 1 do
with sl[x] do
begin
grey := (rgbBlue + rgbGreen + rgbRed) div 3;
rgbBlue := grey;
rgbGreen := grey;
rgbRed := grey;
end;
end;
end;
Proben Nutzung:
procedure TForm4.Button1Click(Sender: TObject);
var
bm: TBitmap;
begin
bm := TBitmap.Create;
try
bm.LoadFromFile('C:\Users\Andreas Rejbrand\Pictures\Porträtt, litet, kvadratiskt.bmp');
MakeGrey(bm);
Canvas.Draw(0, 0, bm);
finally
bm.Free;
end;
end;
Andere Tipps
Andreas Antwort geben Ihnen eine gute, schnelle Annäherung, aber Sie werden einige Qualität verlieren, weil Rot, Grün und Blau nicht mit gleicher Intensität im menschlichen Auge mischen. Wenn Sie möchten, "get it right", anstelle von
grey := (rgbBlue + rgbGreen + rgbRed) div 3;
versuchen, diese:
grey := round(rgbRed * .3) + round(rgbGreen * .59) + round(rgbBlue * .11);
Sie werden ein bisschen eine Performance-Einbußen gegenüber dem einfachen Durchschnitt bekommen, obwohl es wahrscheinlich nicht wahrnehmbar sein wird, wenn Sie auf ein sehr großes Bild sind.
ich die Frage weiß bereits beantwortet worden, aber hier ist mein 2c wert ...
Der folgende Code stammt aus dem PNGComponents Paket (PngFunctions.pas), hergestellt von Thany.
//
//The Following code comes from the PNGComponents package from Thany...
//
procedure MakeImageGrayscale(Image: TPNGObject; Amount: Byte = 255);
procedure GrayscaleRGB(var R, G, B: Byte);
var
X: Byte;
begin
X := Round(R * 0.30 + G * 0.59 + B * 0.11);
R := Round(R / 256 * (256 - Amount - 1)) + Round(X / 256 * (Amount + 1));
G := Round(G / 256 * (256 - Amount - 1)) + Round(X / 256 * (Amount + 1));
B := Round(B / 256 * (256 - Amount - 1)) + Round(X / 256 * (Amount + 1));
end;
var
X, Y, PalCount: Integer;
Line: Pointer;
PaletteHandle: HPalette;
Palette: array[Byte] of TPaletteEntry;
begin
//Don't do anything if the image is already a grayscaled one
if not (Image.Header.ColorType in [COLOR_GRAYSCALE, COLOR_GRAYSCALEALPHA])
then begin
if Image.Header.ColorType = COLOR_PALETTE
then begin
//Grayscale every palette entry
PaletteHandle := Image.Palette;
PalCount := GetPaletteEntries(PaletteHandle, 0, 256, Palette);
for X := 0 to PalCount - 1
do GrayscaleRGB(Palette[X].peRed, Palette[X].peGreen, Palette[X].peBlue);
SetPaletteEntries(PaletteHandle, 0, PalCount, Palette);
Image.Palette := PaletteHandle;
end
else begin
//Grayscale every pixel
for Y := 0 to Image.Height - 1
do begin
Line := Image.Scanline[Y];
for X := 0 to Image.Width - 1
do GrayscaleRGB(PRGBLine(Line)^[X].rgbtRed, PRGBLine(Line)^[X].rgbtGreen, PRGBLine(Line)^[X].rgbtBlue);
end;
end;
end;
end;
Es gibt eine Reihe von Routinen, die ursprünglich vom Autor der PNGImage Komponenten veröffentlicht wurden, die auf dem Code Zentrale gefunden werden können, dass zeigt, wie andere Dinge, wie Alpha tun Mischen von zwei Bildern, Rotation, Overlay etc. Link-Codecentral
Das ist wirklich haben sollte einen Kommentar zu @ Mason Routine gewesen RGB in Grautönen zu drehen, aber da ich nicht weiß, wie man einen Kommentar Show Code zu machen, ich mache es eine Antwort statt.
Dies ist, wie ich die Konvertierung zu tun:
FUNCTION RGB2GRAY(R,G,B : BYTE) : BYTE; Register; ASSEMBLER;
ASM
IMUL EAX,19595
IMUL EDX,38470
IMUL ECX,7471
ADD EAX,EDX
ADD EAX,ECX
SHR EAX,16
END;
FUNCTION GreyScale(C : TColor) : TColor; Register; ASSEMBLER;
ASM
MOVZX EDX,AH
MOV ECX,EAX
SHR ECX,16
MOVZX EAX,AL
CALL RGB2GRAY
MOVZX EAX,AL
MOV AH,AL
SHL EAX,8
MOV AL,AH
END;
Ich weiß nicht, ob es NTSC Formel ist oder was auch immer, aber sie scheinen zu Arbeit in meinen Programmen: -).
Warum gehst du nicht einfach Zuweisen zu einem TJPEGImage, stellen Sie die Graustufen-Eigenschaft des JPEG zu wahren und dann assign zurück zu TPngImage?!