Sign in Join
Wiki copytemporary

Developing with Graphics/es: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11Esta página dará inicio a una serie de tutorías que trataran sobre la manipulación de mapa de bits y otros tipos de gráficos. Como no soy un experto programador de gráficos, ¡invito a todos a compartir sus experiencias! Basta con añadir un enlace a la siguiente sección, añadir una página y crear su propio artículo para el Wiki.
22
33   En esta página se dará alguna información general.
44
55## Otros artículos sobre gráficos
66
77### Dibujo 2D
88
99- [[ZenGL]] - Desarrollo de juegos multi-plataforma usando OpenGL.
1010- [[BGRABitmap]] - Dibuja formas y mapas de bits con transparencia, acceso directo a los píxeles, etc.
1111- [[LazRGBGraphics]] - Un paquete para un veloz procesado en memoria de imagenes y manipulado de puntos (pixel) (similar a *scan line*)
1212- [[Double Gradient]] - Dibuja gradientes dobles y 'n gradientes' en bitmaps facilmente.
1313- [[Gradient Filler]] - TGradientFiller es la mejor manera de crear 'n gradientes' personalizados en Lazarus.
1414- [[PascalMagick]] - Una forma fácil de usar la API para interactuar con [ImageMagick](http://www.imagemagick.org), un paquete software libre multiplataforma para crear, editar y componer imágenes de mapa de bit.
1515- [[Sample Graphics/es]] - Galería de gráficos creada con Lazarus y herramientas de dibujo.
1616
1717### Dibujo 3D
1818
1919- [[GLScene]] - Una adaptación de la librería visual de gráficos OpenGL [GLScene](http://www.glscene.org)
2020
2121### Gráficos
2222
2323- [[TAChart/es|TAChart]] - Componente gráfico para Lazarus
2424- [[PlotPanel/es|PlotPanel]] - Un componente para trazar y realizar gráficos animados
2525- [[Perlin Noise]] - Un atículo sobre la utilización de Perlin Noise en aplicaciones LCL.
2626
2727## Trabajo con TBitmap
2828
2929   Lo primero que hay que recordar es que Lazarus quiere decir plataforma independiente, así que todos los métodos que usan funcionalidades de la API de Windows se salen de la cuestión. Así que un método como ScanLine no es soportado por Lazarus, porque está destinado a Device Independent Bitmap y usa funciones de GDI32.dll.
3030
3131   Tenga cuidado porque si no especifica la anchura y altura de su [[doc:lcl/graphics/tbitmap.html|TBitmap]] tendrá la predefinida, que es muy pequeña.
3232
3333### Un ejemplo de desvanecimiento (fading)
3434
3535   Supongamos que quiere hacer una imagen que se desvanece. En Delphi podría hacer algo así:
3636
3737``` pascal
3838 type
3939 PRGBTripleArray = ^TRGBTripleArray;
4040 TRGBTripleArray = array[0..32767] of TRGBTriple;
4141
4242 procedure TForm1.FadeIn(aBitMap: TBitMap);
4343 var
4444 Bitmap, BaseBitmap: TBitmap;
4545 Row, BaseRow: PRGBTripleArray;
4646 x, y, step: integer;
4747 begin
4848 Bitmap := TBitmap.Create;
4949 try
5050 Bitmap.PixelFormat := pf32bit; // o bien pf24bit
5151 Bitmap.Assign(aBitMap);
5252 BaseBitmap := TBitmap.Create;
5353 try
5454 BaseBitmap.PixelFormat := pf32bit;
5555 BaseBitmap.Assign(Bitmap);
5656 for step := 0 to 32 do begin
5757 for y := 0 to (Bitmap.Height - 1) do begin
5858 BaseRow := BaseBitmap.Scanline[y];
5959 Row := Bitmap.Scanline[y];
6060 for x := 0 to (Bitmap.Width - 1) do begin
6161 Row[x].rgbtRed := (step * BaseRow[x].rgbtRed) shr 5; // desvanec. rojo
6262 Row[x].rgbtGreen := (step * BaseRow[x].rgbtGreen) shr 5; // desvanec. verde
6363 Row[x].rgbtBlue := (step * BaseRow[x].rgbtBlue) shr 5; // desvanec. azul
6464 // disminuyendo progresivamente los valores RGB (Red,Green,Blue o Rojo,
6565 // Verde, Azul que son tres componentes que forman el color a mostrar
6666 // logramos que la imagen se vaya apagando hasta quedarse a oscuras.
6767 end;
6868 end;
6969 Form1.Canvas.Draw(0, 0, Bitmap);
7070 InvalidateRect(Form1.Handle, nil, False);
7171 RedrawWindow(Form1.Handle, nil, 0, RDW_UPDATENOW);
7272 end;
7373 finally
7474 BaseBitmap.Free;
7575 end;
7676 finally
7777 Bitmap.Free;
7878 end;
7979 end;
8080```
8181
8282   Está función en Lazarus sería así:
8383
8484``` pascal
8585{ This code has been taken from the $LazarusPath/examples/lazintfimage/fadein1.lpi project. }
8686uses LCLType, // HBitmap type
8787 IntfGraphics, // TLazIntfImage type
8888 fpImage; // TFPColor type
8989
9090 procedure TForm1.FadeIn(ABitMap: TBitMap);
9191 var
9292 SrcIntfImg, TempIntfImg: TLazIntfImage;
9393 ImgHandle,ImgMaskHandle: HBitmap;
9494 FadeStep: Integer;
9595 px, py: Integer;
9696 CurColor: TFPColor;
9797 TempBitmap: TBitmap;
9898 begin
9999 SrcIntfImg:=TLazIntfImage.Create(0,0);
100100 SrcIntfImg.LoadFromBitmap(ABitmap.Handle,ABitmap.MaskHandle);
101101 TempIntfImg:=TLazIntfImage.Create(0,0);
102102 TempIntfImg.LoadFromBitmap(ABitmap.Handle,ABitmap.MaskHandle);
103103 TempBitmap:=TBitmap.Create;
104104 for FadeStep:=1 to 32 do begin
105105 for py:=0 to SrcIntfImg.Height-1 do begin
106106 for px:=0 to SrcIntfImg.Width-1 do begin
107107 CurColor:=SrcIntfImg.Colors[px,py];
108108 CurColor.Red:=(CurColor.Red*FadeStep) shr 5;
109109 CurColor.Green:=(CurColor.Green*FadeStep) shr 5;
110110 CurColor.Blue:=(CurColor.Blue*FadeStep) shr 5;
111111 TempIntfImg.Colors[px,py]:=CurColor;
112112 end;
113113 end;
114114 TempIntfImg.CreateBitmaps(ImgHandle,ImgMaskHandle,false);
115115 TempBitmap.Handle:=ImgHandle;
116116 TempBitmap.MaskHandle:=ImgMaskHandle;
117117 Canvas.Draw(0,0,TempBitmap);
118118 end;
119119 SrcIntfImg.Free;
120120 TempIntfImg.Free;
121121 TempBitmap.Free;
122122 end;
123123```
124124
125125   El código Lazarus de esta página se ha tomado del proyecto \$LazarusPath/examples/lazintfimage/fadein1.lpi . Así que si desea iniciarse en la programación de gráficos eche una mirada a este ejemplo.
126126
127127### Dibujando mapa de bits de color transparente
128128
129129   Una nueva característica, incluida en Lazarus 0.9.11, son los mapa de bits de color transparente. Los archivos Bitmap (*.BMP) no pueden almacenar cualquier información sobre transparencia, pero pueden trabajar como si la tuviera si selecciona un color en ellos para representar la zona transparente. Este es un truco habitual usado en aplicaciones Win32.
130130
131131   El siguiente ejemplo carga un mapa de bit desde un recurso Windows, selecciona un color para que sea transparente (clFuchsia) y después lo dibuja.
132132
133133``` pascal
134134procedure MyForm.MyButtonOnClick(Sender: TObject);
135135var
136136 buffer: THandle;
137137 bmp: TBitmap;
138138 memstream: TMemoryStream;
139139begin
140140 bmp := TBitmap.Create;
141141
142142 buffer := Windows.LoadBitmap(hInstance, MAKEINTRESOURCE(ResourceID));
143143
144144 if (buffer = 0) then exit; // Error cargando el mapa de bits
145145
146146 bmp.Handle := buffer;
147147 memstream := TMemoryStream.create;
148148 try
149149 bmp.SaveToStream(memstream);
150150 memstream.position := 0;
151151 bmp.LoadFromStream(memstream);
152152 finally
153153 memstream.free;
154154 end;
155155
156156 bmp.Transparent := True;
157157 bmp.TransparentColor := clFuchsia;
158158
159159 MyCanvas.Draw(0, 0, bmp);
160160
161161 bmp.Free; // Liberar el recurso Tbitmap (bmp) creado con anterioridad
162162end;
163163```
164164
165165   Observe las operaciones de memoria realizadas con [[doc:rtl/classes/tmemorystream.html|TMemoryStream]]. Son necesarios para garantizar la correcta carga de la imagen.
166166
167167### Tomar una captura de la pantalla
168168
169169   Desde Lazarus 0.9.16 podemos utilizar la LCL para realizar capturas de la pantalla de forma multiplataforma. El código de ejemplo siguiente lo hace (funciona en gtk2 y Win32, pero no en gtk1 actualmente):
170170
171171``` pascal
172172 uses LCLIntf, LCLType;
173173
174174 ...
175175
176176 var
177177 MyBitmap: TBitmap;
178178 ScreenDC: HDC;
179179 begin
180180 MyBitmap := TBitmap.Create;
181181 ScreenDC := GetDC(0);
182182 MyBitmap.LoadFromDevice(ScreenDC);
183183 ReleaseDC(ScreenDC);
184184
185185 ...
186186```
187187
188188### Pintar un *TLazIntfImage* en el lienzo (*Canvas*)
189189
190190   Puesto que la propiedad *ScanLines* ha sido temporalmente removida de la clase *TBitmap*, la única forma de acceder a datos de línea de exploración de un mapa de bits, es utilizar TLazIntfImage. Esta es una muestra de cómo crear un *TLazIntfImage* desde un *TBitmap* y, a continuación, dibujarlo en el lienzo (*canvas*).
191191
192192``` pascal
193193uses
194194 ...GraphType, IntfGraphics, LCLType, LCLProc, LCLIntf ...
195195
196196procedure TForm1.Button4Click(Sender: TObject);
197197var
198198 b: TBitmap;
199199 t: TLazIntfImage;
200200 bmp, old: HBitmap;
201201 msk: HBitmap;
202202 tmpDC: HDC;
203203begin
204204 b := TBitmap.Create;
205205 try
206206 b.LoadFromFile('test.bmp');
207207 t := b.CreateIntfImage;
208208 t.CreateBitmaps(bmp, msk, false);
209209
210210 tmpDC := CreateCompatibleDC(Canvas.Handle);
211211 old := SelectObject(tmpDC, bmp);
212212 BitBlt(Canvas.Handle, 0, 0, t.Width, t.Height, tmpDC, 0, 0, SRCCOPY);
213213 DeleteObject(SelectObject(tmpDC, old));
214214 DeleteObject(msk);
215215 DeleteDC(tmpDC);
216216
217217 finally
218218 t.Free;
219219 b.Free;
220220 end;
221221end;
222222```
223223
224224## Gráficos en movimiento - Cómo evitar el parpadeo
225225
226226   Muchos programas dibujan su salida al GUI como gráficos 2D. Si esos gráficos necesitan cambiar rápidamente, pronto tendrá un problema: los gráficos que cambian rápidamente a menudo parpadean en la pantalla. Esto ocurre cuando los usuarios algunas veces ven las imágenes ocultas y algunas veces las ven cuando se dibujan sólo parcialmente. Esto ocurre porque el proceso de pintar requiere tiempo.
227227
228228   Pero ¿cómo puedo evitar el parpadeo y conseguir la mejor velocidad de trazado? Claro, podría trabajar con aceleración de hardware utilizando OpenGL, pero es verdaderamente pesado para pequeños programas u ordenadores antiguos. Este tutorial esta enfocado hacia el dibujo con TCanvas. Si necesita ayuda con OpenGL, eche una mirada al ejemplo que viene con Lazarus. Puede también usar el paquete para juegos de A. J. Venter, que proporciona un canvas (lienzo) de doble memoria intermedia y un componente sprite (objeto móvil).
229229
230230   Ahora examinaremos las opciones que tenemos para dibujar en un Canvas (lienzo):
231231
232232- Dibujar en un TImage
233233- Dibujar en el envento OnPaint del formulario, un TPaintBox u otro control
234234- Crear un control personalizado que se dibuja a sí mismo
235235- Utilizando el paquete para juegos de A.J. Venter
236236
237237### Dibujar en un TImage
238238
239239   Un *TImage* consta de 2 partes: Un *TGraphic*, por lo general un *TBitmap*, conteniendo la imagen persistente y el área visual, que es pintada en cada evento *OnPaint*. Cambiar el tamaño del *TImage* **no** cambiar el tamaño del mapa de bits. El gráfico (o mapa de bits) es accesible a través de *Image1.Picture.Graphic* (o *Image1.Picture.Bitmap*). El lienzo es *Image1.Picture.Bitmap.Canvas*. El lienzo de la zona visual de un *TImage* sólo es accesible durante *Image1.OnPaint* través de *Image1.Canvas*.
240240
241241   **Importante**: Nunca use el evento *OnPain*t para dibujar en un *TImage*. Un *TImage* es almacenado en la memoria intermedia por lo que todo lo que necesita hacer es dibujarlo desde cualquier lugar y se cambia para siempre. Sin embargo, si constantemente redibuja, la imagen parpadeará. En este caso puede intentar otras opciones. Dibujar en un *TImage* se considera más lento que otras posibilidades.
242242
243243#### Redimensionando el mapa de bits de un *TImage*
244244
245245   Nota: No uses esto duante un *OnPaint*.
246246
247247``` pascal
248248 with Image1.Picture.Bitmap do begin
249249 Width:=100;
250250 Height:=120;
251251 end;
252252```
253253
254254#### Pintando el mapa de bits de un *TImage*
255255
256256   Nota: No uses esto duante un *OnPaint*.
257257
258258``` pascal
259259 with Image1.Picture.Bitmap.Canvas do begin
260260 // fill the entire bitmap with red
261261 Brush.Color:=clRed;
262262 FillRect(0,0,Width,Height);
263263 end;
264264```
265265
266266   Nota: dentro de un *Image1.OnPaint* el lienzo (el *Image1.Canvas*) apunta al área visible volátil. Fuera del evento *Image1.OnPaint* el lienzo apunta a *Image1.Picture.Bitmap.Canvas*.
267267
268268   Otro ejemplo:
269269
270270``` pascal
271271procedure TForm1.BitBtn1Click(Sender: TObject);
272272 var
273273 x, y: Integer;
274274 begin
275275 // Pinta el fondo
276276 MyImage.Canvas.Pen.Color := clWhite;
277277 MyImage.Canvas.Rectangle(0, 0, Image.Width, Image.Height);
278278
279279 // Dibuja cuadrados
280280 MyImage.Canvas.Pen.Color := clBlack;
281281 for x := 1 to 8 do
282282 for y := 1 to 8 do
283283 MyImage.Canvas.Rectangle(Round((x - 1) * Image.Width / 8), Round((y - 1) * Image.Height / 8),
284284 Round(x * Image.Width / 8), Round(y * Image.Height / 8));
285285 end;
286286```
287287
288288#### Pintando el área visual volátil de un *TImage*
289289
290290   Sólo se puede pintar en esta área durante *OnPaint*.*OnPaint* se llama automáticamente por el LCL, cuando la zona es invalidada. Se puede invalidar la zona manualmente con *Image1.Invalidate*. Esto no llamará inmediatamente a *OnPaint* y es posible invocar *Invalidate* tantas veces como se desee.
291291
292292``` pascal
293293procedure TForm.Image1Paint(Sender: TObject);
294294 begin
295295 with Image1.Canvas do begin
296296 // paint a line
297297 Pen.Color:=clRed;
298298 Line(0,0,Width,Height);
299299 end;
300300 end;
301301```
302302
303303### Dibujar en el evento OnPaint
304304
305305   En este caso todo tiene que dibujarlo en el evento OnPaint del formulario. No se mantiene en la memoria intermedia, como en el TImage.
306306
307307### Crear un control personalizado que se dibuja a sí mismo
308308
309309   Crear un control personalizado tiene la ventaja de estructurar su código y poder reutilizar el control. Está opción es muy rápida, pero puede todavía generar parpadeo si no dibuja en un TBitmap primero y después dibuja en el canvas (lienzo). En este caso no necesita utilizar el evento OnPaint del control.
310310
311311   Este es un ejemplo de control personalizado:
312312
313313``` pascal
314314 uses Classes, SysUtils, Controls, Graphics, LCLType;
315315
316316 type
317317 TMyDrawingControl = class(TCustomControl)
318318 public
319319 procedure EraseBackground(DC: HDC); override;
320320 procedure Paint; override;
321321 end;
322322
323323 implementation
324324
325325 procedure TMyDrawingControl.EraseBackground(DC: HDC);
326326 begin
327327 // Quita los comentarios para habilitar el borrado del fondo predeterminado
328328 //inherited EraseBackground(DC);
329329 end;
330330
331331 procedure TMyDrawingControl.Paint;
332332 var
333333 x, y: Integer;
334334 Bitmap: TBitmap;
335335 begin
336336 Bitmap := TBitmap.Create;
337337 try
338338 // Initializes the Bitmap Size
339339 Bitmap.Height := Height;
340340 Bitmap.Width := Width;
341341
342342 // Draws the background
343343 Bitmap.Canvas.Pen.Color := clWhite;
344344 Bitmap.Canvas.Rectangle(0, 0, Width, Height);
345345
346346 // Draws squares
347347 Bitmap.Canvas.Pen.Color := clBlack;
348348 for x := 1 to 8 do
349349 for y := 1 to 8 do
350350 Bitmap.Canvas.Rectangle(Round((x - 1) * Width / 8), Round((y - 1) * Height / 8),
351351 Round(x * Width / 8), Round(y * Height / 8));
352352
353353 Canvas.Draw(0, 0, Bitmap);
354354 finally
355355 Bitmap.Free;
356356 end;
357357
358358 inherited Paint;
359359 end;
360360```
361361
362362   y cómo lo creamos en el formulario:
363363
364364``` pascal
365365procedure TMyForm.FormCreate(Sender: TObject);
366366 begin
367367 MyDrawingControl:= TMyDrawingControl.Create(Self);
368368 MyDrawingControl.Height := 400;
369369 MyDrawingControl.Width := 500;
370370 MyDrawingControl.Top := 0;
371371 MyDrawingControl.Left := 0;
372372 MyDrawingControl.Parent := Self;
373373 MyDrawingControl.DoubleBuffered := True;
374374 end;
375375```
376376
377377    y para destruirlo:
378378
379379``` pascal
380380procedure TMyForm.FormDestroy(Sender: TObject);
381381 begin
382382 MyDrawingControl.Free;
383383 end;
384384```
385385
386386   Aunque se destruye de forma automática, porque usamos *self* como propietario.
387387
388388   No es necesario asignar cero a Top y Left, ya que ésta es la posición predefinida, pero se hace así para reforzar la posición donde se colocará el control.
389389
390390   "MyDrawingControl.Parent := Self;" es muy importante y no se verá el control si no se hace así.
391391
392392   "MyDrawingControl.DoubleBuffered := True;" se requiere para evitar el parpadeo en Windows. No tiene ningún efecto en gtk.
393393
394394### Utilizando el paquete para juegos de A.J. Venter
395395
396396   El paquete para juegos está enfocado al dibujo de cualquier cosa en un *canvas* (lienzo) de doble memoria intermedia, que sólo se actualiza cuando usted está preparado. Esto supone verdaderamente bastante código, pero tiene la ventaja de ser capaz de hacer muy rápidamente cambios de escenas con múltiples *sprites* (objetos móviles) en ellos. Si desea utilizar esta opción, puede interesarle el paquete para juegos de A. J. Venter, un conjunto de componentes para desarrollar juegos en Lazarus, que proporciona un componente de pantalla de doble memoria intermedia así como un componente *sprite* (ojeto móvil), diseñado para integrarse bien con cualquier otro. Puede obtener el paquete para juegos via subversion:\
397397`svn co `[`svn://silentcoder.co.za/lazarus/gamepack`](svn://silentcoder.co.za/lazarus/gamepack)    Más información, documentación y descargas en la [página principal](http://outkastsolutions.co.za/outkast/index.php?option=com_openwiki&Itemid=&id=gamepack).
398398
399399## Formatos Gráficos y Clases de Imágenes
400400
401401   Esta tabla muestra la clase adecuada a utilizar para cada formato de imagen.
402402
403403| Formato | Clase de Imagen | Unidad |
404404|--------------------------------|-------------------------|----------|
405405| Cursor (cur) | TCursor | Graphics |
406406| Bitmap (bmp) | TBitmap | Graphics |
407407| Windows icon (ico) | TIcon | Graphics |
408408| Mac OS X icon (icns) | TicnsIcon | Graphics |
409409| Pixmap (xpm) | TPixmap | Graphics |
410410| Portable Network Graphic (png) | TPortableNetworkGraphic | Graphics |
411411| JPEG (jpg, jpeg) | TJpegImage | Graphics |
412412| PNM (pnm) | TPortableAnyMapGraphic | Graphics |
413413
414-\
415-
416414## El formato del punto (*pixel*)
417415
418416### TColor
419417
420418   La representación interna de un punto de un *TColor* en la LCL tiene esta forma XXBBGGRR, que coincide con el formato nativo de Windows y es el inverso del que usan la mayoría de las otras librerías, que utilizan AARRGGBB. La parte XX se utiliza para identificar si el color es un color fijo, cuyo caso XX será 00 o si es un índice a un sistema de colores. No hay espacio reservado para un canal alfa.
421419
422420   Para convertir desde un canal separado RGB a *TColor* podemos usar esto:
423421
424422``` pascal
425423 RGBToColor(RedVal, GreenVal, BlueVal);
426424```
427425
428426   Para obtener cada canal de una variable *TColor* usaremos las fucniones *Red*, *Green* y *Blue*:
429427
430428``` pascal
431429 RedVal := Red(MyColor);
432430 GreenVal := Green(MyColor);
433431 BlueVal := Blue(MyColor);
434432```
435433
436434### TFPColor
437435
438436   *TFPColor* utiliza el formato AARRGGBB común en muchas librerías.
439437
440438## Trabajando con el lienzo mediante *TCanvas*
441439
442440### Usando la fuente predeterminada de la interfaz IGU
443441
444442   Esta tarea se puede realizar con este simple código:
445443
446444``` pascal
447445SelectObject(Canvas.Handle, GetStockObject(DEFAULT_GUI_FONT));
448446```
449447
450448### Dibujando un texto limitado a cierto ancho
451449
452450   Usaremos *DrawText*, primero con *DT_CALCRECT* y después sin ello.
453451
454452``` pascal
455453 // Primero calculamos el tamaño del texto para después pintarlo
456454 TextBox := Rect(0, currentPos.Y, Width, High(Integer));
457455 DrawText(ACanvas.Handle, PChar(Text), Length(Text),
458456 TextBox, DT_WORDBREAK or DT_INTERNAL or DT_CALCRECT);
459457
460458 DrawText(ACanvas.Handle, PChar(Text), Length(Text),
461459 TextBox, DT_WORDBREAK or DT_INTERNAL);
462460```
463461
464462### Dibujar texto con bordes afilados (no suavizados)
465463
466464   Some widgetsets support this via
467465
468466``` pascal
469467 Canvas.Font.Quality:=fqNonAntialiased
470468```
471469
472470   Algunos motores gráficos como el gtk2 no soportan esto y pintan siempre suavizando. Aquí tenemos un procedimiento simple para dibujar texto con bordes afilados en GTK2. No tiene en cuenta todos los casos, pero nos da una idea:
473471
474472``` pascal
475473procedure PaintAliased(Canvas: TCanvas; x,y: integer; const TheText: string);
476474 var
477475 w,h: integer;
478476 IntfImg: TLazIntfImage;
479477 Img: TBitmap;
480478 dy: Integer;
481479 dx: Integer;
482480 col: TFPColor;
483481 FontColor: TColor;
484482 c: TColor;
485483 begin
486484 w:=0;
487485 h:=0;
488486 Canvas.GetTextSize(TheText,w,h);
489487 if (w<=0) or (h<=0) then exit;
490488 Img:=TBitmap.Create;
491489 IntfImg:=nil;
492490 try
493491 // paint text to a bitmap
494492 Img.Masked:=true;
495493 Img.SetSize(w,h);
496494 Img.Canvas.Brush.Style:=bsSolid;
497495 Img.Canvas.Brush.Color:=clWhite;
498496 Img.Canvas.FillRect(0,0,w,h);
499497 Img.Canvas.Font:=Canvas.Font;
500498 Img.Canvas.TextOut(0,0,TheText);
501499 // get memory image
502500 IntfImg:=Img.CreateIntfImage;
503501 // replace gray pixels
504502 FontColor:=ColorToRGB(Canvas.Font.Color);
505503 for dy:=0 to h-1 do begin
506504 for dx:=0 to w-1 do begin
507505 col:=IntfImg.Colors[dx,dy];
508506 c:=FPColorToTColor(col);
509507 if c<>FontColor then
510508 IntfImg.Colors[dx,dy]:=colTransparent;
511509 end;
512510 end;
513511 // create bitmap
514512 Img.LoadFromIntfImage(IntfImg);
515513 // paint
516514 Canvas.Draw(x,y,Img);
517515 finally
518516 IntfImg.Free;
519517 Img.Free;
520518 end;
521519 end;
522520```
523521
524522## Pintando sin la LCL
525523
526524   Podemos dibujar sin usar la LCL. Por ejemplo, un programa que se ejecuta en un servidor web generando gráficos trabajará sin necesidad de ninguna librería visual. Para ello puede utilizar *FPImage* (alias *fcl-image*) una muy genérica librería de imagen y dibujo completamente escrita en Pascal. De hecho, la LCL utiliza FPImage mucho y realiza la función de dibujo a través de llamadas al motor gráfico IGU (winapi, gtk, carbon, ...).
527525
528526   Este es un ejemplo, sobre como crear una imagen de 200x100, con un fondo blanco y algún texto y guardarla como un .png:
529527
530528``` pascal
531529
532530program fontdraw;
533531
534532 {$mode objfpc}{$H+}
535533
536534 uses
537535 Classes, SysUtils, FPimage, FPImgCanv, ftfont, FPWritePNG, FPCanvas;
538536
539537 procedure TestFPImgFont;
540538 var
541539 Img: TFPMemoryImage;
542540 Writer: TFPWriterPNG;
543541 ms: TMemoryStream;
544542 ImgCanvas: TFPImageCanvas;
545543 fs: TFileStream;
546544 AFont: TFreeTypeFont;
547545 begin
548546 Img:=nil;
549547 ImgCanvas:=nil;
550548 Writer:=nil;
551549 ms:=nil;
552550 fs:=nil;
553551 AFont:=nil;
554552 try
555553 // initialize free type font manager
556554 ftfont.InitEngine;
557555 FontMgr.SearchPath:='/usr/share/fonts/truetype/ttf-dejavu/';
558556 AFont:=TFreeTypeFont.Create;
559557
560558 // create an image of width 200, height 100
561559 Img:=TFPMemoryImage.Create(200,100);
562560 Img.UsePalette:=false;
563561 // create the canvas with the drawing operations
564562 ImgCanvas:=TFPImageCanvas.create(Img);
565563
566564 // paint white background
567565 ImgCanvas.Brush.FPColor:=colWhite;
568566 ImgCanvas.Brush.Style:=bsSolid;
569567 ImgCanvas.Rectangle(0,0,Img.Width,Img.Height);
570568
571569 // paint text
572570 ImgCanvas.Font:=AFont;
573571 ImgCanvas.Font.Name:='DejaVuSans';
574572 ImgCanvas.Font.Size:=20;
575573 ImgCanvas.TextOut(10,30,'Test');
576574
577575 // write image as png to memory stream
578576 Writer:=TFPWriterPNG.create;
579577 ms:=TMemoryStream.Create;
580578 writer.ImageWrite(ms,Img);
581579 // write memory stream to file
582580 ms.Position:=0;
583581 fs:=TFileStream.Create('testfont.png',fmCreate);
584582 fs.CopyFrom(ms,ms.Size);
585583 finally
586584 AFont.Free;
587585 ms.Free;
588586 Writer.Free;
589587 ImgCanvas.Free;
590588 Img.Free;
591589 fs.Free;
592590 end;
593591 end;
594592
595593 begin
596594 TestFPImgFont;
597595 end.
598596```
599597
600598- [[Basic Pascal Tutorial]] - [Tao Yue's](http://www.taoyue.com/) [Pascal Tutorial](http://www.taoyue.com/tutorials/pascal/)
601599- [[Free Pascal videos|Free Pascal video tutorials]]
602600
603601---
604602*From the Free Pascal wiki, page "Developing with Graphics/es", as it stood on 2020-03-29 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history