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?

War es hilfreich?

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?!

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top