Images
This page has been automatically translated using the Google Translate API services. We are working on improving texts. Thank you for your understanding and patience.
Functions
Image* | image_from_pixels (...) |
Image* | image_from_pixbuf (...) |
Image* | image_from_file (...) |
Image* | image_from_data (...) |
const Image* | image_from_resource (...) |
Image* | image_copy (...) |
Image* | image_trim (...) |
Image* | image_rotate (...) |
Image* | image_scale (...) |
Image* | image_read (...) |
bool_t | image_to_file (...) |
void | image_write (...) |
void | image_destroy (...) |
pixformat_t | image_format (...) |
uint32_t | image_width (...) |
uint32_t | image_height (...) |
Pixbuf* | image_pixels (...) |
bool | image_codec (...) |
codec_t | image_get_codec (...) |
uint32_t | image_num_frames (...) |
real32_t | image_frame_length (...) |
void | image_data (...) |
type* | image_get_data (...) |
void* | image_native (...) |
There is a close relationship between pixel buffers and images. Although the firsts contain "raw" color information, the latter are objects directly linked to the graphical API of each system, which allows them to be drawn in 2d contexts or viewed in a window (Figure 1).
The structure of a digital image, also called bitmap or raster graphics, is the same as that of a buffer pixel. We have a discrete grid of color dots characterized by its resolution (width, height) and depth, which is the amount of bits needed to encode each pixel (Figure 2). bitmap images work best for taking snapshots of the real world, where it is practically impossible to describe the scene using geometric primitives, as we saw in Drawing primitives. On the other hand, as it is composed of discrete points, it does not behave well in the face of changes in size where it will suffer a loss of quality.
1. Load and view images
In most cases, the only thing we will need to know about images will be how to read them from disk or other data source and then display them on the screen as part of the user interface (Listing 1) (Figure 3). We consider that the images are stored in one of the standard formats: JPG, PNG, BMP or GIF.
1 2 3 4 5 |
Image *img = image_from_file("lenna.jpg", NULL); Image *icon = image_from_resource(pack, ekCANCEL); ... imageview_image(view, img); button_image(button, icon); |
- Use image_from_file to load an image from disk.
- Use image_from_data to create an image from a memory buffer.
- Use image_from_resource to get a picture of a resource package.
- Use image_read to create an image from Streams.
- In the demo UrlImg you have an example of how to download them from a Web server.
Once the image object is loaded in memory, we have several ways to view it:
- Use draw_image to draw an image in a 2d context.
- Use imageview_image to assign an image to a view.
- Use button_image to assign an image to a button.
- Use popup_add_elem to assign a text and icon to a drop-down list.
2. Generate images
As we saw in 2D Contexts, if necessary we can create our own images from drawing commands to later display them in the interface (Figure 4) or save them to disk.
- Use dctx_image to create an image from a 2d context.
3. Pixel access
Images are immutable objects optimized for recurring on-screen drawing, so certain licenses are allowed, both in the internal organization of color information and in the management of possible copies. For this reason it is not possible to directly manipulate the pixels, but we must access them using a Pixel Buffer.
- Use image_from_pixels to create an image from the color information.
- Use image_from_pixbuf to create an image from a pixel buffer.
- Use image_pixels to get a buffer with the pixels of the image.
- Use image_width to get the width.
- Use image_height to get the height.
- Use image_format to get the pixel format.
Apple technical documentation: "Treat NSImage and its image representations as immutable objects. The goal of NSImage is to provide an efficient way to display images on the target canvas. Avoid manipulating the data of an image representation directly, especially if there are alternatives to manipulating the data, such as compositing the image and some other content into a new image object."
The pixel buffers allow us to optimally manipulate the content of the image. To view the result or store it in any of the supported formats, we must create a new image (Figure 5).
4. Save images: Codecs
One of the biggest problems of digital images is the large amount of memory they need. An image of only 1024x768 pixels and 32 bits of color needs 3 megabytes of memory. It may not seem like much, but at the end of the 80s this was a great handicap since memory was very expensive and transmissions were very slow. This is why several coding (compression) systems were devised that reduced the amount of memory needed and that were consolidated with the rise of the Internet (Figure 6).
- Use image_get_codec to get the codec associated with the image.
- Use image_codec to change the codec associated with the image.
- Use image_to_file to save it to disk.
- Use image_write to write it in a Stream.
Draw2D does not natively support other formats than those mentioned. If necessary, you will have to find a way to create a Pixbuf
from the specific data of your format, in order to integrate these images into the user interface.
- JPEG: Joint Photographic Experts Group is a format with a very good compression rate based on the Fourier Transform. Ideal for capturing real-world snapshots, although it will detract some quality from the original capture (lossy compression).
- PNG: Portable Network Graphics emerged in response to legal problems with the GIF format. Supports lossless LZ77/Deflate compression and indexed pixel formats. Ideal for computer generated diagrams, graphics or images.
- GIF: Graphics Interchange Format uses the proprietary compression algorithm LZW, although the patent expired in 2003. It has survived PNG because it can include animations in a single file, something that neither of the two previous formats supports.
- BMP: BitMaP. Windows native format widely surpassed by the other three. Although it supports a special type of compression called Run-Length encoding, the truth is that most files are saved uncompressed. BMP files take up much more space, for this reason very little is used on the Internet and almost nothing on non-Windows machines. It is supported by almost all programs and systems because it is very simple an fast to interpret.
To be able to display on the screen, the image must be decompressed (de-encoded), a process that is performed automatically when reading the image. When saving it to disk or sending it over the network, the opposite process is performed, compressed or encoded using the algorithm associated with it (Table 1), but it can be changed.
Constructor | Codec |
image_from_file | The original codec. |
image_from_data | The original codec. |
image_from_resource | The original codec. |
image_from_pixels | Transparencies? Yes:ekPNG No:ekJPG. |
dctx_image | ekPNG. |
Generally, GDI+, NSImage or GdkPixbuf support for codec settings is quite limited. For example, it is not possible to generate indexed PNG files, which is very useful when reducing the size of images for the web. If the application requires more control over the export, we will have no choice but to use libpng, libjpeg or any other third-party solution.
image_from_pixels ()
Create an image from an array of pixels.
Image* image_from_pixels(const uint32_t width, const uint32_t height, const pixformat_t format, const byte_t *data, const color_t *palette, const uint32_t palsize);
width | The image width (in pixels). |
height | The image height (in pixels). |
format | Pixel format. |
data | Buffer that contains the color value of each pixel. It will depend on the resolution and format. |
palette | Color palette required to render indexed images. If it is |
palsize | Number of colors in the palette. |
Return
The image.
Remarks
See Pixel access.
image_from_pixbuf ()
Create an image from a buffer pixel.
Image* image_from_pixbuf(const Pixbuf *pixbuf, const Palette *palette);
pixbuf | The buffer. |
palette | The palette. |
Return
The image.
Remarks
Equal to image_from_pixels avoiding indicating parameters separately.
image_from_file ()
Create an image from a file on disk.
Image* image_from_file(const char_t *pathname, ferror_t *error);
pathname | The file path. Filename and pathname. |
error | Error code if the function fails. Can be |
Return
The image.
Remarks
Only formats jpg, png, bmp and gif are accepted.
image_from_data ()
Create an image from a buffer containing the encoded data.
Image* image_from_data(const byte_t *data, const uint32_t size);
data | The buffer with the image data. |
size | The buffer size in bytes. |
Return
The image.
Remarks
The buffer represents data encoded in jpg, png, bmp or gif. To create the image directly from pixels use image_from_pixels.
image_from_resource ()
Get an image of a resource package.
const Image* image_from_resource(const ResPack *pack, const ResId id);
pack | The resource package. |
id | The resource identifier. |
Return
The image.
Remarks
The image should not be destroyed with image_destroy as it is part of the package itself (it is constant). Make a copy with image_copy in case it needs to be kept after destroying the resources. See Resources.
image_copy ()
Create a copy of the image.
Image* image_copy(const Image *image);
image | The source image. |
Return
The image copy.
Remarks
Images are immutable objects. Copying really means increasing an internal counter without cloning the object. However, the application must destroy the copy with image_destroy just like those created with any other constructor. When all copies are destroyed, it will actually be removed from memory.
image_trim ()
Create an image by cropping another image.
Image* image_trim(const Image *image, const uint32_t x, const uint32_t y, const uint32_t width, const uint32_t height);
image | The source image. |
x | X coordinate of the origin of the sub-image. |
y | Y coordinate of the origin of the sub-image. |
width | Width in pixels of the sub-image. |
height | Height in pixels of the sub-image. |
Return
The new image.
image_rotate ()
Create a new image by rotating an existing one.
Image* image_rotate(const Image *image, const real32_t angle, const bool_t nsize, const color_t background, T2Df *t2d);
image | The original image. |
angle | Angle in radians. |
nsize |
|
background | Background color. The new image will have "blank" areas due to rotation. |
t2d | Saves the transformation applied to the image. They can be |
Return
The newly created image.
image_scale ()
Create a copy of the image, with a new size.
Image* image_scale(const Image *image, const uint32_t nwidth, const uint32_t nheight);
image | The source image. |
nwidth | The width of the new image. Pass UINT32_MAX so that the aspect ratio with respect to |
nheight | The height of the new image. Pass UINT32_MAX so that the aspect ratio with respect to |
Return
The image.
Remarks
If both values nwidth
, nheight
are UINT32_MAX
or the new dimensions are identical to the current ones, the internal reference counter will increase, as is the case in image_copy.
image_read ()
Create an image from the data read from a Streams.
Image* image_read(Stream *stm);
stm | Input stream. Data encoded in jpg, png, bmp or gif are expected. The function detects the format automatically. |
Return
The image.
image_to_file ()
Save an image to disk, using the codec associated with it.
bool_t image_to_file(const Image *image, const char_t *pathname, ferror_t *error);
image | The image. |
pathname | The path of the destination file. Filename and pathname. |
error | Error code if the function fails. Can be |
Return
TRUE
if it was saved correctly or FALSE
and an error has occurred.
Remarks
Use image_codec to change the default codec.
image_write ()
Write an image in an output stream, using the codec associated with it.
void image_write(Stream *stm, const Image *image);
stm | Writing stream. Data encoded in jpg, png, bmp or gif will be written. |
image | The image. |
Remarks
Use image_codec to change the default codec.
image_destroy ()
Destroy the image.
void image_destroy(Image **image);
image | The image. Will be set to |
image_format ()
Get the pixel format of the image.
pixformat_t image_format(const Image *image);
image | The image. |
Return
Pixel format.
image_width ()
Get the width of the image in pixels.
uint32_t image_width(const Image *image);
image | The image. |
Return
Number of pixels wide.
image_height ()
Get the height of the image in pixels.
uint32_t image_height(const Image *image);
image | The image. |
Return
Number of pixels in height.
image_pixels ()
Get a buffer with the pixels that make up the decoded image.
Pixbuf* image_pixels(const Image *image, const pixformat_t format);
image | The image. |
format | The required pixel format. |
Return
Pixel buffer with image content.
Remarks
If in pixformat
we indicate ekFIMAGE it will return the buffer with the original format of the image. We can indicate ekRGB24, ekRGBA32 or ekGRAY8 if we need a specific format. Cannot use indexed formats.
image_codec ()
Change the default codec associated with the image.
bool image_codec(const Image *image, const codec_t codec);
1 2 3 4 |
Image *img = image_from_file("lenna.jpg", NULL); Stream *stm = stm_socket(ip, port, NULL, NULL); image_codec(img, ekPNG); image_write(socket, img); |
image | The image. |
codec | The new codec. |
Return
TRUE
if the graphical API supports the selected codec. FALSE
otherwise.
Remarks
The change will take effect the next time we save or write the image. By default, the image retains the codec with which it was read. When we create it with image_from_pixels ekJPG codec is assigned as default. For images from 2d contexts dctx_image, the default codec is ekPNG. All codecs are supported by all graphical APIs, except ekGIF in some versions of Linux. Check the return value if it is imperative that your application export images in GIF.
image_get_codec ()
Get the codec associated with the image.
codec_t image_get_codec(const Image *image);
image | The image. |
Return
El codec.
Remarks
See image_codec.
image_num_frames ()
Get the number of sequences in animated images.
uint32_t image_num_frames(const Image *image);
image | The image. |
Return
The number of sequences or frames.
Remarks
Only the gif format supports animations. For the rest 1 will always be returned.
image_frame_length ()
Get the time of an animation sequence.
real32_t image_frame_length(const Image *image, const uint32_t findex);
image | The image. |
findex | The frame index. |
Return
Sequence time in seconds.
Remarks
Only gif format supports animations.
image_data ()
Link user data with the image.
void image_data(Image *image, type *data, FPtr_destroy func_destroy_data, type );
image | The image. |
data | The user data. |
func_destroy_data | Destructor of user data. |
User data type. |
image_get_data ()
Gets the user data of the image.
type* image_get_data(const Image *image, type );
image | The image. |
User data type. |
Return
The user data.
image_native ()
Gets the image in the native format of each platform.
void* image_native(const Image *image);
image | The image. |
Return
The native image. Gdiplus::Bitmap
in Windows, GdkPixbuf
in Linux and NSImage
in macOS.