Unit CastleImages

DescriptionUsesClasses, Interfaces, Objects and RecordsFunctions and ProceduresTypesConstantsVariables

Description

Loading, saving, and processing of 2D (and 3D) images (TCastleImage and descendants). Storing images in the memory, loading and saving them from/to files in various formats, resizing, converting to grayscale, copying and merging, many other image operations — it's all here.

The most important class here is TCastleImage. It represents an image as a simple uncompressed array of pixels. Descendants of TCastleImage define what exactly is a "pixel". We have 8-bit color images (TRGBAlphaImage, TRGBImage, TGrayscaleAlphaImage and TGrayscaleImage). We also have an image with floating-point precision and range: TRGBFloatImage. You are free to create more descendants of TCastleImage in your own units if you want to encode the pixel differently.

When reading and writing image files, we understand various image formats. See TImageFormat documentation for a current list of supported formats, with comments specific to particular formats. The basic loading and saving procedures and LoadImage and SaveImage.

Example usage of this unit:

  var
    Image: TCastleImage;
  begin
    Image := LoadImage('image.png', []);
    { scale the image to be 2x smaller }
    Image.Resize(Image.Width div 2, Image.Height div 2);
    SaveImage(Image, 'newimage.png');
  end;

This unit is of course not dependent on OpenGL or any other rendering library. See CastleGLImages for OpenGL image operations (for textures and others).

Uses

Overview

Classes, Interfaces, Objects and Records

Name Description
Class EImagePosOutOfRange Raised by TCastleImage.MakeExtracted when coordinates on image are wrong.
Class EImageLerpError  
Class EImageLerpInvalidClasses  
Class EImageLerpDifferentSizes  
Class TEncodedImage Abstract class for an image with unspecified, possibly compressed, memory format.
Class TCastleImage An abstract class representing image as a simple array of pixels.
Class ECannotFlipS3TCImage  
Class TS3TCImage Image encoded with S3TC compression.
Class ECannotDecompressS3TC  
Class TRGBImage Image with pixel represented as a TVector3Byte (red, green, blue).
Class TRGBAlphaImage  
Class TRGBFloatImage Image with high-precision RGB colors encoded as 3 floats.
Class TGrayscaleImage Grayscale image.
Class TGrayscaleAlphaImage Grayscale image with an alpha channel.
Class EImageLoadError  
Class EInvalidImageFormat  
Class EInvalidBMP  
Class EInvalidPNG  
Class EInvalidPPM  
Class EInvalidIPL  
Class EInvalidRGBE  
Class EUnableToLoadImage  
record TImageFormatInfo  
Class EImageFormatNotSupported  
Class EImageSaveError  

Functions and Procedures

function EqualRGB(const Color1, Color2: TVector3Byte; Tolerance: Byte): boolean;
function InImageClasses(ImageClass: TCastleImageClass; const ImageClasses: array of TCastleImageClass): boolean; overload;
function InImageClasses(Image: TCastleImage; const ImageClasses: array of TCastleImageClass): boolean; overload;
function ImageClassesEqual(const Ar1, Ar2: array of TCastleImageClass): boolean;
procedure ImageClassesAssign(var Variable: TDynArrayImageClasses; const NewValue: array of TCastleImageClass);
function Vector3ToRGBE(const v: TVector3Single): TVector4Byte;
function VectorRGBETo3Single(const v: TVector4Byte): TVector3Single;
function LoadPNG(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
function LoadBMP(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
function LoadGIF(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
function LoadTGA(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
function LoadSGI(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
function LoadTIFF(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
function LoadJP2(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
function LoadEXR(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
function LoadJPEG(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
function LoadXPM(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
function LoadPSD(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
function LoadPCX(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
function LoadPPM(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
function LoadPNM(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
function LoadIPL(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
function LoadRGBE(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
function LoadDDS(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
procedure SaveBMP(Img: TCastleImage; Stream: TStream);
procedure SavePNG(Img: TCastleImage; Stream: TStream; interlaced: boolean); overload;
procedure SavePNG(Img: TCastleImage; Stream: TStream); overload;
procedure SaveJPEG(Img: TCastleImage; Stream: TStream);
procedure SavePPM(Img: TCastleImage; Stream: TStream; binary: boolean); overload;
procedure SavePPM(Img: TCastleImage; Stream: TStream); overload;
procedure SaveRGBE(Img: TCastleImage; Stream: TStream);
procedure SaveDDS(Img: TCastleImage; Stream: TStream);
function MimeTypeToImageFormat(const MimeType: string; const OnlyLoadable, OnlySaveable: boolean; out ImgFormat: TImageFormat): boolean;
function ListImageExtsLong(OnlyLoadable, OnlySaveable: boolean; const LinePrefix: string): string;
function ListImageExtsShort(OnlyLoadable, OnlySaveable: boolean): string;
function LoadImage(Stream: TStream; const StreamFormat: TImageFormat; const AllowedImageClasses: array of TCastleImageClass) :TCastleImage; overload;
function LoadImage(Stream: TStream; const MimeType: string; const AllowedImageClasses: array of TCastleImageClass) :TCastleImage; overload;
function LoadImage(const URL: string; const AllowedImageClasses: array of TCastleImageClass) :TCastleImage; overload;
function LoadImage(const URL: string; const AllowedImageClasses: array of TCastleImageClass; const ResizeToX, ResizeToY: Cardinal; const Interpolation: TResizeInterpolation = riNearest): TCastleImage; overload;
procedure SaveImage(const img: TCastleImage; const Format: TImageFormat; Stream: TStream); overload;
procedure SaveImage(const img: TCastleImage; const MimeType: string; Stream: TStream); overload;
procedure SaveImage(const Img: TCastleImage; const URL: string); overload;
procedure ImageAlphaConstTo1st(var Img: TCastleImage; const AlphaConst: byte);
function ImageClassBestForSavingToFormat(const Format: TImageFormat): TCastleImageClass; overload;
function ImageClassBestForSavingToFormat(const URL: string): TCastleImageClass; overload;
procedure AlphaMaxTo1st(var A: TAlphaChannel; const B: TAlphaChannel);

Types

TAlphaChannel = (...);
TResizeInterpolation = (...);
TCastleImageList = specialize TFPGObjectList<TCastleImage>;
TEncodedImageList = specialize TFPGObjectList<TEncodedImage>;
TS3TCCompression = (...);
TDecompressS3TCFunction = function (Image: TS3TCImage): TCastleImage;
TCastleImageClass = class of TCastleImage;
TEncodedImageClass = class of TEncodedImage;
TDynArrayImageClasses = array of TCastleImageClass;
TImageClass = TCastleImageClass deprecated;
TImage = TCastleImage deprecated;
TImageFormat = (...);
TImageFormats = set of TImageFormat;
TImageLoadFunc = function (Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
TImageSaveFunc = procedure (Img: TCastleImage; Stream: TStream);
TImageLoadHandledClasses = (...);
TImageSaveHandledClasses = (...);
TImageFormatInfoMimeTypesCount = 1..6;
TImageFormatInfoExtsCount = 1..3;

Constants

DefaultAlphaTolerance = 5;
DefaultAlphaWrongPixelsTolerance = 0.01;
ImageFormatInfos: array [TImageFormat] of TImageFormatInfo = ( ( FormatName: 'PNG image'; MimeTypesCount: 1; MimeTypes: ('image/png', '', '', '', '', ''); ExtsCount: 1; Exts: ('png', '', ''); Load: @LoadPNG; LoadedClasses: lcG_GA_RGB_RGBA; Save: @SavePNG; SavedClasses: scG_GA_RGB_RGBA; ), ( FormatName: 'Windows BMP image'; MimeTypesCount: 1; MimeTypes: ('image/bmp', '', '', '', '', ''); ExtsCount: 1; Exts: ('bmp', '', ''); Load: @LoadBMP; LoadedClasses: lcRGB_RGBA; Save: @SaveBMP; SavedClasses: scRGB), ( FormatName: 'PPM image'; MimeTypesCount: 1; MimeTypes: ('image/x-portable-pixmap', '', '', '', '', ''); ExtsCount: 1; Exts: ('ppm', '', ''); Load: @LoadPPM; LoadedClasses: lcRGB; Save: @SavePPM; SavedClasses: scRGB; ), ( FormatName: 'JPEG image'; MimeTypesCount: 2; MimeTypes: ('image/jpeg', 'image/jpg', '', '', '', ''); ExtsCount: 3; Exts: ('jpg', 'jpeg', 'jpe'); Load: @LoadJPEG; LoadedClasses: lcRGB_RGBA; Save: @SaveJPEG; SavedClasses: scRGB ), ( FormatName: 'GIF image'; MimeTypesCount: 1; MimeTypes: ('image/gif', '', '', '', '', ''); ExtsCount: 1; Exts: ('gif', '', ''); Load: @LoadGIF; LoadedClasses: lcRGB_RGBA; Save: nil; SavedClasses: scRGB; ), ( FormatName: 'TarGA image'; MimeTypesCount: 2; MimeTypes: ('image/x-targa', 'image/x-tga', '', '', '', ''); ExtsCount: 2; Exts: ('tga', 'tpic', ''); Load: @LoadTGA; LoadedClasses: lcRGB_RGBA; Save: nil; SavedClasses: scRGB; ), ( FormatName: 'XPM image'; MimeTypesCount: 1; MimeTypes: ('image/x-xpixmap', '', '', '', '', ''); ExtsCount: 1; Exts: ('xpm', '', ''); Load: @LoadXPM; LoadedClasses: lcRGB_RGBA; Save: nil; SavedClasses: scRGB; ), ( FormatName: 'PSD image'; MimeTypesCount: 4; MimeTypes: ('image/photoshop', 'image/x-photoshop', 'image/psd', 'application/photoshop', '', ''); ExtsCount: 1; Exts: ('psd', '', ''); Load: @LoadPSD; LoadedClasses: lcRGB_RGBA; Save: nil; SavedClasses: scRGB; ), ( FormatName: 'ZSoft PCX image'; MimeTypesCount: 5; MimeTypes: ('image/pcx', 'application/pcx', 'application/x-pcx', 'image/x-pc-paintbrush', 'image/x-pcx', ''); ExtsCount: 1; Exts: ('pcx', '', ''); Load: @LoadPCX; LoadedClasses: lcRGB_RGBA; Save: nil; SavedClasses: scRGB; ), ( FormatName: 'PNM image'; MimeTypesCount: 6; MimeTypes: ('image/x-portable-anymap', 'image/x-portable-graymap', 'image/x-pgm', 'image/x-portable-bitmap', 'image/pbm', 'image/x-pbm'); ExtsCount: 3; Exts: ('pnm', 'pgm', 'pbm'); Load: @LoadPNM; LoadedClasses: lcRGB_RGBA; Save: nil; SavedClasses: scRGB; ), ( FormatName: 'DDS image'; MimeTypesCount: 1; MimeTypes: ('image/x-dds', '', '', '', '', ''); ExtsCount: 1; Exts: ('dds', '', ''); Load: @LoadDDS; LoadedClasses: lcG_GA_RGB_RGBA; Save: @SaveDDS; SavedClasses: scG_GA_RGB_RGBA; ), ( FormatName: 'RGBE (RGB+Exponent) image'; MimeTypesCount: 1; MimeTypes: ('image/vnd.radiance', '', '', '', '', ''); ExtsCount: 3; Exts: ('rgbe', 'pic', 'hdr'); Load: @LoadRGBE; LoadedClasses: lcRGB_RGBFloat; Save: @SaveRGBE; SavedClasses: scRGB_RGBFloat; ), ( FormatName: 'IPLab image'; MimeTypesCount: 1; MimeTypes: ('image/x-ipl', '', '', '', '', ''); ExtsCount: 1; Exts: ('ipl', '', ''); Load: @LoadIPL; LoadedClasses: lcRGB; Save: nil; SavedClasses: scRGB; ), ( FormatName: 'TIFF image'; MimeTypesCount: 1; MimeTypes: ('image/tiff', '', '', '', '', ''); ExtsCount: 2; Exts: ('tiff', 'tif', ''); Load: @LoadTIFF; LoadedClasses: lcRGB_RGBA; Save: nil; SavedClasses: scRGB; ), ( FormatName: 'SGI image'; MimeTypesCount: 3; MimeTypes: ('image/sgi', 'image/x-sgi', 'image/x-sgi-rgba', '', '', ''); ExtsCount: 1; Exts: ('sgi', '', ''); Load: @LoadSGI; LoadedClasses: lcG_GA_RGB_RGBA; Save: nil; SavedClasses: scRGB; ), ( FormatName: 'JPEG 2000 image'; MimeTypesCount: 4; MimeTypes: ('image/jp2', 'image/jpeg2000', 'image/jpeg2000-image', 'image/x-jpeg2000-image', '', ''); ExtsCount: 1; Exts: ('jp2', '', ''); Load: @LoadJP2; LoadedClasses: lcG_GA_RGB_RGBA; Save: nil; SavedClasses: scRGB; ), ( FormatName: 'EXR image'; MimeTypesCount: 1; MimeTypes: ('image/x-exr', '', '', '', '', ''); ExtsCount: 1; Exts: ('exr', '', ''); Load: @LoadEXR; LoadedClasses: lcG_GA_RGB_RGBA; Save: nil; SavedClasses: scRGB; ) );

Variables

DecompressS3TC: TDecompressS3TCFunction;
LoadImage_FileFilters: TFileFilterList;
SaveImage_FileFilters: TFileFilterList;

Description

Functions and Procedures

function EqualRGB(const Color1, Color2: TVector3Byte; Tolerance: Byte): boolean;

Check if the two RGB colors are equal, ignoring small differences. All three color components may differ by at most Tolerance. When Tolerance is 0, this is a normal (exact) comparison.

function InImageClasses(ImageClass: TCastleImageClass; const ImageClasses: array of TCastleImageClass): boolean; overload;

Check is ImageClass one of the items in the ImageClasses array, or a descendant of one of them.

function InImageClasses(Image: TCastleImage; const ImageClasses: array of TCastleImageClass): boolean; overload;

Check is Image class one of the items in the ImageClasses array, or a descendant of one of them. This is a shortcut for InImageClasses(Image.ClassType, ImageClasses).

function ImageClassesEqual(const Ar1, Ar2: array of TCastleImageClass): boolean;

Check if both arrays contain exactly the same classes in the same order.

May be extended in the future to do better checks and return true also if both array contain the same classes but in different order, and one array may contain the same classes duplicated any times. So the intention is that you should treat both arrays as sets (i.e. order of elements is ignored).

The problem is that this function should be lighting fast (as the main purpose of it is to use it in constructions like setting property values, e.g.

  if ImageClassesArraysEqual(Value, SomeProperty) then
  begin
    SomeProperty := Value;
    { ... do some lengthy operations to update new value of SomeProperty ... }
  end;

), and doing smarter checks may cost us a little time.

So for now this function returns

  • True if for sure both arrays contain the same classes and

  • False if possibly they don't contain the same classes.

procedure ImageClassesAssign(var Variable: TDynArrayImageClasses; const NewValue: array of TCastleImageClass);
 
function Vector3ToRGBE(const v: TVector3Single): TVector4Byte;

Encode RGB color as Red + Green + Blue + Exponent format. This allows you to encode high-precision colors in 4 bytes, see ifRGBE image format for pointers why this is useful.

Each component of V (red, green, blue) must be from range [0, +infinity), not merely from [0, 1]. That is, V must have only nonnegative values.

function VectorRGBETo3Single(const v: TVector4Byte): TVector3Single;

Decode Red + Green + Blue + Exponent back into RGB (3 floats).

function LoadPNG(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
 
function LoadBMP(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
 
function LoadGIF(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
 
function LoadTGA(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
 
function LoadSGI(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
 
function LoadTIFF(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
 
function LoadJP2(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
 
function LoadEXR(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
 
function LoadJPEG(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
 
function LoadXPM(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
 
function LoadPSD(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
 
function LoadPCX(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
 
function LoadPPM(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;

Load PPM image. Loads only the first image in .ppm file.

function LoadPNM(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;

Load PNM image (PNM, PGM, PBM, PPM) through FpImage. Note that for PPM, for now it's more advised to use our LoadPPM.

function LoadIPL(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
 
function LoadRGBE(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;

Load RGBE image. This low-level function can load to TRGBFloatImage (preserving image data) or to TRGBImage (loosing floating point precision of RGBE format).

function LoadDDS(Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;

Load DDS image file into a single 2D image. This simply returns the first image found in DDS file, which should be the main image. If you want to investigate other images in DDS, you have to use TDDSImage class.

procedure SaveBMP(Img: TCastleImage; Stream: TStream);
 
procedure SavePNG(Img: TCastleImage; Stream: TStream; interlaced: boolean); overload;
 
procedure SavePNG(Img: TCastleImage; Stream: TStream); overload;
 
procedure SaveJPEG(Img: TCastleImage; Stream: TStream);
 
procedure SavePPM(Img: TCastleImage; Stream: TStream; binary: boolean); overload;
 
procedure SavePPM(Img: TCastleImage; Stream: TStream); overload;
 
procedure SaveRGBE(Img: TCastleImage; Stream: TStream);
 
procedure SaveDDS(Img: TCastleImage; Stream: TStream);
 
function MimeTypeToImageFormat(const MimeType: string; const OnlyLoadable, OnlySaveable: boolean; out ImgFormat: TImageFormat): boolean;

Find image file format with given MIME type. Returns False if no format matching given MIME type.

function ListImageExtsLong(OnlyLoadable, OnlySaveable: boolean; const LinePrefix: string): string;

List available image file formats.

This is basically for debug/info purposes, you can show this to user to let him know which formats are supported (and by which extensions they are recognized). Although almost always a better way to show this to user is just to use SaveImage_FileFilters with a save dialog like TCastleWindowBase.FileDialog, this shows file types in the open/save dialog, so it's most natural and convenient to user.

ListImageExtsLong produces a multiline info (separated by NL, last line not terminated by NL), shows all extensions and FormatName for each file format. Each line starts with LinePrefix.

ListImageExtsShort writes all recognized extensions separated by comma (', ').

function ListImageExtsShort(OnlyLoadable, OnlySaveable: boolean): string;
 
function LoadImage(Stream: TStream; const StreamFormat: TImageFormat; const AllowedImageClasses: array of TCastleImageClass) :TCastleImage; overload;

The ultimate procedure to load an image from a file or URL.

URL is downloaded using CastleDownload unit. As always, if you all you care about is loading normal files, then just pass a normal filename (absolute or relative to the current directory) as the URL parameter.

Simple examples:

  { When you don't care what TCastleImage descendant you get: }
  Image := LoadImage('image.png', []);

  { When you insist on getting TRGBImage, that is 8-bit color image
    without an alpha channel. }
  ImageRGB := LoadImage('image.png', [TRGBImage]) as TRGBImage;

Image file format may be given explicitly (overloaded version with Format parameter), or guessed based on URL extension (which can be given explicitly by TypeExt, or automatically calculated from full URL). For now, we cannot guess the file format based on file contents or MIME type (the latter case would be sensible for http URLs).

AllowedImageClasses says what image classes are allowed. As a special case, AllowedImageClasses = [] is equivalent to AllowedImageClasses = [TCastleImage] which says that all TCastleImage descendants are allowed. Then this function will do everything it can to load any image into the best subclass of TCastleImage, losing as little image information it can.

Example: consider you're loading a PNG file. Let's suppose you're loading it with AllowedImageClasses = []. Then you can get TGrayscaleImage, TGrayscaleAlphaImage, TRGBImage, TRGBAlphaImage, depending on whether PNG file is grayscale or not and has alpha or not. Now let's suppose you specified AllowedImageClasses = [TRGBImage]. If PNG file will not be grayscale and not have alpha channel, LoadImage will return TRGBImage descendant, as before. But if PNG fill *will* have alpha channel then LoadImage will simply ignore (strip) alpha channel and return you TRGBImage.

Similar thing for grayscale: if image file was grayscale but you requested only TRGBImage, then grayscale may be "expanded" into full three-channel RGB.

There can also happen reverse situation: you e.g. insist that AllowedImageClasses = [TRGBAlphaImage] but given PNG image does not have alpha channel. In this case LoadImage may add "dummy" alpha channel (everywhere equal to 1.0 or High(Byte)). Similar thing when you e.g. gave AllowedImageClasses = [TRGBFloatImage] but you're loading from PNG image. In this case you want float precision, but image file cannot offer it. So LoadImage can simply convert discreet values to appropriating floating point values.

If at any point LoadImage will find that it's unable to satisfy AllowedImageClasses, it will raise EUnableToLoadImage.

Exceptions raised
EUnableToLoadImage
If Image cannot be loaded into allowed AllowedImageClasses.
EImageFormatNotSupported
If image file format cannot be loaded at all. This can happen if format is totally unknown (not recognized MIME type, derived from file extension in case of local files) or if this image format cannot be loaded at all.
function LoadImage(Stream: TStream; const MimeType: string; const AllowedImageClasses: array of TCastleImageClass) :TCastleImage; overload;
 
function LoadImage(const URL: string; const AllowedImageClasses: array of TCastleImageClass) :TCastleImage; overload;
 
function LoadImage(const URL: string; const AllowedImageClasses: array of TCastleImageClass; const ResizeToX, ResizeToY: Cardinal; const Interpolation: TResizeInterpolation = riNearest): TCastleImage; overload;
 
procedure SaveImage(const img: TCastleImage; const Format: TImageFormat; Stream: TStream); overload;

Save image to a file. Takes URL as parameter, you can give file URL or just a normal filename.

File format is determined by looking at URL (guessing MIME type using URIMimeType), or given explicitly as MimeType, or just given explicitly as Format parameter.

Image class does not affect the created image file format, on the assumption that the "memory format" of the image (what TCastleImage descendant is used) can be orthogonal to the actual "file format" used to save this file.

Tries to write the image preserving it as closely as possible in this image format. When it's not possible, according conversions may be done: floating point precision of TRGBFloatImage may be lost (if saving to any file format besides RGBE file, although saving to OpenEXR may also preserve it once implemented), alpha channel may be lost, grayscale may be expanded and such.

Although not absolutely all conversions are implemented for now. You can be sure that all image formats (that allow any saving at all) can be saved from TRGBImage. Also TRGBFloatImage can be saved to RGBE file. Also PNG format supports full collection (grayscale/rgb, alpha/no alpha are all perfectly possible in PNG file; and TRGBFloatImage will be just converted to 8-bit RGB before saving to PNG).

Exceptions raised
EImageSaveError
When it's not possible to save image, because of Img class (memory format) and/or image file format.
procedure SaveImage(const img: TCastleImage; const MimeType: string; Stream: TStream); overload;
 
procedure SaveImage(const Img: TCastleImage; const URL: string); overload;
 
procedure ImageAlphaConstTo1st(var Img: TCastleImage; const AlphaConst: byte);

Add and set constant alpha channel of given image. If image doesn't have alpha channel, we will create new Img instance (old instance will be freed) with colors copy. Alpha channel is then filled with AlphaConst

function ImageClassBestForSavingToFormat(const Format: TImageFormat): TCastleImageClass; overload;

Choose TCastleImage descendant best matching for this image file format. The only purpose of this for now is to pick TRGBFloatImage for RGBE files, chooses TRGBImage for anything else.

For the overloaded version with URL, file format is determined by guessing based on file extension.

function ImageClassBestForSavingToFormat(const URL: string): TCastleImageClass; overload;
 
procedure AlphaMaxTo1st(var A: TAlphaChannel; const B: TAlphaChannel);

Maximum alpha channel type. Chooses "full range" if anything is "full range", otherwise choose "simple yes/no" if anything is "simple yes/no", otherwise returns "no alpha channel".

Types

TAlphaChannel = (...);

See TCastleImage.AlphaChannel.

Values
  • acNone:  
  • acSimpleYesNo:  
  • acFullRange:  
TResizeInterpolation = (...);
 
Values
  • riNearest:  
  • riBilinear:  
TCastleImageList = specialize TFPGObjectList<TCastleImage>;
 
TEncodedImageList = specialize TFPGObjectList<TEncodedImage>;
 
TS3TCCompression = (...);
 
Values
  • s3tcDxt1_RGB: s3tcDxt1_RGB and s3tcDxt1_RGBA are the same compression method, except in s3tcDxt1_RGB the alpha information is ignored, while in s3tcDxt1_RGBA we have simple yes/no alpha.

    The difference is equivalent to OpenGL differences in treating

    • GL_COMPRESSED_RGB_S3TC_DXT1_EXT and

    • GL_COMPRESSED_RGBA_S3TC_DXT1_EXT.

  • s3tcDxt1_RGBA:  
  • s3tcDxt3: DXT3 and DXT5 are always treated like they had full-range alpha channel.
  • s3tcDxt5:  
TDecompressS3TCFunction = function (Image: TS3TCImage): TCastleImage;
 
TCastleImageClass = class of TCastleImage;
 
TEncodedImageClass = class of TEncodedImage;
 
TDynArrayImageClasses = array of TCastleImageClass;
 
TImageClass = TCastleImageClass deprecated;

Warning: this symbol is deprecated.

Deprecated name for TCastleImageClass.

TImage = TCastleImage deprecated;

Warning: this symbol is deprecated.

Deprecated name for TCastleImage.

TImageFormat = (...);
 
Values
  • ifPNG: We handle PNG file format fully, both reading and writing, through the libpng library.

    This format supports a full alpha channel. Besides PSD, this is the only format that allows full-range (partial transparency) alpha channel.

    Trying to read / write PNG file when libpng is not installed (through LoadImage, SaveImage, LoadPNG, SavePNG and others) will raise exception ELibPngNotAvailable. Note that the check for availability of libpng is done only once you try to load/save PNG file. You can perfectly compile and even run your programs without PNG installed, until you try to load/save PNG format.

  • ifBMP: We handle uncompressed BMP images.
  • ifPPM:  
  • ifJPEG: Image formats below are supported by FPImage.
  • ifGIF:  
  • ifTGA:  
  • ifXPM:  
  • ifPSD:  
  • ifPCX:  
  • ifPNM:  
  • ifDDS: We handle fully DDS (DirectDraw Surface) image format. See also TDDSImage class in DDS unit, this exposes even more features of the DDS image format.
  • ifRGBE: High-dynamic range image format, originally used by Radiance. See e.g. the pfilt and ximage programs from the Radiance package for processing such images.

    The float color values are encoded smartly as 4 bytes: 3 mantisas for RGB and 1 byte for an Exponent. This is the Greg Ward's RGBE color encoding described in the "Graphic Gems" (gem II.5). This allows high floating-point-like precision, and possibility to encode any value >= 0 (not necessarily <= 1), keeping the pixel only 4 bytes long.

    Encoding a color values with float precision is very useful. Otherwise, when synthesized / photographed images are very dark / very bright, simply encoding them in traditional fixed-point pixel format looses color precision. So potentially important but small differences are lost in fixed-point formats. And color values are clamped to [0..1] range. On the other hand, keeping colors as floats preserves everything, and allows to process images later.

    It's most useful and natural to load/save these files as TRGBFloatImage, this way you keep the floating-point precision inside memory. However, you can also load/convert such image format to normal 8-bits image formats (like TRGBImage), if you're Ok with losing some of the precision.

  • ifIPL:  
  • ifTIFF: Image formats below are supported by converting them "under the hood" with ImageMagick. This is available only if this unit is compiled with FPC (i.e. not with Delphi) on platforms where ExecuteProcess is implemented. And ImageMagick must be installed and available on $PATH.
  • ifSGI:  
  • ifJP2:  
  • ifEXR:  
TImageFormats = set of TImageFormat;
 
TImageLoadFunc = function (Stream: TStream; const AllowedImageClasses: array of TCastleImageClass): TCastleImage;
 
TImageSaveFunc = procedure (Img: TCastleImage; Stream: TStream);
 
TImageLoadHandledClasses = (...);

Possible TCastleImage classes that can be returned by Load method of this file format. It's assumed that appropriate Load can return only these classes, and any of these classes, and can convert between them.

If the LoadImage will be called allowing some TCastleImage descendants that can be returned by Load of this format, then LoadImage will pretty much just pass the call to Load for appropriate file format. The above is expected to be the most common and most efficient case. This way necessary conversion (e.g. adding alpha channel) can be done at the lowest level, right inside image format handler, which means that e.g. you can do it per-pixel, or by libpng transforms in case of PNG format.

Only when it's not possible (if, and only if, none of the AllowedImageClasses specified in LoadImage call can be returned by Load of this format) then LoadImage will try more elaborate approach. This means that it will try using Load of this image format, followed by some convertions of the image afterwards. This is generally less efficient, as it means that temporary image will be created during loading.

Values
  • lcRGB:  
  • lcRGB_RGBA:  
  • lcG_GA_RGB_RGBA:  
  • lcRGB_RGBFloat:  
TImageSaveHandledClasses = (...);

Possible TCastleImage classes supported by Save method of this file format.

Values
  • scRGB:  
  • scG_GA_RGB_RGBA:  
  • scRGB_RGBFloat:  
TImageFormatInfoMimeTypesCount = 1..6;

Index of TImageFormatInfo.MimeTypes array and type for TImageFormatInfo.MimeTypesCount. Implies that TImageFormatInfo.MimeTypes is indexed from 1, TImageFormatInfo.MimeTypesCount must be >= 1, so each file format must have at least one (treated as "default" in some cases) MIME type.

TImageFormatInfoExtsCount = 1..3;

A type to index TImageFormatInfo.Exts array and also for TImageFormatInfo.ExtsCount. So TImageFormatInfo.Exts array is indexed from 1, and TImageFormatInfo.ExtsCount must be >= 1, so each file format must have at least one (treated as "default" in some cases) file extension.

Constants

DefaultAlphaTolerance = 5;

Default parameters for TEncodedImage.AlphaChannel, decide how to detect textures alpha channel.

DefaultAlphaWrongPixelsTolerance = 0.01;
 
ImageFormatInfos: array [TImageFormat] of TImageFormatInfo = ( ( FormatName: 'PNG image'; MimeTypesCount: 1; MimeTypes: ('image/png', '', '', '', '', ''); ExtsCount: 1; Exts: ('png', '', ''); Load: @LoadPNG; LoadedClasses: lcG_GA_RGB_RGBA; Save: @SavePNG; SavedClasses: scG_GA_RGB_RGBA; ), ( FormatName: 'Windows BMP image'; MimeTypesCount: 1; MimeTypes: ('image/bmp', '', '', '', '', ''); ExtsCount: 1; Exts: ('bmp', '', ''); Load: @LoadBMP; LoadedClasses: lcRGB_RGBA; Save: @SaveBMP; SavedClasses: scRGB), ( FormatName: 'PPM image'; MimeTypesCount: 1; MimeTypes: ('image/x-portable-pixmap', '', '', '', '', ''); ExtsCount: 1; Exts: ('ppm', '', ''); Load: @LoadPPM; LoadedClasses: lcRGB; Save: @SavePPM; SavedClasses: scRGB; ), ( FormatName: 'JPEG image'; MimeTypesCount: 2; MimeTypes: ('image/jpeg', 'image/jpg', '', '', '', ''); ExtsCount: 3; Exts: ('jpg', 'jpeg', 'jpe'); Load: @LoadJPEG; LoadedClasses: lcRGB_RGBA; Save: @SaveJPEG; SavedClasses: scRGB ), ( FormatName: 'GIF image'; MimeTypesCount: 1; MimeTypes: ('image/gif', '', '', '', '', ''); ExtsCount: 1; Exts: ('gif', '', ''); Load: @LoadGIF; LoadedClasses: lcRGB_RGBA; Save: nil; SavedClasses: scRGB; ), ( FormatName: 'TarGA image'; MimeTypesCount: 2; MimeTypes: ('image/x-targa', 'image/x-tga', '', '', '', ''); ExtsCount: 2; Exts: ('tga', 'tpic', ''); Load: @LoadTGA; LoadedClasses: lcRGB_RGBA; Save: nil; SavedClasses: scRGB; ), ( FormatName: 'XPM image'; MimeTypesCount: 1; MimeTypes: ('image/x-xpixmap', '', '', '', '', ''); ExtsCount: 1; Exts: ('xpm', '', ''); Load: @LoadXPM; LoadedClasses: lcRGB_RGBA; Save: nil; SavedClasses: scRGB; ), ( FormatName: 'PSD image'; MimeTypesCount: 4; MimeTypes: ('image/photoshop', 'image/x-photoshop', 'image/psd', 'application/photoshop', '', ''); ExtsCount: 1; Exts: ('psd', '', ''); Load: @LoadPSD; LoadedClasses: lcRGB_RGBA; Save: nil; SavedClasses: scRGB; ), ( FormatName: 'ZSoft PCX image'; MimeTypesCount: 5; MimeTypes: ('image/pcx', 'application/pcx', 'application/x-pcx', 'image/x-pc-paintbrush', 'image/x-pcx', ''); ExtsCount: 1; Exts: ('pcx', '', ''); Load: @LoadPCX; LoadedClasses: lcRGB_RGBA; Save: nil; SavedClasses: scRGB; ), ( FormatName: 'PNM image'; MimeTypesCount: 6; MimeTypes: ('image/x-portable-anymap', 'image/x-portable-graymap', 'image/x-pgm', 'image/x-portable-bitmap', 'image/pbm', 'image/x-pbm'); ExtsCount: 3; Exts: ('pnm', 'pgm', 'pbm'); Load: @LoadPNM; LoadedClasses: lcRGB_RGBA; Save: nil; SavedClasses: scRGB; ), ( FormatName: 'DDS image'; MimeTypesCount: 1; MimeTypes: ('image/x-dds', '', '', '', '', ''); ExtsCount: 1; Exts: ('dds', '', ''); Load: @LoadDDS; LoadedClasses: lcG_GA_RGB_RGBA; Save: @SaveDDS; SavedClasses: scG_GA_RGB_RGBA; ), ( FormatName: 'RGBE (RGB+Exponent) image'; MimeTypesCount: 1; MimeTypes: ('image/vnd.radiance', '', '', '', '', ''); ExtsCount: 3; Exts: ('rgbe', 'pic', 'hdr'); Load: @LoadRGBE; LoadedClasses: lcRGB_RGBFloat; Save: @SaveRGBE; SavedClasses: scRGB_RGBFloat; ), ( FormatName: 'IPLab image'; MimeTypesCount: 1; MimeTypes: ('image/x-ipl', '', '', '', '', ''); ExtsCount: 1; Exts: ('ipl', '', ''); Load: @LoadIPL; LoadedClasses: lcRGB; Save: nil; SavedClasses: scRGB; ), ( FormatName: 'TIFF image'; MimeTypesCount: 1; MimeTypes: ('image/tiff', '', '', '', '', ''); ExtsCount: 2; Exts: ('tiff', 'tif', ''); Load: @LoadTIFF; LoadedClasses: lcRGB_RGBA; Save: nil; SavedClasses: scRGB; ), ( FormatName: 'SGI image'; MimeTypesCount: 3; MimeTypes: ('image/sgi', 'image/x-sgi', 'image/x-sgi-rgba', '', '', ''); ExtsCount: 1; Exts: ('sgi', '', ''); Load: @LoadSGI; LoadedClasses: lcG_GA_RGB_RGBA; Save: nil; SavedClasses: scRGB; ), ( FormatName: 'JPEG 2000 image'; MimeTypesCount: 4; MimeTypes: ('image/jp2', 'image/jpeg2000', 'image/jpeg2000-image', 'image/x-jpeg2000-image', '', ''); ExtsCount: 1; Exts: ('jp2', '', ''); Load: @LoadJP2; LoadedClasses: lcG_GA_RGB_RGBA; Save: nil; SavedClasses: scRGB; ), ( FormatName: 'EXR image'; MimeTypesCount: 1; MimeTypes: ('image/x-exr', '', '', '', '', ''); ExtsCount: 1; Exts: ('exr', '', ''); Load: @LoadEXR; LoadedClasses: lcG_GA_RGB_RGBA; Save: nil; SavedClasses: scRGB; ) );

Information about supported image formats.

Variables

DecompressS3TC: TDecompressS3TCFunction;

Assign here S3TC decompression function that is available. This way the "decompressor" is pluggable, which means that you can even use OpenGL to decompress S3TC textures, if you're going to load images while some OpenGL context is active.

LoadImage_FileFilters: TFileFilterList;

File filters if you want to choose a file that can be loaded/saved by appropriate functions from Images unit.

These objects should be treated as read-only outside this unit. Initialization / finalization of this unit automatically take care of them.

SaveImage_FileFilters: TFileFilterList;
 

Generated by PasDoc 0.13.0 on 2013-08-17 21:27:12