Added rudimentary SVG support. (#2738)

* Added rudimentary SVG support. Added 2 functions ImageLoadSvg and ImageLoadSvgWithSize.

* Added an example on how to use ImageLoadSvgWithSize and adjusted Makefiles accordingly.

* Added actual correct example file.

* Reviewed the code to keep the raylib coding conventions in mind.
Moved the LoadImageSvg() code into LoadImage() guarded by SUPPORT_FILEFORMAT_SVG.
Renamed LoadImageSvgWithSize() to LoadImageSvg().
Added a LoadImageSvgFromString() function to parse the loaded SVG into an actual image. This does the bulk of the work.

* Fixed typo.

---------

Co-authored-by: Ray <raysan5@gmail.com>
This commit is contained in:
bXi
2023-09-02 07:00:18 -04:00
committed by GitHub
parent 75e5cd86d7
commit c03ab03627
10 changed files with 4700 additions and 17 deletions

View File

@@ -141,22 +141,22 @@
//------------------------------------------------------------------------------------
// Module: rtextures - Configuration Flags
//------------------------------------------------------------------------------------
// Select the desired fileformats to be supported for image data loading
#define SUPPORT_FILEFORMAT_PNG 1
//#define SUPPORT_FILEFORMAT_BMP 1
//#define SUPPORT_FILEFORMAT_TGA 1
//#define SUPPORT_FILEFORMAT_JPG 1
#define SUPPORT_FILEFORMAT_GIF 1
#define SUPPORT_FILEFORMAT_QOI 1
//#define SUPPORT_FILEFORMAT_PSD 1
#define SUPPORT_FILEFORMAT_DDS 1
#define SUPPORT_FILEFORMAT_HDR 1
// Selecte desired fileformats to be supported for image data loading
#define SUPPORT_FILEFORMAT_PNG 1
//#define SUPPORT_FILEFORMAT_BMP 1
//#define SUPPORT_FILEFORMAT_TGA 1
//#define SUPPORT_FILEFORMAT_JPG 1
#define SUPPORT_FILEFORMAT_GIF 1
#define SUPPORT_FILEFORMAT_QOI 1
//#define SUPPORT_FILEFORMAT_PSD 1
#define SUPPORT_FILEFORMAT_DDS 1
//#define SUPPORT_FILEFORMAT_HDR 1
//#define SUPPORT_FILEFORMAT_PIC 1
//#define SUPPORT_FILEFORMAT_PNM 1
//#define SUPPORT_FILEFORMAT_KTX 1
//#define SUPPORT_FILEFORMAT_ASTC 1
//#define SUPPORT_FILEFORMAT_PKM 1
//#define SUPPORT_FILEFORMAT_PVR 1
//#define SUPPORT_FILEFORMAT_KTX 1
//#define SUPPORT_FILEFORMAT_ASTC 1
//#define SUPPORT_FILEFORMAT_PKM 1
//#define SUPPORT_FILEFORMAT_PVR 1
#define SUPPORT_FILEFORMAT_SVG 1
// Support image export functionality (.png, .bmp, .tga, .jpg, .qoi)
#define SUPPORT_IMAGE_EXPORT 1

3053
src/external/nanosvg.h vendored Normal file

File diff suppressed because it is too large Load Diff

1458
src/external/nanosvgrast.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1245,6 +1245,8 @@ RLAPI Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2);
// NOTE: These functions do not require GPU access
RLAPI Image LoadImage(const char *fileName); // Load image from file into CPU memory (RAM)
RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image from RAW file data
RLAPI Image LoadImageSvg(const char *fileName, int width, int height); // Load image from SVG file data with specified size
RLAPI Image LoadImageSvgFromString(const char *string, int width, int height); // Load an image from a SVG string with custom size
RLAPI Image LoadImageAnim(const char *fileName, int *frames); // Load image sequence from file (frames appended to image.data)
RLAPI Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load image from memory buffer, fileType refers to extension: i.e. '.png'
RLAPI Image LoadImageFromTexture(Texture2D texture); // Load image from GPU texture data

View File

@@ -215,6 +215,14 @@
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include "external/stb_image_resize.h" // Required for: stbir_resize_uint8() [ImageResize()]
#if defined(SUPPORT_FILEFORMAT_SVG)
#define NANOSVG_IMPLEMENTATION // Expands implementation
#include "external/nanosvg.h"
#define NANOSVGRAST_IMPLEMENTATION
#include "external/nanosvgrast.h"
#endif
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
@@ -310,6 +318,72 @@ Image LoadImageRaw(const char *fileName, int width, int height, int format, int
return image;
}
// Load an image from SVG file data with a custom size
Image LoadImageSvg(const char *fileName, int width, int height)
{
Image image = { 0 };
unsigned int dataSize = 0;
unsigned char *string = LoadFileData(fileName, &dataSize);
if (string != NULL)
{
image = LoadImageSvgFromString(string, width, height);
RL_FREE(string);
}
return image;
}
// Load an image from a SVG string with custom size
Image LoadImageSvgFromString(const char *string, int width, int height)
{
Image image = { 0 };
if (string != NULL)
{
struct NSVGimage *svgImage = nsvgParse(string, "px", 96.0f);
// Allocate memory for image
unsigned char *img = malloc(width*height*4);
// Calculate scales for both the width and the height
const float scaleWidth = width/svgImage->width;
const float scaleHeight = height/svgImage->height;
// Set the largest of the 2 scales to be the scale to use
const float scale = (scaleHeight > scaleWidth) ? scaleWidth : scaleHeight;
int offsetX = 0;
int offsetY = 0;
if (scaleHeight > scaleWidth)
{
offsetY = (height - svgImage->height*scale) / 2;
}
else
{
offsetX = (width - svgImage->width*scale) / 2;
}
// Rasterize
struct NSVGrasterizer* rast = nsvgCreateRasterizer();
nsvgRasterize(rast, svgImage, (int)offsetX, (int)offsetY, scale, img, width, height, width*4);
// Populate image struct with all data
image.data = img;
image.width = width;
image.height = height;
image.mipmaps = 1;
image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
// Delete
nsvgDelete(svgImage);
}
return image;
}
// Load animated image data
// - Image.data buffer includes all frames: [image#0][image#1][image#2][...]
// - Number of frames is returned through 'frames' parameter
@@ -470,6 +544,27 @@ Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, i
{
image.data = rl_load_astc_from_memory(fileData, dataSize, &image.width, &image.height, &image.format, &image.mipmaps);
}
#endif
#if defined(SUPPORT_FILEFORMAT_SVG)
else if (strcmp(fileType, ".svg") == 0)
{
if (fileData != NULL)
{
// Creating a duplicate svg to read sizes from due to nsvgParse modifiying the string buffer.
unsigned char *duplicate = (unsigned char*)RL_MALLOC(dataSize);
memcpy(duplicate, fileData, dataSize);
struct NSVGimage *svgImage = nsvgParse(duplicate, "px", 96.0f);
RL_FREE(duplicate);
const int width = (int)svgImage->width;
const int height = (int)svgImage->height;
// Delete
nsvgDelete(svgImage);
image = LoadImageSvgFromString(fileData, width, height);
}
}
#endif
else TRACELOG(LOG_WARNING, "IMAGE: Data format not supported");