-
Notifications
You must be signed in to change notification settings - Fork 277
3.0 Roadmap
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.)
}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 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 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 gray level. Can be used for gray level or one surface per channel image.
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);| 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 |
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:
See https://github.com/libgd/libgd/wiki/GD-Draw,-vector-based-drawing-APIs for implementation status and in details documentation.
- 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)
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)
- 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 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.
- Linear
- Radial
APIs using
- gdGradientCreateLinear
- gdGradientCreateRadial
- AddStopColor
- GetStopColors
See Example result in this issue's comment
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.
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.
to list features or functions we like to remove or change.
Deprecate them in 2.x and remove in 3.0
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.
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.
Keep only:
- CMake
- Autoconf