Sign in Join
Wiki copytemporary

fcl-image: what changed

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

OldNewLine
1+**English (en)** | [[fcl-image/ja|**日本語 (ja)**]]
2+
13## Introduction
24
3-FCL-Image started life as "fpimage", pretty much as an attempt to implement a generally portable TImage like class, without the deep win32 and VCL ties.
5+FCL-Image started life as "fpimage", pretty much as an attempt to implement a generally portable TImage like class, without the deep win32 and VCL ties.
46
57## Current file list
68
7-The central units are *[[doc:fcl/fpimage|fpimage]]* and *[[doc:fcl/fpcanvas|fpcanvas]]* and these are further enhanced by OOP derivation.
9+The central units are _[fpimage](<http://lazarus-ccr.sourceforge.net/docs/fcl/fpimage> "doc:fcl/fpimage")_ and _[fpcanvas](<http://lazarus-ccr.sourceforge.net/docs/fcl/fpcanvas> "doc:fcl/fpcanvas")_ and these are further enhanced by OOP derivation.
810
9-- **bmpcomn** A few structures and constants for the BMP fileformat
10-- **clipping** Some utility routines that help with clipping and intersecting of rects.
11-- **ellipses** Drawing of ellipses and arcs, and filling ellipses and pies.
12- - TEllipseInfo
13-- **extinterpolation** interpolation filters for TFPCanvas.StretchDraw (
14- - TBlackmanInterpolation
15- - TBlackmanSincInterpolation
16- - TBlackmanBesselInterpolation
17- - TGaussianInterpolation
18- - TBoxInterpolation
19- - THermiteInterpolation
20- - TLanczosInterpolation
21- - TQuadraticInterpolation
22- - TCubicInterpolation
23- - TCatromInterpolation
24- - TBilineairInterpolation
25- - THanningInterpolation
26- - THammingInterpolation
27-- **fpcanvas** Generic Canvas classes.
28- - [[doc:fcl/fpcanvas/tfpcanvasexception.html|TFPCanvasException]]
29- - TFPPenException
30- - TFPBrushException
31- - TFPFontException
32- - TFPCustomCanvas
33- - TFPCanvasHelper
34- - TFPCustomFont
35- - TFPCustomFontClass
36- - TFPCustomPen
37- - TFPCustomPenClass
38- - TFPCustomBrush
39- - TFPCustomBrushClass
40- - TFPCustomInterpolation
41- - TFPBaseInterpolation
42- - [[doc:fcl/fpcanvas/tmitchelinterpolation.html|TMitchelInterpolation]]
43- - TFPCustomCanvas
44- - TFPCustomDrawFont
45- - TFPEmptyFont
46- - TFPCustomDrawPen
47- - TFPEmptyPen
48- - TFPCustomDrawBrush
49- - TFPEmptyBrush
50-- **fpcolhash** an implementation of a color hash table.
51- - TFPColorHashException
52- - TFPColorHashTable
53-- **fpditherer** contains classes used to dither images.
54- - FPDithererException
55- - TFPBaseDitherer
56- - TFPFloydSteinbergDitherer
57-- **fpimage** fpImage base definitions and classes
58- - TFPCustomImageReader
59- - TFPCustomImageWriter
60- - TFPCustomImage
61- - FPImageException
62- - TFPPalette
63- - TFPCustomImage
64- - TFPMemoryImage
65- - TFPCustomImageHandler
66- - TFPCustomImageReader
67- - TFPCustomImageWriter
68- - TIHData
69- - TImageHandlersManager
70-- **fpimgcanv** Image Canvas - canvas which draws on an image.
71- - TFPImageCanvas
72-- **fpimgcmn** Image Common: small procedural Helpers (swap,crc)
73-- **fppixlcanv**
74- - TPixelCanvas
75-- **fpquantizer** classes used to quantize images. See [1](http://lazarus.freepascal.org/index.php/topic,13468.0)
76-- **freetype** Encapsulating classes over freetype
77-- **freetypeh** Freetype header translation
78-- **ftfont** More freetype related font classes
79-- **pcxcomn** PCX fileformat records and types
80-- **pixtools** Pixel drawing routines.
81-- **pngcomn** PNG fileformat records and types
82-- **polygonfilltools** Routines for filling polygons (FPC 3.3.1 or newer)
83-- **pscanvas** TPostScriptCanvas implementation.
84-- **targacmn** Targa fileformat records and types
11+ * **bmpcomn** A few structures and constants for the BMP fileformat
12+ * **clipping** Some utility routines that help with clipping and intersecting of rects.
13+ * **ellipses** Drawing of ellipses and arcs, and filling ellipses and pies.
14+ * TEllipseInfo
15+ * **extinterpolation** interpolation filters for TFPCanvas.StretchDraw (
16+ * TBlackmanInterpolation
17+ * TBlackmanSincInterpolation
18+ * TBlackmanBesselInterpolation
19+ * TGaussianInterpolation
20+ * TBoxInterpolation
21+ * THermiteInterpolation
22+ * TLanczosInterpolation
23+ * TQuadraticInterpolation
24+ * TCubicInterpolation
25+ * TCatromInterpolation
26+ * TBilineairInterpolation
27+ * THanningInterpolation
28+ * THammingInterpolation
29+ * **fpcanvas** Generic Canvas classes.
30+ * [TFPCanvasException](<http://lazarus-ccr.sourceforge.net/docs/fcl/fpcanvas/tfpcanvasexception.html> "doc:fcl/fpcanvas/tfpcanvasexception.html")
31+ * TFPPenException
32+ * TFPBrushException
33+ * TFPFontException
34+ * TFPCustomCanvas
35+ * TFPCanvasHelper
36+ * TFPCustomFont
37+ * TFPCustomFontClass
38+ * TFPCustomPen
39+ * TFPCustomPenClass
40+ * TFPCustomBrush
41+ * TFPCustomBrushClass
42+ * TFPCustomInterpolation
43+ * TFPBaseInterpolation
44+ * [TMitchelInterpolation](<http://lazarus-ccr.sourceforge.net/docs/fcl/fpcanvas/tmitchelinterpolation.html> "doc:fcl/fpcanvas/tmitchelinterpolation.html")
45+ * TFPCustomCanvas
46+ * TFPCustomDrawFont
47+ * TFPEmptyFont
48+ * TFPCustomDrawPen
49+ * TFPEmptyPen
50+ * TFPCustomDrawBrush
51+ * TFPEmptyBrush
52+ * **fpcolhash** an implementation of a color hash table.
53+ * TFPColorHashException
54+ * TFPColorHashTable
55+ * **fpditherer** contains classes used to dither images.
56+ * FPDithererException
57+ * TFPBaseDitherer
58+ * TFPFloydSteinbergDitherer
59+ * **fpimage** fpImage base definitions and classes
60+ * TFPCustomImageReader
61+ * TFPCustomImageWriter
62+ * TFPCustomImage
63+ * FPImageException
64+ * TFPPalette
65+ * TFPCustomImage
66+ * TFPMemoryImage
67+ * TFPCustomImageHandler
68+ * TFPCustomImageReader
69+ * TFPCustomImageWriter
70+ * TIHData
71+ * TImageHandlersManager
72+ * **fpimgcanv** Image Canvas - canvas which draws on an image.
73+ * TFPImageCanvas
74+ * **fpimgcmn** Image Common: small procedural Helpers (swap,crc)
75+ * **fppixlcanv**
76+ * TPixelCanvas
77+ * **fpquantizer** classes used to quantize images. See [[1]](<http://lazarus.freepascal.org/index.php/topic,13468.0>)
78+ * **freetype** Encapsulating classes over freetype
79+ * **freetypeh** Freetype header translation
80+ * **ftfont** More freetype related font classes
81+ * **pcxcomn** PCX fileformat records and types
82+ * **pixtools** Pixel drawing routines.
83+ * **pngcomn** PNG fileformat records and types
84+ * **polygonfilltools** Routines for filling polygons (FPC 3.3.1 or newer)
85+ * **pscanvas** TPostScriptCanvas implementation.
86+ * **targacmn** Targa fileformat records and types
8587
86-**Readers and writers for various image formats** reside in dedicated units:
88+**Readers and writers for various image formats** reside in dedicated units:
8789
88-- **fpreadbmp**, **fpwritebmp**: Reader and writer units for .bmp files
89-- **fpreadjpeg**, **fpwritejpeg**: Reader and writer units for .jpeg/.jpg files
90-- **fpreadpcx**, **fprwritepcs**: Reader and writer units for .pcx files
91-- **fpreadpng**, **fpwritepng**: Reader and writer units for .png files
92-- **fpreadpnm**, **fpwritepnm**: Reader and writer units for .pnm files
93-- **fpreadtga**, **fpwritetga**: Reader and writer units for .tga files
94-- **fpreadtiff**, **fpwritetiff**: Reader and writer units for .tiff/.tif files
95-- **fpreadxpm**, **fpwritexpm**: Reader and writer units for .xpm files
90+ * **fpreadbmp** , **fpwritebmp** : Reader and writer units for .bmp files
91+ * **fpreadjpeg** , **fpwritejpeg** : Reader and writer units for .jpeg/.jpg files
92+ * **fpreadpcx** , **fprwritepcs** : Reader and writer units for .pcx files
93+ * **fpreadpng** , **fpwritepng** : Reader and writer units for .png files
94+ * **fpreadpnm** , **fpwritepnm** : Reader and writer units for .pnm files
95+ * **fpreadtga** , **fpwritetga** : Reader and writer units for .tga files
96+ * **fpreadtiff** , **fpwritetiff** : Reader and writer units for .tiff/.tif files
97+ * **fpreadxpm** , **fpwritexpm** : Reader and writer units for .xpm files
9698
9799**INC files uses in fpcanvas**
98100
99-- fpbrush
100-- fpcanvas
101-- fpcdrawh
102-- fpfont
103-- fphelper
104-- fpinterpolation
105-- fppen
101+ * fpbrush
102+ * fpcanvas
103+ * fpcdrawh
104+ * fpfont
105+ * fphelper
106+ * fpinterpolation
107+ * fppen
106108
107-INC files uses in fpmake
109+INC files uses in fpmake
108110
109-- fpcolors
110-- fpimage
111-- fphandler
112-- fpcolcnv
113-- fppalette
111+ * fpcolors
112+ * fpimage
113+ * fphandler
114+ * fpcolcnv
115+ * fppalette
114116
115-Demos
117+Demos
116118
117-- drawing
118-- imgconv
119+ * drawing
120+ * imgconv
119121
120122## Known Issues and limitations
121123
122-- fcl-image is written for maximal portability and maintainability and is quite slow. The main storage type is 16-bit RGBA, storing always 64-bit per pixel, and a function is called to get each pixel.
123-- pngwriter doesn't implement automatic detection of filters, and thus is always "filter none"
124-- most writers don't autodetect what format to save. You must correctly set the relevant writer options ( see also [bug 17621](http://bugs.freepascal.org/view.php?id=17621)).
125-- the color format can be counter intuitive, read [this thread](http://www.mail-archive.com/fpc-devel@lists.freepascal.org/msg16506.html)
126-- png only implements basic chunk types (idat,trns,plte,ihdr and iend). It e.g. can't handle chunks like pHYs,iCCP,gAMA,cHRM yet. ([bug 19209](http://bugs.freepascal.org/view.php?id=19209)).
124+ * fcl-image is written for maximal portability and maintainability and is quite slow. The main storage type is 16-bit RGBA, storing always 64-bit per pixel, and a function is called to get each pixel.
125+ * pngwriter doesn't implement automatic detection of filters, and thus is always "filter none"
126+ * most writers don't autodetect what format to save. You must correctly set the relevant writer options ( see also [bug 17621](<http://bugs.freepascal.org/view.php?id=17621>)).
127+ * the color format can be counter intuitive, read [this thread](<http://www.mail-archive.com/fpc-devel@lists.freepascal.org/msg16506.html>)
128+ * png only implements basic chunk types (idat,trns,plte,ihdr and iend). It e.g. can't handle chunks like pHYs,iCCP,gAMA,cHRM yet. ([bug 19209](<http://bugs.freepascal.org/view.php?id=19209>)).
127129
128130## Image formats
129131
130-Here is a table with the correct class to use for each image format, as well as comparing to the LCL.
131-
132-| Format | fcl-image reader unit | fcl-image writer unit | LCL class |
133-|----|----|----|----|
134-| Windows Bitmap. A very simple format, usually used without compression and without transparency, but it may also have them, although many applications don't support those extra features. (*.bmp) | fpreadbmp | fpwritebmp | TBitmap |
135-| A popular format for websites. It supports up to 8 bits per pixels, which are 256 distinct colors chosen from the 24-bit RGB color space. This limitation makes it unsuitable for complex images, but useful for simple graphics. The image is compressed without loss in quality and the format also supports animations. (*.gif) | fpreadgif\|\|- | TGIFImage | |
136-| The most popular format for websites, and an ISO standard since 1994. The format compressed the image but generates a small loss of quality. (*.jpeg, *.jpg) | fpreadjpeg | fpwritejpeg | TJpegImage |
137-| A format widely used in DOS applications, but now less popular. (*.pcx) | fpreadpcx | fpwritepcx\|\|- | |
138-| Portable Network Graphics. A popular format for it's efficient compression without quality loss. (*.png) | fpreadpng | fpwritepng | TPortableNetworkGraphic |
139-| \|Supports the formats Portable BitMaps (*.pbm), Portable GrayMaps (*.pgm) and Portable PixMaps (*.ppm) | fpreadpnm | fpwritepnm | TPortableAnyMapGraphic |
140-| The default file format for Adobe Photoshop® (*.psd) | fpreadpsd\|\|-\|\|- | | |
141-| Called either Truevision TGA File Format or TARGA File Format, this is a compressed format commonly used in games. (*.tga, *.tpic) | fpreadtga | fpwritetga\|\|- | |
142-| Tagged Image File Format (TIFF), originally created to have a common image format for scanners. (*.tiff, *.tif). Controlled by Adobe® | fpreadtiff | fpwritetiff | TTiffImage |
143-| X PixMap, an image format used by the X Window System which stores the data in ASCII text. Is also used as an icon format in UNIX applications. (*.xpm) | fpreadxpm | fpwritexpm | TPixmap |
144-| X Window Dump file format. Used by the program xwd which generates screenshots in the X Window System. (*.xwd) | fpreadxwd\|\|-\|\|- | | |
145-| Windows Icon. Is a list of small bitmaps in various color depths and sizes, with transparency support and no compression. (*.ico)\|\|-\|\|- | TIcon | | |
146-| Windows Cursor. Exactly the same format as the Windows Icon, but with an extra field in the header for the cursor hotspot. (*.cur)\|\|-\|\|- | TCursorImage | | |
147-| macOS icon. List of small images in various sizes. (*.icns)\|\|-\|\|- | TIcnsIcon | | |
132+Here is a table with the correct class to use for each image format, as well as comparing to the LCL.
148133
134+Format | fcl-image reader unit | fcl-image writer unit | LCL class
135+---|---|---|---
136+Windows Bitmap. A very simple format, usually used without compression and without transparency, but it may also have them, although many applications don't support those extra features. (*.bmp) | fpreadbmp | fpwritebmp | TBitmap
137+A popular format for websites. It supports up to 8 bits per pixels, which are 256 distinct colors chosen from the 24-bit RGB color space. This limitation makes it unsuitable for complex images, but useful for simple graphics. The image is compressed without loss in quality and the format also supports animations. (*.gif) | fpreadgif | - | TGIFImage
138+The most popular format for websites, and an ISO standard since 1994. The format compressed the image but generates a small loss of quality. (*.jpeg, *.jpg) | fpreadjpeg | fpwritejpeg | TJpegImage
139+A format widely used in DOS applications, but now less popular. (*.pcx) | fpreadpcx | fpwritepcx | \-
140+Portable Network Graphics. A popular format for it's efficient compression without quality loss. (*.png) | fpreadpng | fpwritepng | TPortableNetworkGraphic
141+Supports the formats Portable BitMaps (*.pbm), Portable GrayMaps (*.pgm) and Portable PixMaps (*.ppm) | fpreadpnm | fpwritepnm | TPortableAnyMapGraphic
142+The default file format for Adobe Photoshop® (*.psd) | fpreadpsd | - | \-
143+Called either Truevision TGA File Format or TARGA File Format, this is a compressed format commonly used in games. (*.tga, *.tpic) | fpreadtga | fpwritetga | \-
144+Tagged Image File Format (TIFF), originally created to have a common image format for scanners. (*.tiff, *.tif). Controlled by Adobe® | fpreadtiff | fpwritetiff | TTiffImage
145+X PixMap, an image format used by the X Window System which stores the data in ASCII text. Is also used as an icon format in UNIX applications. (*.xpm) | fpreadxpm | fpwritexpm | TPixmap
146+X Window Dump file format. Used by the program xwd which generates screenshots in the X Window System. (*.xwd) | fpreadxwd | - | \-
147+Windows Icon. Is a list of small bitmaps in various color depths and sizes, with transparency support and no compression. (*.ico) | - | - | TIcon
148+Windows Cursor. Exactly the same format as the Windows Icon, but with an extra field in the header for the cursor hotspot. (*.cur) | - | - | TCursorImage
149+macOS icon. List of small images in various sizes. (*.icns) | - | - | TIcnsIcon
150+
149151### Tiff
150152
151-Working features of the reader:
153+Working features of the reader:
152154
153-- Black and white/lineart/1 bit (FPC trunk only, not in FPC 2.6.x)
154-- Grayscale 8,16bit (optional alpha),
155-- RGB 8,16bit (optional alpha),
156-- Orientation, except for rotated orientation
157-- compression: packbits, LZW, deflate
158-- endian
159-- multiple images/multipage
160-- strips and tiles
161-- Sets properties in the image Extras properties, which is used by the writer, so that reading/writing keeps many common tags like Artist, Copyright, DateAndTime, HostComputer, ImageDescription, Maker, Model, Software, DocumentName, XResolution, YResolution, Orientation, bit depts, page name, isThumbnail.
155+ * Black and white/lineart/1 bit (FPC trunk only, not in FPC 2.6.x)
156+ * Grayscale 8,16bit (optional alpha),
157+ * RGB 8,16bit (optional alpha),
158+ * Orientation, except for rotated orientation
159+ * compression: packbits, LZW, deflate
160+ * endian
161+ * multiple images/multipage
162+ * strips and tiles
163+ * Sets properties in the image Extras properties, which is used by the writer, so that reading/writing keeps many common tags like Artist, Copyright, DateAndTime, HostComputer, ImageDescription, Maker, Model, Software, DocumentName, XResolution, YResolution, Orientation, bit depts, page name, isThumbnail.
162164
163-Here is an incomplete list of open / not yet implemented features of the reader:
165+Here is an incomplete list of open / not yet implemented features of the reader:
164166
165-- Compression: jpeg, CCITT Group 3, CCITT Group 4
166-- PlanarConfiguration 2
167-- ColorMap
168-- separate mask
169-- fillorder - not needed by baseline tiff reader
170-- bigtiff 64bit offsets
171-- XMP tag 700
172-- ICC profile tag 34675
173-- Orientation with rotation
167+ * Compression: jpeg, CCITT Group 3, CCITT Group 4
168+ * PlanarConfiguration 2
169+ * ColorMap
170+ * separate mask
171+ * fillorder - not needed by baseline tiff reader
172+ * bigtiff 64bit offsets
173+ * XMP tag 700
174+ * ICC profile tag 34675
175+ * Orientation with rotation
174176
175-Working features of the writer:
177+Working features of the writer:
176178
177-- Grayscale 8,16bit (optional alpha)
178-- RGB 8,16bit (optional alpha)
179-- Orientation except rotated
180-- multiple images, pages
181-- thumbnail
182-- Compression: deflate
179+ * Grayscale 8,16bit (optional alpha)
180+ * RGB 8,16bit (optional alpha)
181+ * Orientation except rotated
182+ * multiple images, pages
183+ * thumbnail
184+ * Compression: deflate
183185
184-Here is an incomplete list of open / not yet implemented features of the writer:
186+Here is an incomplete list of open / not yet implemented features of the writer:
185187
186-- Compression: LZW, packbits, jpeg, CCIT Group 3,CCIT Group 4,...
187-- Planar
188-- ColorMap
189-- separate mask
190-- fillorder - not needed by baseline tiff reader
191-- bigtiff 64bit offsets
192-- endian - currently using system endianess
193-- Orientation with rotation
188+ * Compression: LZW, packbits, jpeg, CCIT Group 3,CCIT Group 4,...
189+ * Planar
190+ * ColorMap
191+ * separate mask
192+ * fillorder - not needed by baseline tiff reader
193+ * bigtiff 64bit offsets
194+ * endian - currently using system endianess
195+ * Orientation with rotation
194196
195197## Walk-through
196198
197199### Basic Canvas Setup
198200
199-You'll need a few things to start up. A canvas, image, and writer. The writer is to write images like PNG. The sample below will give you a 100x100 black png.
200-
201-``` Pascal
201+You'll need a few things to start up. A canvas, image, and writer. The writer is to write images like PNG. The sample below will give you a 100x100 black png.
202+```
202203{$mode objfpc}{$h+}
203-program demo;
204-
205-uses classes, sysutils,
206- FPImage, FPCanvas, FPImgCanv,
207- FPWritePNG;
208-
209-var canvas : TFPCustomCanvas;
210- image : TFPCustomImage;
211- writer : TFPCustomImageWriter;
212-begin
213- { Create an image 100x100 pixels}
214- image := TFPMemoryImage.Create (100,100);
215-
216- { Attach the image to the canvas }
217- Canvas := TFPImageCanvas.Create (image);
218-
219- { Create the writer }
220- Writer := TFPWriterPNG.Create;
221-
222- { Save to file }
223- image.SaveToFile ('DrawTest.png', writer);
224-
225- { Clean up! }
226- Canvas.Free;
227- image.Free;
228- writer.Free;
229-end.
204+ program demo;
205+
206+ uses classes, sysutils,
207+ FPImage, FPCanvas, FPImgCanv,
208+ FPWritePNG;
209+
210+ var canvas : TFPCustomCanvas;
211+ image : TFPCustomImage;
212+ writer : TFPCustomImageWriter;
213+ begin
214+ { Create an image 100x100 pixels}
215+ image := TFPMemoryImage.Create (100,100);
216+
217+ { Attach the image to the canvas }
218+ Canvas := TFPImageCanvas.Create (image);
219+
220+ { Create the writer }
221+ Writer := TFPWriterPNG.Create;
222+
223+ { Save to file }
224+ image.SaveToFile ('DrawTest.png', writer);
225+
226+ { Clean up! }
227+ Canvas.Free;
228+ image.Free;
229+ writer.Free;
230+ end.
230231```
231232
232233### Drawing a Circle
233234
234-Drawing a circle requires a bit more then just giving a width. You'll need to setup the pen style, mode, width, and color to do this. FCL-Image comes with a few pen modes and styles, it will really be up to you to decide which you'll need. Its best for now to try with a few modes and styles to get a better understanding of what FCL-Image can do.
235-
236-``` Pascal
235+Drawing a circle requires a bit more then just giving a width. You'll need to setup the pen style, mode, width, and color to do this. FCL-Image comes with a few pen modes and styles, it will really be up to you to decide which you'll need. Its best for now to try with a few modes and styles to get a better understanding of what FCL-Image can do.
236+```
237237{$mode objfpc}{$h+}
238-program demo;
239-
240-uses classes, sysutils,
241- FPImage, FPCanvas, FPImgCanv,
242- FPWritePNG;
243-
244-var canvas : TFPcustomCanvas;
245- image : TFPCustomImage;
246- writer : TFPCustomImageWriter;
247- {
248- Colors range from 0 to 65535 in each primary color.
249- They can also show as hexadecimal:
250- $FFFF = 65535, $0000 = 0
251- }
252- passionRed: TFPColor = (Red: 65535; Green: 0; Blue: 0; Alpha: 65535);
253-begin
254- image := TFPMemoryImage.Create (100,100);
255- Canvas := TFPImageCanvas.Create (image);
256- Writer := TFPWriterPNG.Create;
257-
258- { Set the pen styles }
259- with canvas do
260- begin
261- pen.mode := pmCopy;
262- pen.style := psSolid;
263- pen.width := 1;
264- pen.FPColor := passionRed;
265- end;
266-
267- { Draw a circle }
268- canvas.Ellipse (10,10, 90,90);
269-
270- { Save to file }
271- image.SaveToFile ('DrawTest.png', writer);
272-
273- { Clean up! }
274- Canvas.Free;
275- image.Free;
276- writer.Free;
277-end.
238+ program demo;
239+
240+ uses classes, sysutils,
241+ FPImage, FPCanvas, FPImgCanv,
242+ FPWritePNG;
243+
244+ var canvas : TFPcustomCanvas;
245+ image : TFPCustomImage;
246+ writer : TFPCustomImageWriter;
247+ {
248+ Colors range from 0 to 65535 in each primary color.
249+ They can also show as hexadecimal:
250+ $FFFF = 65535, $0000 = 0
251+ }
252+ passionRed: TFPColor = (Red: 65535; Green: 0; Blue: 0; Alpha: 65535);
253+ begin
254+ image := TFPMemoryImage.Create (100,100);
255+ Canvas := TFPImageCanvas.Create (image);
256+ Writer := TFPWriterPNG.Create;
257+
258+ { Set the pen styles }
259+ with canvas do
260+ begin
261+ pen.mode := pmCopy;
262+ pen.style := psSolid;
263+ pen.width := 1;
264+ pen.FPColor := passionRed;
265+ end;
266+
267+ { Draw a circle }
268+ canvas.Ellipse (10,10, 90,90);
269+
270+ { Save to file }
271+ image.SaveToFile ('DrawTest.png', writer);
272+
273+ { Clean up! }
274+ Canvas.Free;
275+ image.Free;
276+ writer.Free;
277+ end.
278278```
279279
280280### Drawing Alpha-Blended Shapes
281281
282-Alpha-blending means: When something is painted over an existing image the old pixels are allowed to shine through the new drawing. The amount of mixing is given by the `Alpha` value of the new color which is specified as fourth word parameter of the brush's FPColor. `Alpha=0` means: the new painting is fully transparent, `Alpha=$FFFF` means: the new drawing is fully opaque.
283-
284-In order to activate alpha-blending the `DrawingMode` of the canvas must be switched to `dmAlphaBlend`, and the brush color of a new shape must be extended by its `Alpha` value.
282+Alpha-blending means: When something is painted over an existing image the old pixels are allowed to shine through the new drawing. The amount of mixing is given by the `Alpha` value of the new color which is specified as fourth word parameter of the brush's FPColor. `Alpha=0` means: the new painting is fully transparent, `Alpha=$FFFF` means: the new drawing is fully opaque.
285283
286-``` pascal
284+In order to activate alpha-blending the `DrawingMode` of the canvas must be switched to `dmAlphaBlend`, and the brush color of a new shape must be extended by its `Alpha` value.
285+```
287286program alphablend;
288-uses
289- FPImage, FPImgCanv, FPCanvas, FPWritePNG;
290-var
291- img: TFPMemoryImage;
292- canvas: TFPImageCanvas;
293-begin
294- img := TFPMemoryImage.Create(200, 200);
295- canvas := TFPImageCanvas.Create(img);
296- try
297- canvas.DrawingMode := dmAlphaBlend; // This activates the alpha-blend mode
298-
299- // Background
300- canvas.Pen.Style := psClear;
301- canvas.Brush.FPColor := colWhite;
302- canvas.FillRect(0, 0, img.Width, img.Height);
303-
304- // Yellow opaque rectangle
305- canvas.Brush.FPColor := FPColor($FFFF, $FFFF, 0);
306- canvas.Rectangle(10, 10, 190, 100);
307-
308- // Overlapping semi-transparent red circle
309- canvas.Brush.FPColor := FPColor($FFFF, 0, 0, $4000);
310- canvas.Ellipse(60, 60, 140, 140);
311-
312- // Overlapping semi-transparent blue circle
313- canvas.Brush.FPColor := FPColor(0, 0, $FFFF, $8000);
314- canvas.Ellipse(0, 100, 100, 200);
315-
316- // Save to image file
317- img.SaveToFile('alphablend.png');
318- finally
319- canvas.Free;
320- img.Free;
321- end;
322-end.
287+ uses
288+ FPImage, FPImgCanv, FPCanvas, FPWritePNG;
289+ var
290+ img: TFPMemoryImage;
291+ canvas: TFPImageCanvas;
292+ begin
293+ img := TFPMemoryImage.Create(200, 200);
294+ canvas := TFPImageCanvas.Create(img);
295+ try
296+ canvas.DrawingMode := dmAlphaBlend; // This activates the alpha-blend mode
297+
298+ // Background
299+ canvas.Pen.Style := psClear;
300+ canvas.Brush.FPColor := colWhite;
301+ canvas.FillRect(0, 0, img.Width, img.Height);
302+
303+ // Yellow opaque rectangle
304+ canvas.Brush.FPColor := FPColor($FFFF, $FFFF, 0);
305+ canvas.Rectangle(10, 10, 190, 100);
306+
307+ // Overlapping semi-transparent red circle
308+ canvas.Brush.FPColor := FPColor($FFFF, 0, 0, $4000);
309+ canvas.Ellipse(60, 60, 140, 140);
310+
311+ // Overlapping semi-transparent blue circle
312+ canvas.Brush.FPColor := FPColor(0, 0, $FFFF, $8000);
313+ canvas.Ellipse(0, 100, 100, 200);
314+
315+ // Save to image file
316+ img.SaveToFile('alphablend.png');
317+ finally
318+ canvas.Free;
319+ img.Free;
320+ end;
321+ end.
323322```
324323
325324### Brush Styles
326325
327-The **brush** defines how a closed area will be filled. There are several predefined styles to determine the fill pattern.
326+The **brush** defines how a closed area will be filled. There are several predefined styles to determine the fill pattern.
328327
329-- `bsSolid` - fills the area with uniform color
330-- `bsClear` - no fill
331-- `bsHorizontal` - draws horizontal lines of width 1 across the shape to be filled
332-- `bsVertical` - vertical lines
333-- `bsFDiagonal` - diagonal lines (45°, \\\\\\)
334-- `bsBDiagonal` - diagonal lines (45°, ///)
335-- `bsCross` - crossed vertical and horizontal lines (+)
336-- `bsDiagCross` - crossed diagonal lines (x)
328+ * `bsSolid` \- fills the area with uniform color
329+ * `bsClear` \- no fill
330+ * `bsHorizontal` \- draws horizontal lines of width 1 across the shape to be filled
331+ * `bsVertical` \- vertical lines
332+ * `bsFDiagonal` \- diagonal lines (45°, \\\\\\)
333+ * `bsBDiagonal` \- diagonal lines (45°, ///)
334+ * `bsCross` \- crossed vertical and horizontal lines (+)
335+ * `bsDiagCross` \- crossed diagonal lines (x)
337336
338-The fill color is given by the `FPColor` property of the `Brush`. The space between the lines of the non-solid patterns is not painted, i.e. is left transparent. If the canvas on which the brush is used descends from `TFPPixelCanvas` (e.g. `TFPImageCanvas` in unit *fpimgcanv*, or `TLazCanvas` in the LazUtils unit *lazcanvas*) the distance between the pattern lines can be adjusted by means of the `Canvas.HashWidth` property (Note that this does not apply to the `TCanvas` introduced by the Lazarus LCL.)
337+The fill color is given by the `FPColor` property of the `Brush`. The space between the lines of the non-solid patterns is not painted, i.e. is left transparent. If the canvas on which the brush is used descends from `TFPPixelCanvas` (e.g. `TFPImageCanvas` in unit _fpimgcanv_ , or `TLazCanvas` in the LazUtils unit _lazcanvas_) the distance between the pattern lines can be adjusted by means of the `Canvas.HashWidth` property (Note that this does not apply to the `TCanvas` introduced by the Lazarus LCL.)
339338
340-Furthermore there are two additional possibilities for user-defined patterns:
339+Furthermore there are two additional possibilities for user-defined patterns:
341340
342-- `bsImage` - tiles the area to be filled with copies of the image provided by the `Brush.Image` which must be a `TFPCustomImage` descendant, e.g. `TFPMemoryImage`. The colors of the image are retained, and its alpha channel is supported. By default the image position refers to the image origin, but if the canvas descends from `TFPPixelCanvas` (e.g. `TFPImageCanvas` in unit *fpimgcanv*, or `TLazCanvas` in the LazUtils unit *lazcanvas*), it can be changed to be relative to the top/left shape bounding box by setting the property `Canvas.RelativeBrushImage` to `true`. Again this does not apply to the LCL `TCanvas` of Lazarus.
343-- `bsPattern` - provides a user-defined pattern in the `Brush.Pattern` property of type `TBrushPattern`. This is a 32-element array of 32-bit integers where every set bit is interpreted as a painted pixel using the `Brush.FPColor`; cleared bits are not painted and thus are transparent.
341+ * `bsImage` \- tiles the area to be filled with copies of the image provided by the `Brush.Image` which must be a `TFPCustomImage` descendant, e.g. `TFPMemoryImage`. The colors of the image are retained, and its alpha channel is supported. By default the image position refers to the image origin, but if the canvas descends from `TFPPixelCanvas` (e.g. `TFPImageCanvas` in unit _fpimgcanv_ , or `TLazCanvas` in the LazUtils unit _lazcanvas_), it can be changed to be relative to the top/left shape bounding box by setting the property `Canvas.RelativeBrushImage` to `true`. Again this does not apply to the LCL `TCanvas` of Lazarus.
342+ * `bsPattern` \- provides a user-defined pattern in the `Brush.Pattern` property of type `TBrushPattern`. This is a 32-element array of 32-bit integers where every set bit is interpreted as a painted pixel using the `Brush.FPColor`; cleared bits are not painted and thus are transparent.
344343
345344**Example**
346345
347-The following mini project fills a rectangle by a user-defined blue checkerboard pattern, and saves the image as a transparent png file: ![](/wiki-images/e/e5/Checkerboard_rectangle.png)
346+The following mini project fills a rectangle by a user-defined blue checkerboard pattern, and saves the image as a transparent png file:
348347
349-``` pascal
348+[![checkerboard rectangle.png](/wiki-images/c/c2/checkerboard_rectangle.png)](</File:checkerboard_rectangle.png>)
349+```
350350program FillTest;
351-uses
352- FPImage, FPCanvas, FPPixlCanv, FPImgCanv, FPWritePNG;
353-const
354- BRUSH_PATTERN: TBrushPattern = (
355- $FF00FF00, $FF00FF00, $FF00FF00, $FF00FF00,
356- $FF00FF00, $FF00FF00, $FF00FF00, $FF00FF00,
357- $00FF00FF, $00FF00FF, $00FF00FF, $00FF00FF,
358- $00FF00FF, $00FF00FF, $00FF00FF, $00FF00FF,
359- $FF00FF00, $FF00FF00, $FF00FF00, $FF00FF00,
360- $FF00FF00, $FF00FF00, $FF00FF00, $FF00FF00,
361- $00FF00FF, $00FF00FF, $00FF00FF, $00FF00FF,
362- $00FF00FF, $00FF00FF, $00FF00FF, $00FF00FF
363- );
364-var
365- image: TFPMemoryImage;
366- canvas: TFPImageCanvas;
367- writer: TFPCustomImageWriter;
368-begin
369- image := TFPMemoryImage.Create(100, 100);
370- try
371- canvas := TFPImageCanvas.Create(image);
372- try
373- // Prepare the brush for the shape interior
374- canvas.Brush.Style := bsPattern;
375- canvas.Brush.FPColor := colBlue;
376- canvas.Brush.Pattern := BRUSH_PATTERN;
377-
378- // Prepare the pen for the shape border
379- canvas.Pen.Style := psSolid;
380- canvas.Pen.Width := 3;
381- canvas.Pen.FPColor := colDkBlue;
382-
383- // Fill shape
384- canvas.Rectangle(10, 10, 90, 90);
385-
386- // Save to file
387- writer := TFPWriterPNG.Create;
351+ uses
352+ FPImage, FPCanvas, FPPixlCanv, FPImgCanv, FPWritePNG;
353+ const
354+ BRUSH_PATTERN: TBrushPattern = (
355+ $FF00FF00, $FF00FF00, $FF00FF00, $FF00FF00,
356+ $FF00FF00, $FF00FF00, $FF00FF00, $FF00FF00,
357+ $00FF00FF, $00FF00FF, $00FF00FF, $00FF00FF,
358+ $00FF00FF, $00FF00FF, $00FF00FF, $00FF00FF,
359+ $FF00FF00, $FF00FF00, $FF00FF00, $FF00FF00,
360+ $FF00FF00, $FF00FF00, $FF00FF00, $FF00FF00,
361+ $00FF00FF, $00FF00FF, $00FF00FF, $00FF00FF,
362+ $00FF00FF, $00FF00FF, $00FF00FF, $00FF00FF
363+ );
364+ var
365+ image: TFPMemoryImage;
366+ canvas: TFPImageCanvas;
367+ writer: TFPCustomImageWriter;
368+ begin
369+ image := TFPMemoryImage.Create(100, 100);
388370 try
389- // Activate alpha channel in saved image
390- TFPWriterPNG(writer).UseAlpha := true;
391- image.SaveToFile('rectangle.png', writer);
371+ canvas := TFPImageCanvas.Create(image);
372+ try
373+ // Prepare the brush for the shape interior
374+ canvas.Brush.Style := bsPattern;
375+ canvas.Brush.FPColor := colBlue;
376+ canvas.Brush.Pattern := BRUSH_PATTERN;
377+
378+ // Prepare the pen for the shape border
379+ canvas.Pen.Style := psSolid;
380+ canvas.Pen.Width := 3;
381+ canvas.Pen.FPColor := colDkBlue;
382+
383+ // Fill shape
384+ canvas.Rectangle(10, 10, 90, 90);
385+
386+ // Save to file
387+ writer := TFPWriterPNG.Create;
388+ try
389+ // Activate alpha channel in saved image
390+ TFPWriterPNG(writer).UseAlpha := true;
391+ image.SaveToFile('rectangle.png', writer);
392+ finally
393+ writer.Free;
394+ end;
395+
396+ finally
397+ canvas.Free;
398+ end;
399+
392400 finally
393- writer.Free;
401+ image.Free;
394402 end;
403+ end.
404+```
395405
396- finally
397- canvas.Free;
398- end;
406+### Drawing a Gradient
399407
400- finally
401- image.Free;
402- end;
403-end.
408+Filling a rectangle by a horizontal or vertical gradient is rather easy - we just draw vertical or horizontal lines with varying colors:
404409```
410+uses
411+ FPImage, FPCanvas, FPImgCanv;
412+
413+ type
414+ TGradientDir = (gdHorizontal, gdVertical);
415+
416+ procedure GradientFill(Canvas: TFPCustomCanvas; ARect: TRect; AStartColor, AEndColor: TFPColor; ADirection: TGradientDir);
417+
418+ function InterpolateColor(x, xmax: Integer): TFPColor;
419+ var
420+ factor1, factor2: Single;
421+ begin
422+ factor2 := x / xmax;
423+ factor1 := 1.0 - factor2;
424+ Result.Red := trunc(AStartColor.Red * factor1 + AEndColor.Red * factor2);
425+ Result.Green := trunc(AStartColor.Green * factor1 + AEndColor.Green * factor2);
426+ Result.Blue := trunc(AStartColor.Blue * factor1 + AEndColor.Blue * factor2);
427+ Result.Alpha := trunc(AStartColor.Alpha * factor1 + AEndColor.Alpha * factor2);
428+ end;
429+
430+ var
431+ x, y, max: Integer;
432+ color: TFPColor;
433+ begin
434+ if ADirection = gdHorizontal then
435+ begin
436+ max := ARect.Right - ARect.Left;
437+ for x := ARect.Left to ARect.Right do
438+ begin
439+ color := InterpolateColor(x - ARect.Left, max);
440+ for y := ARect.Top to ARect.Bottom do
441+ Canvas.DrawPixel(x, y, color);
442+ end;
443+ end else
444+ begin
445+ max := ARect.Bottom - ARect.Top + 1;
446+ for y := ARect.Top to ARect.Bottom do
447+ begin
448+ color := InterpolateColor(y - ARect.Top, max);
449+ for x := ARect.Left to ARect.Right do
450+ Canvas.DrawPixel(x, y, color);
451+ end;
452+ end;
453+ end;
454+```
405455
406456### Pen Modes
407457
408-The pen mode is how the pixel drawn will react to the pixels beneath it. So if its a white pixel and you draw a red pixel over it with the mode of pmXor then you'll get a vibrate blue pixel.
458+The pen mode is how the pixel drawn will react to the pixels beneath it. So if its a white pixel and you draw a red pixel over it with the mode of pmXor then you'll get a vibrate blue pixel.
409459
410-- `pmBlack`
411-- `pmWhite`
412-- `pmNop`
413-- `pmNot`
414-- `pmCopy`
415-- `pmNotCopy`
416-- `pmMergePenNot`
417-- `pmMaskPenNot`
418-- `pmMergeNotPen`
419-- `pmMaskNotPen`
420-- `pmMerge`
421-- `pmNotMerge`
422-- `pmMask`
423-- `pmNotMask`
424-- `pmXor`
425-- `pmNotXor`
460+ * `pmBlack`
461+ * `pmWhite`
462+ * `pmNop`
463+ * `pmNot`
464+ * `pmCopy`
465+ * `pmNotCopy`
466+ * `pmMergePenNot`
467+ * `pmMaskPenNot`
468+ * `pmMergeNotPen`
469+ * `pmMaskNotPen`
470+ * `pmMerge`
471+ * `pmNotMerge`
472+ * `pmMask`
473+ * `pmNotMask`
474+ * `pmXor`
475+ * `pmNotXor`
426476
427477### Pen Styles
428478
429-- `psSolid`
430-- `psDash`
431-- `psDot`
432-- `psDashDot`
433-- `psDashDotDot`
434-- `psinsideFrame`
435-- `psPattern`
436-- `psClear`
479+ * `psSolid`
480+ * `psDash`
481+ * `psDot`
482+ * `psDashDot`
483+ * `psDashDotDot`
484+ * `psinsideFrame`
485+ * `psPattern`
486+ * `psClear`
437487
438488### Drawing modes
439489
440-- `dmOpaque` -- painting over an existing image overwrites the pixels previously written.
441-- `dmAlphaBlend` -- painting over an existing image blends the old and new colors in the ratio of their `Alpha` value.
442-- `dmCustom` -- similar to `dmAlphaBlend`, but a function must be provided which defines how old and new colors are combined (`TFPCanvasCombineColors = function(const color1, color2: TFPColor): TFPColor of object;`).
443-
444-The following code applies the `dmAlphaBlend` `DrawingMode` to draw two semi-transparent circles over an opaque rectangle:
490+ * `dmOpaque` \-- painting over an existing image overwrites the pixels previously written.
491+ * `dmAlphaBlend` \-- painting over an existing image blends the old and new colors in the ratio of their `Alpha` value.
492+ * `dmCustom` \-- similar to `dmAlphaBlend`, but a function must be provided which defines how old and new colors are combined (`TFPCanvasCombineColors = function(const color1, color2: TFPColor): TFPColor of object;`).
445493
446-``` Pascal
494+The following code applies the `dmAlphaBlend` `DrawingMode` to draw two semi-transparent circles over an opaque rectangle:
495+```
447496program alphablend;
448-uses
449- FPImage, FPImgCanv, FPCanvas, FPWritePNG;
450-var
451- img: TFPMemoryImage;
452- canvas: TFPImageCanvas;
453-begin
454- img := TFPMemoryImage.Create(200, 200);
455- canvas := TFPImageCanvas.Create(img);
456- try
457- canvas.DrawingMode := dmAlphaBlend; // This activates the alpha-blend mode
458-
459- // Background
460- canvas.Pen.Style := psClear;
461- canvas.Brush.FPColor := colWhite;
462- canvas.FillRect(0, 0, img.Width, img.Height);
463-
464- // Yellow opaque rectangle
465- canvas.Brush.FPColor := FPColor($FFFF, $FFFF, 0);
466- canvas.Rectangle(10, 10, 190, 100);
467-
468- // Overlapping semi-transparent red circle
469- canvas.Brush.FPColor := FPColor($FFFF, 0, 0, $4000);
470- canvas.Ellipse(60, 60, 140, 140);
471-
472- // Overlapping semi-transparent blue circle
473- canvas.Brush.FPColor := FPColor(0, 0, $FFFF, $8000);
474- canvas.Ellipse(0, 100, 100, 200);
475-
476- img.SaveToFile('alphablend.png');
477- finally
478- canvas.Free;
479- img.Free;
480- end;
481-end.
497+ uses
498+ FPImage, FPImgCanv, FPCanvas, FPWritePNG;
499+ var
500+ img: TFPMemoryImage;
501+ canvas: TFPImageCanvas;
502+ begin
503+ img := TFPMemoryImage.Create(200, 200);
504+ canvas := TFPImageCanvas.Create(img);
505+ try
506+ canvas.DrawingMode := dmAlphaBlend; // This activates the alpha-blend mode
507+
508+ // Background
509+ canvas.Pen.Style := psClear;
510+ canvas.Brush.FPColor := colWhite;
511+ canvas.FillRect(0, 0, img.Width, img.Height);
512+
513+ // Yellow opaque rectangle
514+ canvas.Brush.FPColor := FPColor($FFFF, $FFFF, 0);
515+ canvas.Rectangle(10, 10, 190, 100);
516+
517+ // Overlapping semi-transparent red circle
518+ canvas.Brush.FPColor := FPColor($FFFF, 0, 0, $4000);
519+ canvas.Ellipse(60, 60, 140, 140);
520+
521+ // Overlapping semi-transparent blue circle
522+ canvas.Brush.FPColor := FPColor(0, 0, $FFFF, $8000);
523+ canvas.Ellipse(0, 100, 100, 200);
524+
525+ img.SaveToFile('alphablend.png');
526+ finally
527+ canvas.Free;
528+ img.Free;
529+ end;
530+ end.
482531```
483532
484533### Drawing text
485534
486-Here is an example, how to create a 200x100 image, painting a white background and some text and saving it as .png:
487-
488-``` Pascal
535+Here is an example, how to create a 200x100 image, painting a white background and some text and saving it as .png:
536+```
489537program fontdraw;
490-
491-{$mode objfpc}{$H+}
492-
493-uses
494- Classes, SysUtils, FPimage, FPImgCanv, FTFont, FPWritePNG, FPCanvas;
495-
496-procedure TestFPImgFont;
497-var
498- Img: TFPMemoryImage;
499- Writer: TFPWriterPNG;
500- ms: TMemoryStream;
501- ImgCanvas: TFPImageCanvas;
502- AFont: TFreeTypeFont;
503-begin
504- Img:=nil;
505- ImgCanvas:=nil;
506- Writer:=nil;
507- ms:=nil;
508- AFont:=nil;
509- try
510- // initialize free type font manager
511- FTFont.InitEngine;
512- FontMgr.SearchPath:='/usr/share/fonts/truetype/ttf-dejavu/'; // not needed on Windows
513- AFont:=TFreeTypeFont.Create;
514-
515- // create an image of width 200, height 100
516- Img:=TFPMemoryImage.Create(200,100);
517- Img.UsePalette:=false;
518- // create the canvas with the drawing operations
519- ImgCanvas:=TFPImageCanvas.Create(Img);
520-
521- // paint white background
522- ImgCanvas.Brush.FPColor:=colWhite;
523- ImgCanvas.Brush.Style:=bsSolid;
524- ImgCanvas.Rectangle(0,0,Img.Width-1,Img.Height-1);
525-
526- // paint text
527- ImgCanvas.Font:=AFont;
528- ImgCanvas.Font.Name:='DejaVuSans';
529- ImgCanvas.Font.Size:=20;
530- ImgCanvas.TextOut(10,30,'Test');
531-
532- // write image as png to memory stream
533- Writer:=TFPWriterPNG.create;
534- ms:=TMemoryStream.Create;
535- writer.ImageWrite(ms,Img);
536- // write memory stream to file
537- ms.Position:=0;
538- ms.SaveToFile('testfont.png');
539- finally
540- AFont.Free;
541- ms.Free;
542- Writer.Free;
543- ImgCanvas.Free;
544- Img.Free;
545- end;
546-end;
547-
548-begin
549- TestFPImgFont;
550-end.
538+
539+ {$mode objfpc}{$H+}
540+
541+ uses
542+ Classes, SysUtils, FPimage, FPImgCanv, FTFont, FPWritePNG, FPCanvas;
543+
544+ procedure TestFPImgFont;
545+ var
546+ Img: TFPMemoryImage;
547+ Writer: TFPWriterPNG;
548+ ms: TMemoryStream;
549+ ImgCanvas: TFPImageCanvas;
550+ AFont: TFreeTypeFont;
551+ begin
552+ Img:=nil;
553+ ImgCanvas:=nil;
554+ Writer:=nil;
555+ ms:=nil;
556+ AFont:=nil;
557+ try
558+ // initialize free type font manager
559+ FTFont.InitEngine;
560+ FontMgr.SearchPath:='/usr/share/fonts/truetype/ttf-dejavu/'; // not needed on Windows
561+ AFont:=TFreeTypeFont.Create;
562+
563+ // create an image of width 200, height 100
564+ Img:=TFPMemoryImage.Create(200,100);
565+ Img.UsePalette:=false;
566+ // create the canvas with the drawing operations
567+ ImgCanvas:=TFPImageCanvas.Create(Img);
568+
569+ // paint white background
570+ ImgCanvas.Brush.FPColor:=colWhite;
571+ ImgCanvas.Brush.Style:=bsSolid;
572+ ImgCanvas.Rectangle(0,0,Img.Width-1,Img.Height-1);
573+
574+ // paint text
575+ ImgCanvas.Font:=AFont;
576+ ImgCanvas.Font.Name:='DejaVuSans';
577+ ImgCanvas.Font.Size:=20;
578+ ImgCanvas.TextOut(10,30,'Test');
579+
580+ // write image as png to memory stream
581+ Writer:=TFPWriterPNG.create;
582+ ms:=TMemoryStream.Create;
583+ writer.ImageWrite(ms,Img);
584+ // write memory stream to file
585+ ms.Position:=0;
586+ ms.SaveToFile('testfont.png');
587+ finally
588+ AFont.Free;
589+ ms.Free;
590+ Writer.Free;
591+ ImgCanvas.Free;
592+ Img.Free;
593+ end;
594+ end;
595+
596+ begin
597+ TestFPImgFont;
598+ end.
551599```
552600
553601### Reading an image file
554602
555-It is very easy to read image files with fcl-image, as the example below shows:
556-
557-``` Pascal
603+It is very easy to read image files with fcl-image, as the example below shows:
604+```
558605uses
559- fpreadgif, fpimage;
560-
561-var
562- image: TFPCustomImage;
563- reader: TFPCustomImageReader;
564-begin
565- Image := TFPMemoryImage.Create(10, 10);
566- Reader := TFPReaderGIF.Create;
567- Image.LoadFromFile(AFileName, Reader);
568- // ...
606+ fpreadgif, fpimage;
607+
608+ var
609+ image: TFPCustomImage;
610+ reader: TFPCustomImageReader;
611+ begin
612+ Image := TFPMemoryImage.Create(10, 10);
613+ Reader := TFPReaderGIF.Create;
614+ Image.LoadFromFile(AFileName, Reader);
615+ // ...
569616```
570617
571618### Converting between two raster image formats
572619
573-To convert simply open in one format and save in the desired one, like in this example:
574-
575-``` Pascal
620+To convert simply open in one format and save in the desired one, like in this example:
621+```
576622uses
577- fpreadgif, fpimage, fpwritebmp;
578-
579-var
580- image: TFPCustomImage;
581- reader: TFPCustomImageReader;
582- writer: TFPCustomImageWriter;
583-begin
584- Image := TFPMemoryImage.Create(10, 10);
585- Reader := TFPReaderGIF.Create;
586- Writer := TFPWriterBMP.Create;
587-
588- Image.LoadFromFile(AFileName, Reader);
589- Image.SaveToFile(ADestFileName, Writer);
590- //...
623+ fpreadgif, fpimage, fpwritebmp;
624+
625+ var
626+ image: TFPCustomImage;
627+ reader: TFPCustomImageReader;
628+ writer: TFPCustomImageWriter;
629+ begin
630+ Image := TFPMemoryImage.Create(10, 10);
631+ Reader := TFPReaderGIF.Create;
632+ Writer := TFPWriterBMP.Create;
633+
634+ Image.LoadFromFile(AFileName, Reader);
635+ Image.SaveToFile(ADestFileName, Writer);
636+ //...
591637```
592638
593639### Rescaling a bitmap image
594640
595-In order to rescale a bitmap image to a new size we need an interpolation for calculating the intermediate new pixels. FCL-Image provides several interpolation classes; in all of them neighboring pixels are combined in some specific way to calculate the new pixel. The visual appearance of the result image depends on the type of the interpolation. Generally reducing the image size results in better image qualtity and magnification of the image size.
596-
597-In order to access an interpolation class we need a instance of TFPCustomCanvas. A convenient one is TFPImageCanvas which closely cooperates with a TFPCustomImage.
641+In order to rescale a bitmap image to a new size we need an interpolation for calculating the intermediate new pixels. FCL-Image provides several interpolation classes; in all of them neighboring pixels are combined in some specific way to calculate the new pixel. The visual appearance of the result image depends on the type of the interpolation. Generally reducing the image size results in better image qualtity and magnification of the image size.
598642
599-``` Pascal
643+In order to access an interpolation class we need a instance of TFPCustomCanvas. A convenient one is TFPImageCanvas which closely cooperates with a TFPCustomImage.
644+```
600645program project1;
601-uses
602- FPImage, FPCanvas, FPImgCanv, FPReadJPEG, FPWriteJPEG;
603-const
604- FILE_NAME = 'cheetah.jpg';
605- MAX_SIZE = 512;
606-var
607- srcImg, destImg: TFPMemoryImage;
608- canvas: TFPImageCanvas;
609- scaleFactor: Double;
610-begin
611- // Create and load the source image
612- srcImg := TFPMemoryImage.Create(0, 0);
613- srcImg.LoadFromFile(FILE_NAME);
614-
615- // Calculate the image scaling factor
616- if srcImg.Width > srcImg.Height then
617- scaleFactor := MAX_SIZE / srcImg.Width
618- else
619- scaleFactor := MAX_SIZE / srcImg.Height;
620-
621- // Create the destination image in the requested size
622- destimg := TFPMemoryImage.Create(round(srcImg.Width*scaleFactor), round(srcImg.Height*scaleFactor));
623-
624- // Create a canvas for the destination image ...
625- canvas := TFPImageCanvas.Create(destImg);
626-
627- // ... and an interpolation
628- canvas.Interpolation := TFPBaseInterpolation.Create;
629-
630- // Use the interpolation to stretch the source image to the new size
631- canvas.StretchDraw(0, 0, destImg.Width, destImg.Height, srcImg);
632-
633- // Save destination image to file
634- destImg.SaveToFile('resized.jpg');
635-
636- // Clean up
637- canvas.Interpolation.Free;
638- canvas.Free;
639- destImg.Free;
640- srcImg.Free;
641-end.
646+ uses
647+ FPImage, FPCanvas, FPImgCanv, FPReadJPEG, FPWriteJPEG;
648+ const
649+ FILE_NAME = 'cheetah.jpg';
650+ MAX_SIZE = 512;
651+ var
652+ srcImg, destImg: TFPMemoryImage;
653+ canvas: TFPImageCanvas;
654+ scaleFactor: Double;
655+ begin
656+ // Create and load the source image
657+ srcImg := TFPMemoryImage.Create(0, 0);
658+ srcImg.LoadFromFile(FILE_NAME);
659+
660+ // Calculate the image scaling factor
661+ if srcImg.Width > srcImg.Height then
662+ scaleFactor := MAX_SIZE / srcImg.Width
663+ else
664+ scaleFactor := MAX_SIZE / srcImg.Height;
665+
666+ // Create the destination image in the requested size
667+ destimg := TFPMemoryImage.Create(round(srcImg.Width*scaleFactor), round(srcImg.Height*scaleFactor));
668+
669+ // Create a canvas for the destination image ...
670+ canvas := TFPImageCanvas.Create(destImg);
671+
672+ // ... and an interpolation
673+ canvas.Interpolation := TFPBaseInterpolation.Create;
674+
675+ // Use the interpolation to stretch the source image to the new size
676+ canvas.StretchDraw(0, 0, destImg.Width, destImg.Height, srcImg);
677+
678+ // Save destination image to file
679+ destImg.SaveToFile('resized.jpg');
680+
681+ // Clean up
682+ canvas.Interpolation.Free;
683+ canvas.Free;
684+ destImg.Free;
685+ srcImg.Free;
686+ end.
642687```
643688
644689### Rotating a bitmap image by an arbitrary angle
645690
646-Using the `RotatePoint()` and `RotateRect()` functions in the Lazarus unit `GraphMath` it is rather easy to rotate the pixels in a bitmap by an arbitrary angle. `RotateRect()` is needed to calculate the size of the rotated image, and `RotatePoint` is used to calculate back to the unrotated pixel for each point in the rotated image.
647-
648-``` Pascal
691+Using the `RotatePoint()` and `RotateRect()` functions in the Lazarus unit `GraphMath` it is rather easy to rotate the pixels in a bitmap by an arbitrary angle. `RotateRect()` is needed to calculate the size of the rotated image, and `RotatePoint` is used to calculate back to the unrotated pixel for each point in the rotated image.
692+```
649693uses
650- Types, Math, FPImage, GraphMath;
651-
652-function CreateRotatedImage(AImage: TFPMemoryImage; Angle: Double): TFPMemoryImage; // Angle is in radians
653-var
654- R: TRect;
655- x, y: Integer;
656- C, P: TPoint;
657- delta: TPoint;
658-begin
659- // Calculate bounds of the rotated image
660- R := RotateRect(AImage.Width, AImage.Height, Angle);
661- OffsetRect(R, -R.Left, -R.Top);
662-
663- // Calculate center of rotated image
664- C := Point((R.Left + R.Right) div 2, (R.Top + R.Bottom) div 2);
665-
666- // Create the resulting image.
667- Result := TFPMemoryImage.Create(R.Right - R.Left, R.Bottom - R.Top);
668-
669- // Correction needed to center the rotated pixels
670- delta := Point((AImage.Width - Result.Width) div 2, (AImage.Height - Result.Height) div 2);
671-
672- // Iterate over all pixels in the result image and look up the corresponding
673- // pixels in the unrotated image. Pixels in the rotated image which are outside
674- // the unrotated image are set to be transparent.
675- for y := 0 to Result.Height-1 do
676- for x := 0 to Result.Width-1 do
694+ Types, Math, FPImage, GraphMath;
695+
696+ function CreateRotatedImage(AImage: TFPMemoryImage; Angle: Double): TFPMemoryImage; // Angle is in radians
697+ var
698+ R: TRect;
699+ x, y: Integer;
700+ C, P: TPoint;
701+ delta: TPoint;
677702 begin
678- P := RotatePoint(Point(x, y) - C, -Angle) + C;
679- P := P + delta;
680- if (P.X >= 0) and (P.Y >= 0) and (P.X < AImage.Width) and (P.Y < AImage.Height) then
681- Result.Colors[x, y] := AImage.Colors[P.X, P.Y]
682- else
683- Result.Colors[x, y] := colTransparent;
703+ // Calculate bounds of the rotated image
704+ R := RotateRect(AImage.Width, AImage.Height, Angle);
705+ OffsetRect(R, -R.Left, -R.Top);
706+
707+ // Calculate center of rotated image
708+ C := Point((R.Left + R.Right) div 2, (R.Top + R.Bottom) div 2);
709+
710+ // Create the resulting image.
711+ Result := TFPMemoryImage.Create(R.Right - R.Left, R.Bottom - R.Top);
712+
713+ // Correction needed to center the rotated pixels
714+ delta := Point((AImage.Width - Result.Width) div 2, (AImage.Height - Result.Height) div 2);
715+
716+ // Iterate over all pixels in the result image and look up the corresponding
717+ // pixels in the unrotated image. Pixels in the rotated image which are outside
718+ // the unrotated image are set to be transparent.
719+ for y := 0 to Result.Height-1 do
720+ for x := 0 to Result.Width-1 do
721+ begin
722+ P := RotatePoint(Point(x, y) - C, -Angle) + C;
723+ P := P + delta;
724+ if (P.X >= 0) and (P.Y >= 0) and (P.X < AImage.Width) and (P.Y < AImage.Height) then
725+ Result.Colors[x, y] := AImage.Colors[P.X, P.Y]
726+ else
727+ Result.Colors[x, y] := colTransparent;
728+ end;
684729 end;
685-end;
686730```
687731
688732### Writing an 8-bit paletted bitmap file
689733
690-The following section is based on forum discussion <https://forum.lazarus.freepascal.org/index.php/topic,63215.msg478472.html#msg478472>.
734+The following section is based on forum discussion <https://forum.lazarus.freepascal.org/index.php/topic,63215.msg478472.html#msg478472>.
691735
692736For creating a bmp file with a color palette set the `UsePalette` property of the `TFPCustomImage` to `true`. Add the FPColors of the palette entries to the image's `Palette` property. For painting on a canvas define colors by the FPColor values in the same way as with an unpaletted image; the palette index of the requested color is determined internally. When a color is not found in the existing palette, the color is added automatically. If this is not wanted you can also specify the colors by means of the palette index: `canvas.Brush.FPColor := image.Palette[1]`
693-
694-``` Pascal
737+```
695738program PaletteBMP;
696-
697-{$mode objfpc}{$H+}
698-
699-uses
700- classes, fpcanvas, fpimage, fpimgcanv, fpwritebmp;
701-
702-var
703- img: TFPMemoryImage;
704- cnv: TFPImageCanvas;
705- writer: TFPCustomimageWriter;
706-begin
707- img := TFPMemoryImage.Create(100, 100);
708- try
709- img.UsePalette := true; // IMPORTANT!
710- // colBlack is always available at index 0.
711- img.Palette.Add(colYellow); // Index 1
712- img.Palette.Add(colBlue); // Index 2
713- img.Palette.Add(colGreen); // Index 3
714-
715- cnv := TFPImageCanvas.Create(img);
716- try
717- cnv.Brush.FPColor := colYellow;
718- cnv.Rectangle(10, 10, 45, 45);
719-
720- cnv.Brush.FPColor := colBlue;
721- cnv.Rectangle(55, 10, 90, 45);
722-
723- cnv.Brush.FPColor := img.Palette[3];
724- cnv.Rectangle(10, 55, 45, 90);
725-
726- cnv.Brush.FPColor := colWhite; // not yet in palette
727- cnv.Rectangle(55, 55, 90, 90);
728- finally
729- cnv.Free;
730- end;
731-
732- writer := TFPWriterBMP.Create;
733- TFPWriterBMP(writer).BitsPerPixel := 8;
734- try
735- img.SaveToFile('test-8bpp.bmp', writer);
736- finally
737- writer.Free;
738- end;
739- finally
740- img.Free;
741- end;
742-end.
739+
740+ {$mode objfpc}{$H+}
741+
742+ uses
743+ classes, fpcanvas, fpimage, fpimgcanv, fpwritebmp;
744+
745+ var
746+ img: TFPMemoryImage;
747+ cnv: TFPImageCanvas;
748+ writer: TFPCustomimageWriter;
749+ begin
750+ img := TFPMemoryImage.Create(100, 100);
751+ try
752+ img.UsePalette := true; // IMPORTANT!
753+ // colBlack is always available at index 0.
754+ img.Palette.Add(colYellow); // Index 1
755+ img.Palette.Add(colBlue); // Index 2
756+ img.Palette.Add(colGreen); // Index 3
757+
758+ cnv := TFPImageCanvas.Create(img);
759+ try
760+ cnv.Brush.FPColor := colYellow;
761+ cnv.Rectangle(10, 10, 45, 45);
762+
763+ cnv.Brush.FPColor := colBlue;
764+ cnv.Rectangle(55, 10, 90, 45);
765+
766+ cnv.Brush.FPColor := img.Palette[3];
767+ cnv.Rectangle(10, 55, 45, 90);
768+
769+ cnv.Brush.FPColor := colWhite; // not yet in palette
770+ cnv.Rectangle(55, 55, 90, 90);
771+ finally
772+ cnv.Free;
773+ end;
774+
775+ writer := TFPWriterBMP.Create;
776+ TFPWriterBMP(writer).BitsPerPixel := 8;
777+ try
778+ img.SaveToFile('test-8bpp.bmp', writer);
779+ finally
780+ writer.Free;
781+ end;
782+ finally
783+ img.Free;
784+ end;
785+ end.
743786```
744787
745788### Color reduction
746789
747-When images are to be displayed on devices which support only a limited number of colors the number of distinct colors in the image must be reduced such that there is no significant loss in image quality. Two steps are involved in this process
790+When images are to be displayed on devices which support only a limited number of colors the number of distinct colors in the image must be reduced such that there is no significant loss in image quality. Two steps are involved in this process
748791
749-- color quantization: This creates a palette with a maximum allowed size and adds those colors that are a good approximation of all colors in the original image.
750-- dithering: The palette colors are distributed over the image so that the original image is best approximated.
792+ * color quantization: This creates a palette with a maximum allowed size and adds those colors that are a good approximation of all colors in the original image.
793+ * dithering: The palette colors are distributed over the image so that the original image is best approximated.
751794
752-For this purpose, fcl-image contains the units fpquantizer and fpditherer. The following code is adapted from the forum post <https://forum.lazarus.freepascal.org/index.php/topic,13468.msg70495>. It reduces the input image to an image with the specified bits per pixels (4 bits per pixel --\> 16 colors, 8 bits per pixel --\> 256 colors):
795+For this purpose, fcl-image contains the units fpquantizer and fpditherer. The following code is adapted from the forum post <https://forum.lazarus.freepascal.org/index.php/topic,13468.msg70495>. It reduces the input image to an image with the specified bits per pixels (4 bits per pixel --> 16 colors, 8 bits per pixel --> 256 colors):
753796
754-![](/wiki-images/6/60/Fcl-image_lenna_24bpp.png) ![](/wiki-images/b/ba/Fcl-image_lenna_8bpp.png)
797+[![fcl-image lenna 24bpp.png](/wiki-images/f/fa/fcl-image_lenna_24bpp.png)](</File:fcl-image_lenna_24bpp.png>)
755798
756-``` Pascal
799+[![fcl-image lenna 8bpp.png](/wiki-images/b/b7/fcl-image_lenna_8bpp.png)](</File:fcl-image_lenna_8bpp.png>)
800+```
757801uses
758- fpimage, fpimgcanv, fpreadbmp, fpwritebmp, fpquantizer, fpditherer;
759-
760-procedure ReduceColors(SourceFile, TargetFile:String; BitsPerPixel: Integer);
761-var
762- sourceImg, targetImg: TFPMemoryImage;
763- reader: TFPReaderBMP;
764- writer: TFPWriterBMP;
765- quantizer: TFPMedianCutQuantizer = nil;
766- palette: TFPPalette = nil;
767- ditherer: TFPFloydSteinbergDitherer = nil;
768-begin
769- if FileExists(SourceFile) then begin
770- sourceImg := TFPMemoryImage.Create(0,0);
771- targetImg := TFPMemoryImage.Create(0,0);
772- reader := TFPReaderBMP.Create;
773- writer := TFPWriterBMP.Create;
774- try
775- sourceImg.LoadFromFile(SourceFile);
776- quantizer := TFPMedianCutQuantizer.Create;
777- quantizer.ColorNumber := 1 shl BitsPerPixel;
778- quantizer.Add(sourceImg);
779- palette := quantizer.Quantize;
780- ditherer := TFPFloydSteinbergDitherer.Create(palette);
781- ditherer.Dither(sourceImg, targetImg);
782- writer.BitsPerPixel := BitsPerPixel;
783- targetImg.SaveToFile(TargetFile, writer);
784- finally
785- ditherer.Free;
786- palette.Free;
787- quantizer.Free;
788- writer.Free;
789- reader.Free;
790- targetImg.Free;
791- sourceImg.Free;
802+ fpimage, fpimgcanv, fpreadbmp, fpwritebmp, fpquantizer, fpditherer;
803+
804+ procedure ReduceColors(SourceFile, TargetFile:String; BitsPerPixel: Integer);
805+ var
806+ sourceImg, targetImg: TFPMemoryImage;
807+ reader: TFPReaderBMP;
808+ writer: TFPWriterBMP;
809+ quantizer: TFPMedianCutQuantizer = nil;
810+ palette: TFPPalette = nil;
811+ ditherer: TFPFloydSteinbergDitherer = nil;
812+ begin
813+ if FileExists(SourceFile) then begin
814+ sourceImg := TFPMemoryImage.Create(0,0);
815+ targetImg := TFPMemoryImage.Create(0,0);
816+ reader := TFPReaderBMP.Create;
817+ writer := TFPWriterBMP.Create;
818+ try
819+ sourceImg.LoadFromFile(SourceFile);
820+ quantizer := TFPMedianCutQuantizer.Create;
821+ quantizer.ColorNumber := 1 shl BitsPerPixel;
822+ quantizer.Add(sourceImg);
823+ palette := quantizer.Quantize;
824+ ditherer := TFPFloydSteinbergDitherer.Create(palette);
825+ ditherer.Dither(sourceImg, targetImg);
826+ writer.BitsPerPixel := BitsPerPixel;
827+ targetImg.SaveToFile(TargetFile, writer);
828+ finally
829+ ditherer.Free;
830+ palette.Free;
831+ quantizer.Free;
832+ writer.Free;
833+ reader.Free;
834+ targetImg.Free;
835+ sourceImg.Free;
836+ end;
837+ end;
792838 end;
793- end;
794-end;
795839```
796840
797-The same code can be used to reduce the colored input image to a dithered black-and-white image. Since here the palette consists of black and white only, the quantizer can be omitted: ![](/wiki-images/6/60/Fcl-image_lenna_24bpp.png) ![](/wiki-images/f/f9/Fcl-image_lenna_1bpp.png)
841+The same code can be used to reduce the colored input image to a dithered black-and-white image. Since here the palette consists of black and white only, the quantizer can be omitted:
798842
799-``` Pascal
800-uses
801- SysUtils,
802- fpimage, fpimgcanv, fpreadbmp, fpwritebmp, fpditherer;
843+[![fcl-image lenna 24bpp.png](/wiki-images/f/fa/fcl-image_lenna_24bpp.png)](</File:fcl-image_lenna_24bpp.png>)
803844
804-procedure BlackAndWhite(SourceFile, TargetFile:String);
805-var
806- sourceImg, targetImg: TFPMemoryImage;
807- reader: TFPReaderBMP;
808- writer: TFPWriterBMP;
809- palette: TFPPalette = nil;
810- ditherer: TFPFloydSteinbergDitherer = nil;
811-begin
812- sourceImg := TFPMemoryImage.Create(0,0);
813- targetImg := TFPMemoryImage.Create(0,0);
814- reader := TFPReaderBMP.Create;
815- writer := TFPWriterBMP.Create;
816- try
817- sourceImg.LoadFromFile(SourceFile);
818- palette := TFPPalette.Create(2);
819- palette.Add(colBlack);
820- palette.Add(colWhite);
821- ditherer := TFPFloydSteinbergDitherer.Create(palette);
822- ditherer.Dither(sourceImg, targetImg);
823- writer.BitsPerPixel := 1;
824- targetImg.SaveToFile(TargetFile, writer);
825- finally
826- ditherer.Free;
827- palette.Free;
828- writer.Free;
829- reader.Free;
830- targetImg.Free;
831- sourceImg.Free;
832- end;
833-end;
845+[![fcl-image lenna 1bpp.png](/wiki-images/4/41/fcl-image_lenna_1bpp.png)](</File:fcl-image_lenna_1bpp.png>)
834846```
847+uses
848+ SysUtils,
849+ fpimage, fpimgcanv, fpreadbmp, fpwritebmp, fpditherer;
850+
851+ procedure BlackAndWhite(SourceFile, TargetFile:String);
852+ var
853+ sourceImg, targetImg: TFPMemoryImage;
854+ reader: TFPReaderBMP;
855+ writer: TFPWriterBMP;
856+ palette: TFPPalette = nil;
857+ ditherer: TFPFloydSteinbergDitherer = nil;
858+ begin
859+ sourceImg := TFPMemoryImage.Create(0,0);
860+ targetImg := TFPMemoryImage.Create(0,0);
861+ reader := TFPReaderBMP.Create;
862+ writer := TFPWriterBMP.Create;
863+ try
864+ sourceImg.LoadFromFile(SourceFile);
865+ palette := TFPPalette.Create(2);
866+ palette.Add(colBlack);
867+ palette.Add(colWhite);
868+ ditherer := TFPFloydSteinbergDitherer.Create(palette);
869+ ditherer.Dither(sourceImg, targetImg);
870+ writer.BitsPerPixel := 1;
871+ targetImg.SaveToFile(TargetFile, writer);
872+ finally
873+ ditherer.Free;
874+ palette.Free;
875+ writer.Free;
876+ reader.Free;
877+ targetImg.Free;
878+ sourceImg.Free;
879+ end;
880+ end;
881+```
835882
836883### Gamma correction
837884
838-FCL-Image can be used for image transformations, such as **gamma correction** (adjustment of pixel values to modify brightness, see <https://en.wikipedia.org/wiki/Gamma_correction>):
839-
840-``` Pascal
885+FCL-Image can be used for image transformations, such as **gamma correction** (adjustment of pixel values to modify brightness, see <https://en.wikipedia.org/wiki/Gamma_correction>):
886+```
841887uses
842- fpimage, fpreadjpeg, fpwritejpeg, math;
843-
844-procedure GammaCorrection(const ASrcFile, ADestFile: String; AGamma: Double);
845-var
846- img: TFPMemoryImage;
847- reader: TFPCustomImageReader;
848- writer: TFPCustomImageWriter;
849- i, j: Integer;
850- clr: TFPColor;
851-begin
852- Assert(AGamma <> 0.0);
853-
854- img := TFPMemoryImage.Create(0, 0);
855- try
856- reader := TFPReaderJpeg.Create;
857- try
858- img.LoadFromFile(ASrcFile, reader);
859- finally
860- reader.Free;
861- end;
862-
863- for j := 0 to img.Height - 1 do
864- for i := 0 to img.Width - 1 do
865- begin
866- clr := img.Colors[i, j];
867- clr.Red := round(((clr.Red / 65535)**AGamma)*65535);
868- clr.Green := round(((clr.Green / 65535)**AGamma)*65535);
869- clr.Blue := round(((clr.Blue / 65535)**AGamma)*65535);
870- img.Colors[i, j] := clr;
888+ fpimage, fpreadjpeg, fpwritejpeg, math;
889+
890+ procedure GammaCorrection(const ASrcFile, ADestFile: String; AGamma: Double);
891+ var
892+ img: TFPMemoryImage;
893+ reader: TFPCustomImageReader;
894+ writer: TFPCustomImageWriter;
895+ i, j: Integer;
896+ clr: TFPColor;
897+ begin
898+ Assert(AGamma <> 0.0);
899+
900+ img := TFPMemoryImage.Create(0, 0);
901+ try
902+ reader := TFPReaderJpeg.Create;
903+ try
904+ img.LoadFromFile(ASrcFile, reader);
905+ finally
906+ reader.Free;
907+ end;
908+
909+ for j := 0 to img.Height - 1 do
910+ for i := 0 to img.Width - 1 do
911+ begin
912+ clr := img.Colors[i, j];
913+ clr.Red := round(((clr.Red / 65535)**AGamma)*65535);
914+ clr.Green := round(((clr.Green / 65535)**AGamma)*65535);
915+ clr.Blue := round(((clr.Blue / 65535)**AGamma)*65535);
916+ img.Colors[i, j] := clr;
917+ end;
918+
919+ writer := TFPWriterJpeg.Create;
920+ try
921+ img.SaveToFile(ADestFile, writer);
922+ finally
923+ writer.Free;
924+ end;
925+ finally
926+ img.Free;
871927 end;
872-
873- writer := TFPWriterJpeg.Create;
874- try
875- img.SaveToFile(ADestFile, writer);
876- finally
877- writer.Free;
878928 end;
879- finally
880- img.Free;
881- end;
882-end;
883929```
884930
885931### Bar codes
886932
887-FCL-Image contains some units to create bar codes. Here is an example how to create a QRCode and save it as a graphics file:
933+FCL-Image contains some units to create bar codes. Here is an example how to create a QRCode and save it as a graphics file:
888934
889-``` Pascal
935+[![fpc output qrcode as imagefile.png](/wiki-images/c/ce/fpc_output_qrcode_as_imagefile.png)](</File:fpc_output_qrcode_as_imagefile.png>)
936+```
890937program qrcode_as_imagefile;
891-uses
892- fpqrcodegen, fpimgqrcode, fpWritePng;
893-const
894- TEXT_STRING = 'This is a qrcode generated by fpc.';
895- FILE_NAME = 'qrcode.png';
896-var
897- qrcode: TImageQRCodeGenerator;
898-begin
899- qrcode := TImageQRCodeGenerator.Create;
900- try
901- qrcode.PixelSize := 4;
902- qrcode.Border := 8;
903- qrcode.ErrorCorrectionLevel := EccHigh;
904- qrcode.Generate(TEXT_STRING);
905- qrcode.SaveToFile(FILE_NAME);
906- finally
907- qrcode.Free;
908- end;
909-end.
938+ uses
939+ fpqrcodegen, fpimgqrcode, fpWritePng;
940+ const
941+ TEXT_STRING = 'This is a qrcode generated by fpc.';
942+ FILE_NAME = 'qrcode.png';
943+ var
944+ qrcode: TImageQRCodeGenerator;
945+ begin
946+ qrcode := TImageQRCodeGenerator.Create;
947+ try
948+ qrcode.PixelSize := 4;
949+ qrcode.Border := 8;
950+ qrcode.ErrorCorrectionLevel := EccHigh;
951+ qrcode.Generate(TEXT_STRING);
952+ qrcode.SaveToFile(FILE_NAME);
953+ finally
954+ qrcode.Free;
955+ end;
956+ end.
910957```
911958
912-And the next example creates a "2-of-5-industrial" barcode:
959+And the next example creates a "2-of-5-industrial" barcode:
913960
914-``` pascal
915-program project1;
916-uses
917- Types, fpImage, fpBarCode, fpImgBarCode, fpWritePng;
918-const
919- HEIGHT = 60;
920- NUMERIC_TEXT = '0123456789';
921- ENCODING = be2of5Industrial;
922- UNIT_WIDTH = 2;
923- WEIGHT = 4;
924- FILE_NAME = 'barcode.png';
925-var
926- barcode: TFPDrawBarcode;
927- width: Integer;
928-begin
929- barcode := TFPDrawBarcode.Create;
930- try
931- barcode.Encoding := ENCODING;
932- barcode.UnitWidth := UNIT_WIDTH;
933- barcode.Weight := WEIGHT;
934- barcode.Text := NUMERIC_TEXT;
935- width := barcode.CalcWidth;
936- barcode.Rect := Rect(0, 0, width, HEIGHT);
937- barcode.Image := TFPCompactImgGray8Bit.Create(barcode.Rect.Width, barcode.Rect.Height);
938- try
939- if barcode.Draw then
940- begin
941- barcode.Image.SaveToFile(FILE_NAME);
942- WriteLn('Saved to file ', FILE_NAME);
943- end else
944- WriteLn('Error generating barcode.');
945- finally
946- barcode.Image.Free;
947- end;
948- finally
949- barcode.Free;
950- end;
951-end.
961+[![fpc output code25 as imagefile.png](/wiki-images/5/5b/fpc_output_code25_as_imagefile.png)](</File:fpc_output_code25_as_imagefile.png>)
952962```
963+program code25_as_image_file;
964+ uses
965+ Types, fpImage, fpBarCode, fpImgBarCode, fpWritePng;
966+ const
967+ HEIGHT = 60;
968+ NUMERIC_TEXT = '0123456789';
969+ ENCODING = be2of5Industrial;
970+ UNIT_WIDTH = 2;
971+ WEIGHT = 4;
972+ FILE_NAME = 'barcode.png';
973+ var
974+ barcode: TFPDrawBarcode;
975+ width: Integer;
976+ begin
977+ barcode := TFPDrawBarcode.Create;
978+ try
979+ barcode.Encoding := ENCODING;
980+ barcode.UnitWidth := UNIT_WIDTH;
981+ barcode.Weight := WEIGHT;
982+ barcode.Text := NUMERIC_TEXT;
983+ width := barcode.CalcWidth;
984+ barcode.Rect := Rect(0, 0, width, HEIGHT);
985+ barcode.Image := TFPCompactImgGray8Bit.Create(barcode.Rect.Width, barcode.Rect.Height);
986+ try
987+ if barcode.Draw then
988+ begin
989+ barcode.Image.SaveToFile(FILE_NAME);
990+ WriteLn('Saved to file ', FILE_NAME);
991+ end else
992+ WriteLn('Error generating barcode.');
993+ finally
994+ barcode.Image.Free;
995+ end;
996+ finally
997+ barcode.Free;
998+ end;
999+ end.
1000+```
9531001
9541002### Getting image size without loading the image itself
9551003
956-Answer by forum member **wp**.
957-
958-The basic image reader type, `TFPCustomImageReader`, is equipped with a class function `ImageSize: TPoint` which determines the image size in pixels without decoding the image data. In case of a jpeg image, the reader class is `TFPReaderJPEG` in unit `fpreadjpeg`; therefore, assuming that the image file is accessed via a stream, the image size can be obtained as a `TPoint` by a one-liner:
1004+Answer by forum member **wp**.
9591005
960-``` pascal
961- Size := TFPReaderJPEG.ImageSize(stream);
1006+The basic image reader type, `TFPCustomImageReader`, is equipped with a class function `ImageSize: TPoint` which determines the image size in pixels without decoding the image data. In case of a jpeg image, the reader class is `TFPReaderJPEG` in unit `fpreadjpeg`; therefore, assuming that the image file is accessed via a stream, the image size can be obtained as a `TPoint` by a one-liner:
9621007```
963-
964-If you have other image file formats you must pick the correct reader class from the fcl-image units. To help you, the basic fcl-image class, `TFPCustomImage`, has class methods `FindReaderFromStream(AStream)` which determines the required reader class from the file header or `FindReaderFromFileName(AFileName)` which determines the reader class from the extension of the filename.
1008+Size := TFPReaderJPEG.ImageSize(stream);
1009+```
9651010
966-Putting these class methods together you can determine the image size for any image format supported by fcl-image by the following short function (do not forget to list the reader units in the uses clause for all file formats requested):
1011+If you have other image file formats you must pick the correct reader class from the fcl-image units. To help you, the basic fcl-image class, `TFPCustomImage`, has class methods `FindReaderFromStream(AStream)` which determines the required reader class from the file header or `FindReaderFromFileName(AFileName)` which determines the reader class from the extension of the filename.
9671012
968-``` pascal
1013+Putting these class methods together you can determine the image size for any image format supported by fcl-image by the following short function (do not forget to list the reader units in the uses clause for all file formats requested):
1014+```
9691015uses
970- [...] fpImage, fpReadJpeg, fpReadBMP, fpReadPNG, fpReadGIF, fpReadPCX, fpReadTIFF, fpReadTGA;
971-
972-function GetImageSize(const AFileName: String; out ASize: TPoint): Boolean;
973-var
974- stream: TStream;
975- readerClass: TFPCustomImageReaderClass;
976-begin
977- Result := false;
978- ASize := Point(-1, -1);
979- stream := TFileStream.Create(AFileName, fmOpenRead);
980- try
981- readerClass := TFPCustomImage.FindReaderFromStream(stream);
982- if readerClass <> nil then
1016+ [...] fpImage, fpReadJpeg, fpReadBMP, fpReadPNG, fpReadGIF, fpReadPCX, fpReadTIFF, fpReadTGA;
1017+
1018+ function GetImageSize(const AFileName: String; out ASize: TPoint): Boolean;
1019+ var
1020+ stream: TStream;
1021+ readerClass: TFPCustomImageReaderClass;
9831022 begin
984- ASize := readerClass.ImageSize(stream);
985- Result := true;
1023+ Result := false;
1024+ ASize := Point(-1, -1);
1025+ stream := TFileStream.Create(AFileName, fmOpenRead);
1026+ try
1027+ readerClass := TFPCustomImage.FindReaderFromStream(stream);
1028+ if readerClass <> nil then
1029+ begin
1030+ ASize := readerClass.ImageSize(stream);
1031+ Result := true;
1032+ end;
1033+ finally
1034+ stream.Free;
1035+ end;
9861036 end;
987- finally
988- stream.Free;
989- end;
990-end;
9911037```
9921038
1039+![Light bulb](https://upload.wikimedia.org/wikipedia/commons/d/d8/Nuvola_apps_ktip.png) **Note:** It is not guaranteed that file readers from third-party graphics libraries (e.g. BGRABitmap) support this mechanism. If their reader class does not implement the ImageSize class method the result of the function above will be (-1,-1).
1040+
9931041## See also
9941042
995-- [[Package List|Packages List]]
996-- [[Developing with Graphics]]
997-- [Stretching a Canvas: Image support for Free Pascal](https://www.freepascal.org/~michael/articles/#canvas): In this extensive article by Michael Van Canneyt, the Free Pascal support for images and simple drawing support is presented.
1043+ * [[Package List|Packages List]]
1044+ * [[Developing with Graphics]]
1045+ * [Stretching a Canvas: Image support for Free Pascal](<https://www.freepascal.org/~michael/articles/#canvas>): In this extensive article by Michael Van Canneyt, the Free Pascal support for images and simple drawing support is presented.
9981046
9991047---
1000-*From the Free Pascal wiki, page "fcl-image", as it stood on 2024-03-08 after a change by Wp, 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).*
1001-Category: FCL
1002-Category: Graphics
1003-Category: Packages
1048+*From the Free Pascal wiki, page "fcl-image", as the Internet Archive kept it on 2025-08-19, last changed on 2025-07-01. 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