Image class
The base class of Bitmap and Metafile: a picture loaded from a file or a stream, with its size, resolution, pixel format and properties.
An Image holds either raster data or a recorded sequence of drawing commands. Bitmap and Metafile inherit every member described here and add the members that work on one kind of picture. A program creates an Image directly to load a file whose kind it does not know, and uses Type to find out which kind it got. The class mirrors the GDI+ Image class.
- Creating
- Saving
- Size and format
- Palette
- Thumbnails
- Frames
- Properties of a file
- Items of image data
- Example
- See Also
Note 0.9.45.0
A project that references the VB package (every default project does) also has a VB control class named Image. A bare Image in a declaration means the VB class, so write GdiPlus.Image for the class and for the function that creates it, as the samples on this page do. Bitmap and Metafile have no such clash.
Creating
Syntax: img = GdiPlus.Image( filename [ , useEmbeddedColorManagement ] )
Syntax: img = New GdiPlus.Image( filename [ , useEmbeddedColorManagement ] )
Syntax: img = GdiPlus.Image( stream [ , useEmbeddedColorManagement ] )
Syntax: img = GdiPlus.FromFile( filename [ , useEmbeddedColorManagement ] )
- filename
- required A String naming an image file. GDI+ decodes the formats that ImageCodec lists, and metafiles. The file stays open until the Image is released.
- stream
- required An IStream to read the picture from.
- useEmbeddedColorManagement
- optional A Boolean. True applies the colour profile stored in the file. The default is False.
The three forms with the same name are one thing: the function creates the object with the same arguments as New. FromFile is another name for the function. A constructor that fails creates an unusable object whose LastResult tells why. Loading a missing file gives OutOfMemory, which is how GDI+ reports a file it cannot open.
An Image that holds a bitmap is not a Bitmap: it has no pixel access. To read or change pixels, load the file with Bitmap instead.
Dim user As GdiPlusUser = GdiPlusUser()
Dim bmp As Bitmap = Bitmap(16!, 8!)
Dim g As Graphics = Graphics(bmp)
g.Clear(Color(255, 200, 100, 50))
Dim dir As String = Environ$("TEMP") & "\tbdocs-gdiplus-image"
ImagePageSaver.MakeDir dir
Dim path As String = dir & "\sample.png"
Debug.Print ImagePageSaver.SavePng(bmp, path)
Dim img As GdiPlus.Image = GdiPlus.Image(path)
Debug.Print img.LastResult & " " & img.Width & " " & img.Height & " " & img.Type
Dim missing As GdiPlus.Image = GdiPlus.Image(dir & "\no-such-file.png")
Debug.Print missing.LastResult
' Output:
' 0
' 0 16 8 1
' 3
Clone
Syntax: copy = img.Clone( )
Returns a new Image that holds a copy of the picture. The copy is an Image, even when the original is a Bitmap or a Metafile.
Note 0.9.45.0
Bitmap and Metafile declare their own Clone, and on a Bitmap the no-argument form is not available: the call does not compile. To copy a whole Bitmap, use Bitmap.Clone with the full rectangle.
Saving
Save writes the picture to a file or a stream with one of the encoders listed by ImageCodec. clsidEncoder is the class ID of the encoder: ImageCodecPNG, ImageCodecJPG and the others are functions that return it.
Save
Syntax: status = img.Save( filename, clsidEncoder, encoderParams( ) )
Syntax: status = img.Save( stream, clsidEncoder, encoderParams( ) )
- filename
- required A String naming the file to write. An existing file is replaced.
- stream
- required An IStream to write to.
- clsidEncoder
- required The class ID of the encoder, which also selects the file format.
- encoderParams
- required An array of GpEncoderParameter. The call expects its lower bound to be 0, and element 0 to be a dummy that is not filled in; the parameters follow from element 1. Any other lower bound returns InvalidParameter.
Warning 0.9.45.0
Save does not work with an encoder parameter array. The call stores the parameter count in memory that lies before the array, and gives GDI+ a pointer to that place, so GDI+ reads its parameters from memory the array does not own. With Dim ep(0 To 0) As GpEncoderParameter the call returns InvalidParameter and leaves an empty file. With a longer array it returns Ok in 64-bit programs while GDI+ ignores the parameters (a JPEG saved with a quality of 10 has the same size as one saved with 100), and in 32-bit programs it raises an access violation or does not return. SaveAdd and SaveAddImage build their argument in the same way. Bitmap shows how to write a PNG without calling Save.
SaveAdd
Syntax: status = img.SaveAdd( encoderParams( ) )
Syntax: status = img.SaveAddImage( newImage, encoderParams( ) )
Adds a frame to a file that an earlier Save started with the EncoderSaveFlag parameter set to multi-frame. SaveAdd adds the frame of the picture itself; SaveAddImage adds the frame of newImage, an Image. Both take encoderParams as Save does, and are subject to the same warning.
Size and format
Type
Syntax: t = img.Type
Returns a GpImageType: ImageTypeBitmap for raster data and ImageTypeMetafile for a recording. The property is read-only.
Width, Height, Size
Syntax: w = img.Width
Syntax: h = img.Height
Syntax: s = img.Size
Width and Height return the size in pixels as a Long. Size returns both in a GpSize. For a metafile the numbers are the size of the bounds in device units.
Dimension
Syntax: d = img.Dimension
Returns the width and height as a GpSizeF in the unit of the picture, which for a bitmap is the pixel and for a metafile depends on its frame.
Bounds
Syntax: r = img.Bounds( srcUnit )
- srcUnit
- required A GpUnit giving the unit of the returned rectangle.
Returns a GpRectF whose upper left corner is (0, 0) for a bitmap and whose size is the size of the picture in srcUnit.
Dim user As GdiPlusUser = GdiPlusUser()
Dim bmp As Bitmap = Bitmap(8!, 6!)
Debug.Print bmp.Type & " " & bmp.Width & " " & bmp.Height
Debug.Print bmp.Size.Width & " " & bmp.Size.Height
Debug.Print bmp.Dimension.Width & " " & bmp.Dimension.Height
Dim b As GpRectF = bmp.Bounds(UnitPixel)
Debug.Print b.X & " " & b.Y & " " & b.Width & " " & b.Height
' Output:
' 1 8 6
' 8 6
' 8 6
' 0 0 8 6
HorizontalResolution, VerticalResolution
Syntax: dpi = img.HorizontalResolution
Syntax: dpi = img.VerticalResolution
Return the resolution in dots per inch as a Single. A new bitmap takes the resolution of the screen, so the number differs between machines. Set it with Bitmap.SetResolution.
PixelFormat
Syntax: fmt = img.PixelFormat
Returns the PixelFormat of the picture. A bitmap created without a format has PixelFormat32bppARGB.
Flags
Syntax: flags = img.Flags
Returns a combination of ImageFlags values as a Long: whether the picture scales, has alpha or translucent pixels, its colour space and whether its resolution and size come from the file.
RawFormat
Syntax: id = img.RawFormat
Returns the class ID of the file format the picture was loaded from, as a UUID. Compare it with the values that the format functions return, such as ImageFormatPNG. A picture created in memory has ImageFormatMemoryBMP.
Dim user As GdiPlusUser = GdiPlusUser()
Dim bmp As Bitmap = Bitmap(4!, 4!)
Debug.Print Hex$(bmp.PixelFormat)
Debug.Print Hex$(bmp.Flags)
Debug.Print bmp.RawFormat.Data1 = ImageFormatMemoryBMP().Data1
' Output:
' 26200A
' 2
' True
Palette
PaletteSize
Syntax: n = img.PaletteSize
Returns the size in bytes of the colour palette of the picture, which is 0 or a small header for a picture without a palette and 1032 for a bitmap in the PixelFormat8bppIndexed format.
Palette
Syntax: pal = img.Palette
Syntax: img.Palette = pal
The getter is meant to return the palette as an array of ColorPalette, and the setter to take one.
Warning 0.9.45.0
Reading Palette overflows the stack, in 32-bit and 64-bit programs, and the process stops. The setter calls the GDI+ function that reads a palette, not the one that writes it, and so does not change the picture. To get a palette, use ImageAttributes.GetAdjustedPalette or fill a ColorPalette yourself, and give it to Bitmap.ConvertFormat.
Thumbnails
GetThumbnail
Syntax: thumb = img.GetThumbnail( thumbSize [ , callback [ , callbackData ] ] )
Syntax: thumb = img.GetThumbnail( thumbWidth, thumbHeight [ , callback [ , callbackData ] ] )
- thumbSize
- required A GpSize with the size of the thumbnail in pixels.
- thumbWidth, thumbHeight
- required Long values for the same size.
- callback
- optional A callback that GDI+ can call to ask whether it should stop. Omit it.
- callbackData
- optional A pointer passed to callback. The default is 0.
Returns a new Image of the requested size, or Nothing when the call fails. The thumbnail is the embedded one when the file has one, and a scaled copy of the picture otherwise.
Dim user As GdiPlusUser = GdiPlusUser()
Dim bmp As Bitmap = Bitmap(40!, 20!)
Dim thumb As GdiPlus.Image = bmp.GetThumbnail(10, 5)
Debug.Print bmp.LastResult & " " & thumb.Width & " " & thumb.Height
' Output:
' 0 10 5
Frames
An image file can hold several frames, such as the pages of a TIFF or the pictures of an animated GIF. Frames are grouped in dimensions; the identifiers are the functions FrameDimensionTime, FrameDimensionPage and FrameDimensionResolution.
FrameDimensionsCount
Syntax: n = img.FrameDimensionsCount
Returns the number of frame dimensions the picture has. A bitmap created in memory has one: the page dimension.
GetFrameDimensionsList
Syntax: ids = img.GetFrameDimensionsList( )
Returns the class IDs of the frame dimensions as an array of UUID that starts at 1.
FrameCount
Syntax: n = img.FrameCount( dimensionID )
- dimensionID
- required The class ID of a frame dimension, such as FrameDimensionPage( ).
Returns the number of frames in that dimension.
SelectActiveFrame
Syntax: status = img.SelectActiveFrame( dimensionID, frameIndex )
- dimensionID
- required The class ID of a frame dimension.
- frameIndex
- required The index of the frame to select, counted from 0.
Makes the frame the one that drawing and the size properties use.
Dim user As GdiPlusUser = GdiPlusUser()
Dim bmp As Bitmap = Bitmap(4!, 4!)
Debug.Print bmp.FrameDimensionsCount
Debug.Print bmp.FrameCount(FrameDimensionPage())
Debug.Print bmp.GetFrameDimensionsList()(1).Data1 = FrameDimensionPage().Data1
Debug.Print bmp.SelectActiveFrame(FrameDimensionPage(), 0)
' Output:
' 1
' 1
' True
' 0
RotateFlip
Syntax: status = img.RotateFlip( rotateFlipType )
- rotateFlipType
- required A RotateFlipType giving a rotation, a flip, or both. The picture is rotated first.
Rotates and flips the picture in place. A rotation is clockwise. After a rotation by 90 or 270 degrees the width and height are exchanged.
Dim user As GdiPlusUser = GdiPlusUser()
Dim bmp As Bitmap = Bitmap(4!, 3!)
bmp.Pixel(0, 0) = Color(255, 255, 0, 0) ' upper left corner
bmp.RotateFlip Rotate90FlipNone
Debug.Print bmp.Width & " " & bmp.Height
Debug.Print Hex$(bmp.Pixel(2, 0).argb) ' the red pixel is now at the upper right
bmp.RotateFlip Rotate270FlipNone
bmp.RotateFlip RotateNoneFlipX
Debug.Print Hex$(bmp.Pixel(3, 0).argb) ' flipped across the vertical axis
' Output:
' 3 4
' FFFF0000
' FFFF0000
Properties of a file
An image file can hold named properties: the camera model of a photograph, the time it was taken, the delay of a GIF frame. Each has a numeric ID, and the PropertyTag... constants of the package name the IDs of the common ones. A property is a GpPropertyItem.
PropertyCount
Syntax: n = img.PropertyCount
Returns the number of properties the picture has.
PropertyIdList
Syntax: ids = img.PropertyIdList
Returns the IDs of the properties as an array of Long that starts at 1.
PropertyItem
Syntax: items = img.PropertyItem( propId )
Syntax: img.PropertyItem = item
The getter returns the property with the ID propId as an array of GpPropertyItem that holds one element, at index 1. The setter takes one GpPropertyItem and sets that property on the picture, adding it when it is not there. Its Id, type, length and the address of its value must be filled in.
Warning 0.9.45.0
Reading an element of the array that PropertyItem returns stops the process with an access violation, because the array is built in a way that the element access cannot use. Only UBound and LBound of the array work. GetAllPropertyItems returns its array in the same way and has the same defect. The setter, PropertyCount, PropertyIdList and RemovePropertyItem work.
RemovePropertyItem
Syntax: status = img.RemovePropertyItem( propId )
Removes the property with that ID.
GetAllPropertyItems
Syntax: items = img.GetAllPropertyItems( )
Returns all properties as an array of GpPropertyItem. See the warning under PropertyItem.
Dim user As GdiPlusUser = GdiPlusUser()
Dim bmp As Bitmap = Bitmap(4!, 4!)
Dim text() As Byte = StrConv("A test picture" & vbNullChar, vbFromUnicode)
Dim item As GpPropertyItem
item.Id = PropertyTagImageDescription
item._type = PropertyTagTypeASCII
item._length = UBound(text) + 1
item._address = VarPtr(text(0))
bmp.PropertyItem = item
Debug.Print bmp.LastResult & " " & bmp.PropertyCount
Debug.Print Hex$(bmp.PropertyIdList()(1))
Debug.Print bmp.RemovePropertyItem(PropertyTagImageDescription)
Debug.Print bmp.PropertyCount
' Output:
' 0 1
' 10E
' 0
' 0
GetEncoderParameterList
Syntax: params = img.GetEncoderParameterList( clsidEncoder )
Returns the parameters that the encoder with the class ID clsidEncoder accepts for this picture, as an array of GpEncoderParameter.
Warning 0.9.45.0
GetEncoderParameterList stops the process with an access violation in 32-bit and 64-bit programs. The call hands GDI+ the address of a temporary variable in place of the buffer, so GDI+ overwrites the stack.
Items of image data
Some formats store data beside the pixels. FindFirstItem, FindNextItem and GetItemData enumerate and read it, with a GpImageItemData in an array of one element. These members need GDI+ 1.1 and Windows 7 or later, and only the codecs that provide such data return any. The array is built as for PropertyItem, so its element cannot be read.
FindFirstItem
Syntax: item = img.FindFirstItem( )
FindNextItem
Syntax: item = img.FindNextItem( )
GetItemData
Syntax: status = img.GetItemData( item( ) )
FindFirstItem and FindNextItem return the first and the following item as an array of one GpImageItemData. GetItemData reads the data of the item in the array that is passed to it.
SetAbort
Syntax: status = img.SetAbort( pIAbort )
GDI+ declares this function, but does not implement it in versions 1.0 and 1.1: it does nothing useful. The argument is a GdiPlusAbort object.
Example
The example makes a small picture, rotates and flips it, and reads the results back.
Dim user As GdiPlusUser = GdiPlusUser()
Dim bmp As Bitmap = Bitmap(6!, 2!)
Dim g As Graphics = Graphics(bmp)
g.Clear(Color(255, 255, 255, 255))
bmp.Pixel(0, 0) = Color(255, 0, 0, 255)
Dim copy As GdiPlus.Image = bmp
Debug.Print copy.Width & "x" & copy.Height & " " & copy.Type
bmp.RotateFlip Rotate180FlipNone
Debug.Print Hex$(bmp.Pixel(5, 1).argb)
' Output:
' 6x2 1
' FF0000FF
See Also
- Image – Microsoft’s documentation of the GDI+ class
- Bitmap class
- Metafile class
- ImageAttributes class
- ImageCodec – encoders, decoders and the identifiers they use
- GpPropertyItem type
- GpEncoderParameter type