Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Pierre Joye edited this page Aug 13, 2021 · 32 revisions

Key Features

True 32bits Surface

New Surface/Image buffer format

The array of bytes for TrueColor or palette images have penalized GD for a while now. Performance to access the data and interface with other libraries. It is time to have actual image data a continuous buffer+stride along with new image formats (next two sections).

Start of basic Surface support available in the branch features/surface with:

  • Example at examples/surface.c (open in alpha aware app to see the full alpha)
  • Basic PNG export for ARGB32 or XRGB32 only
#include "gd.h"
#include <stdio.h>
#include <stdlib.h>

void save_png(gdSurfacePtr surface, const char *filename)
{
    FILE *fp;
    fp = fopen(filename, "wb");
    if (!fp)
    {
        fprintf(stderr, "Can't save png image %s\n", filename);
        return;
    }
    gdSurfacePng(surface, fp);
    fclose(fp);
}

int main()
{
    gdSurface *surface;
    unsigned char *data;
    surface = gdSurfaceCreate(500, 500, GD_SURFACE_ARGB32);

    // If this data is somehow passed around and used in other places
    // caller is responsible to call gdSurfaceAddRef to keep it from
    // being destroyed. gdSurfaceDestroy decreases the refcount, when reach
    // 0 it is actually freed
    data = gdSurfaceGetData(surface);
    int x = 100;
    for (int y = 100; y < 150; y++)
    {
        unsigned int *img = (unsigned int *)(data + surface->stride * y);
        for (int x = 100; x < 150; x++)
        {
            img[x] = 0x80FF0000;
        }
    }
    for (int y = 200; y < 350; y++)
    {
        unsigned int *img = (unsigned int *)(data + surface->stride * y);
        for (int x = 200; x < 350; x++)
        {
            img[x] = 0xFF00FF00;
        }
    }
    for (int y = 400; y < 450; y++)
    {
        unsigned int *img = (unsigned int *)(data + surface->stride * y);
        for (int x = 400; x < 450; x++)
        {
            img[x] = 0x300000FF;
        }
    }
    if (!surface)
    {
        fprintf(stderr, "Can't create 400x400 surface\n");
        return 1;
    }

    save_png(surface, "surface.png");

    gdSurfaceDestroy(surface);
    return 0;
}
struct {
    unsigned char* data; // surface buffer
    int format; // GD_SURFACE_ARGB32, GD_SURFACE_XRGB32, GD_SURFACE_A8
    int gdOwned; // Data allocated by libGD
    int width; // width of the surface
    int height; // height of the surface
    int stride; // offset to reach next row
    int ref; // Reference counter (pattern filling f.e.)
}

ARGB 32 bit

No transparent color (like in truecolor or palette). Only using (A)RGB values. Each image format exports can have specific options if they support transparent color index or value.

premultiplied

Premultiplied 32bit argb is a kind of a must. Most other libraries for advanced rastering use this format. It is also what GUI apps (X or other rely on).

RGB 24 Bit

RGB surface, no alpha channel. XRGB as encoding. We may add 16/24/32bits surface gray levels at some point. Same concept but it will need int * or other types for the surface's buffer.

8 bit

8 bit gray level. Can be used for gray level or one surface per channel image.

APIs

Create a surface, data allocated by libGd.

gdSurface * gdSurfaceCreate(int32_t width, int32_t width, uint32_t format);

Create a surface, data allocated by caller.

gdSurface * gdSurfaceCreateForData(unsigned char *data, int32_t width, int32_t width, int32_t stride, uint32_t format);

Destroy a surface. Do we need to have a callback for freeing the data? (ie if ref>1 and the data cannot be destroyed, it can be referenced in a pattern or other contexts).

void gdSurfaceDestroy(gdSurface *surface);

Clear a surface using optional color. If not white full transparency by default (NULL passed).

gdSurfaceClear(gdSurface *surface, gdColor *color);

Get a pointer to the data, to pass to another library, GUI, etc.

unsigned char * gdSurfaceGetData(gdSurface *surface);

Implementation status

API Group Name Status
Core
gdSurfaceCreate Done
gdSurfaceDestroy Done
gdSurfaceCreateForData Done
gdSurfaceAddRef Done
gdSurfaceGetType Done
gdSurfaceGetWidth Done
gdSurfaceGetHeight Done
gdSurfaceGetStride Done
Codecs
PNG
gdSurfaceCreateFromPng Done
gdSurfaceCreateFromPngPtr Done
gdSurfaceCreateFromPngCtx Done
gdSurfacePng Done
gdSurfacePngEx Done
gdSurfacePngCtx Done
WebP
gdSurfaceWebp Done
gdSurfaceWebpPtr Done
gdSurfaceWebpPtrEx Done
gdSurfaceWebpEx Done
gdSurfaceWebpCtx Done
gdSurfaceCreateFromWebpCtx Done
gdSurfaceCreateFromWebp Done
gdSurfaceCreateFromWebpPtr Done
Jpeg
gdSurfaceJpeg Done
gdSurfaceJpegPtr Done
gdSurfaceJpegCtx Done
gdSurfaceCreateFromJpeg Done
gdSurfaceCreateFromJpegEx Done
gdSurfaceCreateFromJpegCtxEx Done
HEIF
gdSurfaceHeif Done
gdSurfaceHeifPtr Done
gdSurfaceHeifEx Done
gdSurfaceHeifCtx Done
gdSurfaceCreateFromHeif Done
gdSurfaceCreateFromJpegCtxEx Done
gdSurfaceCreateFromHeifCtx Done
TIFF TBD
GIF TBD
TGA TBD
BMP TBD
WBMP TBD
AVIF TBD
XPM TBD
BMP TBD

Use of advance vector raster

High quality rendering is still a key feature we miss. However it may not be worth implement it half way ourselves (f.e. using Freetype Rasterizer). I have some code I will push to a branch in the next couple of weeks for 2 libraries (one with JIT and one standard simple 2D raster).

Primitives and helpers work with double coordinates. This allows subpixel positioning and rendering. Antitaliasing will show actual coverage based on the coordinates of each path.

The first implementation using Freetype Raster has been pushed to https://github.com/libgd/libgd/blob/features/surface/

These images are rendered using it:

curved Rectangle

Path Clipped Tiger head

See https://github.com/libgd/libgd/wiki/GD-Draw,-vector-based-drawing-APIs for implementation status and in details documentation.

Core Primitives

  • gdPathMoveTo(double x, double y) move to position
  • gdPathLineTo(double x, double y) line from current point to (x,y)
  • gdPathQuadTo(double x1, double y1, double x2, double y2) Quadratic curve
  • gdPathCubicTo(double x1, double y1, double x2, double y2, double x3, double y3) cubic Bézier spline
  • gdPathArcTo(double x1, double y1, double x2, double y2, double radius); add an arc to the path
  • gdPathClose() close current path (line)

Relative Primitives

Same as main function but coordinates are relatives to the current positions

  • gdPathRelMoveTo(double x, double y)
  • gdPathRelLineTo(double x, double y)
  • gdPathRelQuadTo(double x1, double y1, double x2, double y2)
  • gdPathRelCubicTo(double x1, double y1, double x2, double y2, double x3, double y3)

Helpers

  • gdPathaddRect(double x, double y, double w, double h);
  • gdPathAddRoundRect(double x, double y, double w, double h, double rx, double ry);
  • gdPathAddEllipse(double cx, double cy, double rx, double ry);
  • gdPathAddCircle(double cx, double cy, double r);
  • gdPathAddArc(double cx, double cy, double r, double angle1, double angle2, int counterClockWise);

Dashed path

Dashed definitions are defined by the lenght of each element of the pattern, for example:

2.4 1 3.4 5

will create a pattern made of respectivelly path of 2.4 1 3.4 and 5 userspace units. First position is On, 2nd Off etc. A single entry pattern will automatically alternate between On and Off of the same length.

Gradients

  • Linear
  • Radial

APIs using

  • gdGradientCreateLinear
  • gdGradientCreateRadial
  • AddStopColor
  • GetStopColors

FT Raster

See Example result in this issue's comment

GD Error/Warning Callback

Create hooks for callback on GD error or warning. It will avoid overwrite at compile time for languages like php's ext/gd f.e.

Coder/Decoder options

Many image formats have various options available, which affect quality, size, colors or any other details of a picture. It can be hard to maintain to create specific APIs for each of these options.

One possibility is to have a CoderOptionsSet/Get API, which could use a gdCodecOptions[] as input:

struct gdCodecOptions {
  char *name; // Name of the option
  gdVariant value; // value as gdVarian
}

A gdVariant could be like:

struct {
  int type // Variant Type, GD_INT, GD_DOUBLE, GD_STRING, GD_MATRIX, etc.
  int intval;
  char *strval;
  void *data; // other non scalar data like GD_MATRIX (double[3][3] f.e.)
}

This would allow to have specific gdCodecOptions handler in each codec and fallback/ignore options not available in a given build f.e. The user (binding or direct C/Rust/Go/V users) won't have to check for functions existence to pass options.

A gdCodeOptionsAvailable could provide the options available for a given codec.

BC breaks (if any)

to list features or functions we like to remove or change.

GD/GD2 Image Format

Deprecate them in 2.x and remove in 3.0

CLI tools

As of now we have many small tools, which are parts of the default builds. It is unclear if anyone is actually using them. We may think about dropping them all into the examples folders and eventually add a simple conversion/resize/transform tool like imconvert, gdconvert f.e.

Build and platforms

Platforms

We could keep the following platforms officially

  • Linux x86/x64/ARM
  • *BSD x86/x64/ARM
  • Windows x86/x64/ARM
  • MacOs (?) x64, M1+ (?)

Other like VMS and similar are very hard to keep up-to-date.

If some dependencies do nor work on a given architecture (like ARM), it would be fine to add it but clearly document it as such.

Build

Keep only:

  • CMake
  • Autoconf