|
Registriert seit: 4. Jun 2010 15.392 Beiträge |
#1
Tbitmap.scanline es una propiedad indexada de solo lectura que devuelve un puntero a una fila de pixeles de un bitmap. Es la forma más rápida de acceder a los píxeles de una imagen y esto depende del formato del mapa de bits que se indica desde la propiedad Pixelformat de la unit Graphics. TPixelFormat = (pfDevice, pf1bit, pf4bit, pf8bit, pf15bit, pf16bit, pf24bit, pf32bit, pfCustom); Ejemplo de carga un bitmap: VAR bmp: tbitmap; BEGIN bmp := tbitmap.Create; TRY IF OpenDialog1.Execute THEN BEGIN bmp.LoadFromFile(OpenDialog1.FileName); bmp.PixelFormat := pf24bit; Invalidate; { Mostrar la imagen } END; FINALLY bmp.Free; END; END; Cuando creamos un mapa de bits cada pixel se inicializa al máximo valor, es decir a 255 por eso el mapa de bits es blanco, ese el formato de pixel predeterminado. Un pixel en un mapa de bits de 24 bits se describe con 3 valores rojo, verde y azul, que se almacenan en la memoria en orden inverso: azul, verde y rojo. El puntero a la matriz de bytes que hace scanline se vería de la siguiente forma: Para obtener el resultado anterior hay que asignar el resultado de Scanline a un puntero de bytes: pByteArray VAR p: PByteArray; BEGIN p := FImage.ScanLine[0]; END; Por ejemplo para poner el primer pixel de de la primera fila de la imagen de color negro y el segundo de color blanco habría que hacer: VAR p: PByteArray; BEGIN p := FImage.ScanLine[0]; { lee la primera fila } p[0] := 0; { primer pixel de color negro } p[1] := 0; p[2] := 0; p[3] := 255; { segundo pixel de color blanco } p[4] := 255; p[5] := 255; Invalidate; END; También podemos usar la siguiente estructura: type TRGBTriple = packed record rgbtBlue: Byte; rgbtGreen: Byte; rgbtRed: Byte; end; Para conseguir que la segunda fila del bitmap sea de color negro: type PRGBTripleArray = ^TRGBTripleArray; TRGBTripleArray = array[0..4095] of TRGBTriple; procedure TForm1.Button1Click(Sender: TObject); var I: Integer; Bitmap: TBitmap; Pixels: PRGBTripleArray; begin Bitmap := TBitmap.Create; try Bitmap.Width := 3; Bitmap.Height := 2; Bitmap.PixelFormat := pf24bit; // get pointer to the second row's raw data Pixels := Bitmap.ScanLine[1]; // iterate our row pixel data array in a whole width for I := 0 to Bitmap.Width - 1 do begin Pixels[I].rgbtBlue := 0; Pixels[I].rgbtGreen := 0; Pixels[I].rgbtRed := 0; end; Bitmap.SaveToFile('c:\Image.bmp'); finally Bitmap.Free; end; end; De lo anterior podemos observar que el primer pixel del bitmap se encuentra en el offset 0 de la primera fila, el segundo en el offset 3, el tercero en el offset 6 esto quiere decir que el byte en la ubicación x*3 es el componente azul, el byte de la ubicación x*3+1 es el componente verde y el x*3+2 es el rojo. Entonces si quisiéramos poner una imagen en color negro habría que hacer lo siguiente: VAR p: PByteArray; x: Integer; y: Integer; BEGIN { Iterar entre todas las líneas} FOR y := 0 TO Pred(FImage.Height) DO BEGIN p := FImage.ScanLine[y]; FOR x := 0 TO Pred(FImage.Width) DO BEGIN p[x * 3] := 0; p[x * 3 + 1] := 0; p[x * 3 + 2] := 0; END; END; END; Ahora vamos a profundizar un poco más en este aspecto, hemos visto que cambiando los valores de los bytes de un pixel podemos conseguir los diferentes tipos de colores y si vamos un poco más allá conseguiremos espectaculares efectos visuales como los siguientes: - Solarize VAR p: PByteArray; x: Integer; y: Integer; BEGIN FOR y := 0 TO Pred(FImage.Height) DO BEGIN p := FImage.ScanLine[y]; FOR x := 0 TO Pred(FImage.Width) DO BEGIN IF p[x * 3] > 127 THEN p[x * 3] := 255 - p[x * 3]; IF p[x * 3 + 1] > 127 THEN p[x * 3 + 1] := 255 - p[x * 3 + 1]; IF p[x * 3 + 2] > 127 THEN p[x * 3 + 2] := 255 - p[x * 3 + 2]; END; END; END; - Invertir colores VAR p: PByteArray; x: Integer; y: Integer; BEGIN FOR y := 0 TO Pred(FImage.Height) DO BEGIN { get the pointer to the y line } p := FImage.ScanLine[y]; FOR x := 0 TO Pred(FImage.Width) DO BEGIN { modificar el color azul } p[x * 3] := 255 - p[x * 3]; { modificar el color verde } p[x * 3 + 1] := 255 - p[x * 3 + 1]; { modificar el color rojo } p[x * 3 + 2] := 255 - p[x * 3 + 2]; END; END; END; - Convertir a escala de grises Se hace con la siguiente fórmula Gray = (Red * 3 + Blue * 4 + Green * 2) div 9 VAR p: PMyPixelArray; x: Integer; y: Integer; gray: Integer; BEGIN FOR y := 0 TO Pred(FImage.Height) DO BEGIN p := FImage.ScanLine[y]; FOR x := 0 TO Pred(FImage.Width) DO WITH p[x] DO BEGIN gray := (Red * 3 + Blue * 4 + Green * 2) DIV 9; Blue := gray; Red := gray; Green := gray; END; END; END; - Hacer un espejo vertical procedure TForm1.Button1Click(Sender: TObject); procedure EspejoVertical(Origen,Destino:TBitmap); var x,y : integer; Alto : integer; Po,Pd : PByteArray; tmpBMP : TBitmap; LongScan : integer; begin {Si es un modo raro... pasamos} case Origen.PixelFormat of pfDevice, pfCustom: Raise exception.create( 'Formato no soportado'+#13+ 'Bitmap Format not valid'); end; {Calculamos variables intermedias} Alto :=Image1.Picture.Bitmap.Height-1; try {Calculo de cuánto ocupa un scan} LongScan:= Abs( Integer(Origen.ScanLine[0])- Integer(Origen.ScanLine[1]) ); except Raise exception.create( 'ScanLine Error...'); end; {Cremos un bitmap intermedio} tmpBMP:=TBitmap.Create; with tmpBMP do begin {Lo asignamos, así se copia la paleta si la hay} Assign(Origen); {Esto es para que sea un bitmap nuevo... es un bug de D3 y D4} Canvas.Pixels[0,0]:=Origen.Canvas.Pixels[0,0]; end; {Damos la vuelta al bitmap} for y:=0 to Alto do begin Po := Origen.ScanLine[y]; Pd := tmpBMP.ScanLine[Alto-y]; for x := 0 to LongScan-1 do begin Pd^[X]:=Po^[X]; end; end; {Lo asignamos al bitmap destino} Destino.Assign(tmpBMP); {Esto es para parchear un bug de Delphi 3 y Delphi4...} Destino.Canvas.Pixels[0,0]:=tmpBMP.Canvas.Pixels[0,0]; tmpBMP.Free; end; begin EspejoVertical( Image1.Picture.Bitmap, Image1.Picture.Bitmap); Image1.Refresh; end; - Ajustar el brillo Se hace con la siguiente fórmula: NewPixel = OldPixel + (1 * Percent) div 200 FUNCTION IntToByte(AInteger: Integer): Byte; INLINE; BEGIN IF AInteger > 255 THEN Result := 255 ELSE IF AInteger < 0 THEN Result := 0 ELSE Result := AInteger; END; PROCEDURE TMainForm.AdjustBrightness(Percent: Integer); VAR p: PMyPixelArray; x: Integer; y: Integer; amount: Integer; BEGIN amount := (255 * Percent) DIV 200; FOR y := 0 TO Pred(FImage.Height) DO BEGIN p := FImage.ScanLine[y]; FOR x := 0 TO Pred(FImage.Width) DO WITH p[x] DO BEGIN Blue := IntToByte(Blue + amount); Green := IntToByte(Green + amount); Red := IntToByte(Red + amount); END; END; Invalidate; END; PROCEDURE TMainForm.ScanLineBrightnessClick(Sender: TObject); VAR amount: Integer; BEGIN amount := StrToInt(InputBox('Brightness Level', 'Enter a value from -100 to 100:', '50')); AdjustBrightness(amount); END;Suscribirse : Weiterlesen... |
Zitat |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |