22#include <SDL3_image/SDL_image.h>
39 SDL_DestroySurface(this->surface);
97static bool isSVG(
const Image *self,
const uint8_t *bytes,
size_t length) {
99 if (self->
type && SDL_strcasecmp(self->
type,
"svg") == 0) {
105 SDL_IOStream *stream = SDL_IOFromConstMem(bytes, (
int) length);
107 svg = IMG_isSVG(stream);
120 if (
isSVG(self, bytes, length)) {
121 return $(self,
initWithSVG, bytes, length, pixelDensity);
124 SDL_IOStream *stream = SDL_IOFromConstMem(bytes, (
int) length);
126 SDL_Surface *surface = IMG_LoadTyped_IO(stream, 0, self->
type);
129 SDL_DestroySurface(surface);
131 self = release(self);
135 self = release(self);
148 self = $(self,
initWithBytes, data->bytes, data->length, pixelDensity);
150 self = release(self);
163 self->
type = strrchr(resource->name,
'.') ? strrchr(resource->name,
'.') + 1 : NULL;
164 self = $(self,
initWithData, resource->data, pixelDensity);
166 self = release(self);
185 *points = MakeSize(0, 0);
188 char *at = strrchr(
name,
'@');
196 const char *extension = strrchr(
name,
'.');
198 if (extension && at > extension) {
200 if (sscanf(at + 1,
"%dx%d%c", &w, &h, &excess) == 2 && w > 0 && h > 0) {
201 *points = MakeSize(w, h);
208 const size_t length = (extension ? (size_t) (extension - at) : strlen(at)) - 1;
211 if (length == 0 || length >=
sizeof(decoration)) {
215 memcpy(decoration, at + 1, length);
216 decoration[length] =
'\0';
218 if (sscanf(decoration,
"%dx%c", &w, &excess) == 1 && w > 0) {
229 const char *extension = strrchr(
name,
'.');
230 const int stem = extension ? (int) (extension -
name) : (int) strlen(
name);
232 char *variant = NULL;
233 if (SDL_asprintf(&variant,
"%.*s@%dx%s", stem,
name, density, extension ?:
"") < 0) {
248 char *resourceName = strdup(
name);
249 assert(resourceName);
256 Resource *resource = NULL;
258 const char *extension = strrchr(resourceName,
'.');
262 if (points.w == 0 && scale == 0.f && !(extension && SDL_strcasecmp(extension,
".svg") == 0)) {
264 const int density = (int) SDL_roundf(pixelDensity);
267 char *variant =
variantName(resourceName, density);
270 resource = $$(Resource, resourceWithName, variant);
272 scale = (float) density;
280 if (resource == NULL) {
281 resource = $$(Resource, resourceWithName, resourceName);
286 if (resource == NULL) {
287 return release(self);
290 if (points.w && points.h && resource->data &&
291 isSVG(self, resource->data->bytes, resource->data->length)) {
292 self = $(self,
initWithSVGSize, resource->data->bytes, resource->data->length, points,
297 if (self && scale > 0.f) {
312 SDL_Surface *surface = NULL;
314 SDL_IOStream *stream = SDL_IOFromConstMem(bytes, (
int) length);
316 surface = IMG_LoadSizedSVG_IO(stream,
size.w,
size.h);
329 scale = scale > 0.f ? scale : 1.f;
331 SDL_Surface *surface =
rasterizeSVG(bytes, length, MakeSize(0, 0));
333 if (surface && scale != 1.f) {
334 const SDL_Size
size = MakeSize(
335 (
int) SDL_roundf(surface->w * scale),
336 (
int) SDL_roundf(surface->h * scale)
339 SDL_DestroySurface(surface);
345 SDL_DestroySurface(surface);
353 self = release(self);
365 const SDL_Size pixels = MakeSize(
366 (
int) SDL_roundf(points.w * pixelDensity),
367 (
int) SDL_roundf(points.h * pixelDensity)
370 SDL_Surface *surface =
rasterizeSVG(bytes, length, pixels);
373 SDL_DestroySurface(surface);
377 self->
scale = pixelDensity;
381 self = release(self);
393 self = (
Image *) super(Object, self,
init);
398 if (surface->format != SDL_PIXELFORMAT_RGBA32) {
399 self->
surface = SDL_ConvertSurface(surface, SDL_PIXELFORMAT_RGBA32);
423#pragma mark - Class lifecycle
430 ((ObjectInterface *) clazz->interface)->dealloc =
dealloc;
432 ((ImageInterface *) clazz->interface)->imageWithBytes =
imageWithBytes;
445 ((ImageInterface *) clazz->interface)->
size =
size;
457 clazz = _initialize(&(
const ClassDef) {
459 .superclass = _Object(),
460 .instanceSize =
sizeof(
Image),
461 .interfaceSize =
sizeof(ImageInterface),
static View * init(View *self)
static String * name(const Font *self)
static Image * imageWithBytes(const uint8_t *bytes, size_t length, float pixelDensity)
static Image * initWithSurface(Image *self, SDL_Surface *surface)
static Image * initWithResource(Image *self, const Resource *resource, float pixelDensity)
static Image * initWithBytes(Image *self, const uint8_t *bytes, size_t length, float pixelDensity)
static Image * imageWithResource(const Resource *resource, float pixelDensity)
static Image * imageWithSurface(SDL_Surface *surface)
static Image * initWithSVGSize(Image *self, const uint8_t *bytes, size_t length, SDL_Size points, float pixelDensity)
static Image * initWithData(Image *self, const Data *data, float pixelDensity)
static bool isSVG(const Image *self, const uint8_t *bytes, size_t length)
static Image * imageWithResourceName(const char *name, float pixelDensity)
static void dealloc(Object *self)
static SDL_Size size(const Image *self)
static Image * imageWithData(const Data *data, float pixelDensity)
static void initialize(Class *clazz)
static SDL_Surface * rasterizeSVG(const uint8_t *bytes, size_t length, SDL_Size size)
Rasterizes bytes as SVG at size pixels, or at its intrinsic size when size is zero.
static Image * initWithSVG(Image *self, const uint8_t *bytes, size_t length, float scale)
static char * variantName(const char *name, int density)
Composes the name of the @<density>x variant of name, e.g. foo@2x.png.
static void parseDecoration(char *name, SDL_Size *points, float *scale)
Interprets an @ decoration in name.
static Image * imageWithSVG(const uint8_t *bytes, size_t length, float scale)
static Image * initWithResourceName(Image *self, const char *name, float pixelDensity)
View logging facilities via SDL_Log.
#define MVC_LogWarn(fmt,...)
SDL_Size size(const Image *self)
const char * type
The image type, inferred if instantiated with a Resource.
Image * initWithData(Image *self, const Data *data)
Initializes this Image with the specified Data.
Image * initWithResourceName(Image *self, const char *name)
Initializes this Image, loading the Resource by the given name.
Image * initWithSVGSize(Image *self, const uint8_t *bytes, size_t length, SDL_Size points)
Initializes this Image by rasterizing the specified SVG at points times the pixel density,...
Image * initWithBytes(Image *self, const uint8_t *bytes, size_t length)
Initializes this Image with the specified bytes.
float scale
Pixels of surface per point: 1 for raster images, the requested scale for SVG.
Image * imageWithSVG(const uint8_t *bytes, size_t length, float scale)
Instantiates an Image by rasterizing the specified SVG.
Image * initWithSVG(Image *self, const uint8_t *bytes, size_t length, float scale)
Initializes this Image by rasterizing the specified SVG at its intrinsic size times scale.
Image * imageWithResourceName(const char *name)
Instantiates an Image with the specified Resource name.
Image * imageWithData(const Data *data)
Instantiates an Image with the specified Data.
Image * initWithSurface(Image *self, SDL_Surface *surface)
Initializes this Image with the given surface.
SDL_Surface * surface
The backing surface.
Image * imageWithResource(const Resource *resource)
Instantiates an Image with the specified Resource.
Image * imageWithSurface(SDL_Surface *surface)
Instantiates an Image with the specified surface.
Image * initWithResource(Image *self, const Resource *resource)
Initializes this Image with the specified Resource.