/**
* ISC License
*
* © 2019 Mattias Andrée <m@maandree.se>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef LIBSLIM_H
#define LIBSLIM_H
#include <stddef.h>
#include <stdint.h>
#include <string.h>
struct libslim_image_meta {
size_t width;
size_t height;
size_t hblank;
};
#define LIBSLIM_DECLARE_FORMAT(SUFFIX, PIXEL)\
struct libslim_pixel_##SUFFIX PIXEL;\
struct libslim_image_##SUFFIX {\
struct libslim_image_meta meta;\
struct libslim_pixel_##SUFFIX *data;\
}
LIBSLIM_DECLARE_FORMAT(xyza_f, { float x, y, z, a; });
LIBSLIM_DECLARE_FORMAT(xyza_d, { double x, y, z, a; });
LIBSLIM_DECLARE_FORMAT(xyza_ld, { long double x, y, z, a; });
LIBSLIM_DECLARE_FORMAT(xyz_f, { float x, y, z; });
LIBSLIM_DECLARE_FORMAT(xyz_d, { double x, y, z; });
LIBSLIM_DECLARE_FORMAT(xyz_ld, { long double x, y, z; });
LIBSLIM_DECLARE_FORMAT(rgba_f, { float r, g, b, a; });
LIBSLIM_DECLARE_FORMAT(rgba_d, { double r, g, b, a; });
LIBSLIM_DECLARE_FORMAT(rgba_ld, { long double r, g, b, a; });
LIBSLIM_DECLARE_FORMAT(rgb_f, { float r, g, b; });
LIBSLIM_DECLARE_FORMAT(rgb_d, { double r, g, b; });
LIBSLIM_DECLARE_FORMAT(rgb_ld, { long double r, g, b; });
/* Replace an entire row, of an image, with a single colour */
#define libslim_set_colour_row(OUT, COLOUR)\
do {\
size_t x__, y__;\
size_t w__ = (OUT)->meta.width;\
for (x__ = 0; x__ < w__; x__++)\
(OUT)->data[x__] = *(COLOUR);\
} while (0)
/* Replace an entire image with a single colour */
#define libslim_set_colour(OUT, COLOUR)\
do {\
size_t x__, y__;\
size_t h__ = (OUT)->meta.height;\
size_t w__ = (OUT)->meta.width;\
void *out__ = (OUT)->data;\
for (y__ = 0; y__ < h__; y__++) {\
for (x__ = 0; x__ < w__; x__++)\
(OUT)->data[x__] = (COLOUR);\
(OUT)->data += (OUT)->meta.width + (OUT)->meta.hblank;\
}\
(OUT)->data = out__;\
} while (0)
/* Horizontally flip a row of an image */
#define libslim_flop_row(OUT, IN)\
do {\
size_t i__;\
size_t n__ = (IN)->meta.width - 1;\
for (i__ = 0; i__ <= n__; i__++)\
(OUT)->data[n__ - i__] = (IN)->data[i__];\
} while (0)
/* Horizontally flip an image */
#define libslim_flop(OUT, IN)\
do {\
size_t i__;\
size_t n__ = (IN)->meta.width - 1;\
size_t h__ = (IN)->meta.height;\
void *in__ = (IN)->data;\
void *out__ = (OUT)->data;\
(OUT)->meta.width = (IN)->meta.width;\
(OUT)->meta.height = (IN)->meta.height;\
while (h__--) {\
for (i__ = 0; i__ <= n__; i__++)\
(OUT)->data[n__ - i__] = (IN)->data[i__];\
(IN)->data += (IN)->meta.width + (IN)->meta.hblank;\
(OUT)->data += (OUT)->meta.width + (OUT)->meta.hblank;\
}\
(IN)->data = in__;\
(OUT)->data = out__;\
} while (0)
/* Vertically flip an image */
#define libslim_flip(OUT, IN)\
do {\
size_t i__;\
size_t n__ = (IN)->meta.height;\
size_t w__ = (IN)->meta.width * sizeof(*(IN)->data);\
void *in__ = (IN)->data;\
void *out__ = (OUT)->data;\
(OUT)->meta.width = (IN)->meta.width;\
(OUT)->meta.height = (IN)->meta.height;\
(OUT)->data += (n__ - 1) * ((OUT)->meta.width + (OUT)->meta.hblank); \
for (i__ = 0; i__ < n__; i__++) {\
memcpy((OUT)->data, (IN)->data, w__);\
(IN)->data += (IN)->meta.width + (IN)->meta.hblank;\
(OUT)->data -= (OUT)->meta.width + (OUT)->meta.hblank;\
}\
(IN)->data = in__;\
(OUT)->data = out__;\
} while (0)
/* Transpose an image */
#define libslim_transpose(OUT, IN)\
do {\
size_t x__, y__, i__;\
size_t rw__ = (OUT)->meta.width + (OUT)->meta.hblank;\
size_t w__ = (IN)->meta.width;\
size_t h__ = (IN)->meta.height;\
void *in__ = (IN)->data;\
void *out__ = (OUT)->data;\
(OUT)->meta.width = (IN)->meta.height;\
(OUT)->meta.height = (IN)->meta.width;\
for (y__ = 0; y__ < h__; y__++) {\
for (x__ = i__ = 0; x__ < w__; x__++, i__ += rw__)\
(OUT)->data[i__] = (IN)->data[x__];\
(IN)->data += (IN)->meta.width + (IN)->meta.hblank;\
(OUT)->data += 1;\
}\
(IN)->data = in__;\
(OUT)->data = out__;\
} while (0)
/* Rotate an image 90 degrees clockwise */
#define libslim_rotate_90(OUT, IN)\
do {\
/* equivalent to flip than transpose */\
size_t x__, y__, i__;\
size_t rw__ = (OUT)->meta.width + (OUT)->meta.hblank;\
size_t w__ = (IN)->meta.width;\
size_t h__ = (IN)->meta.height;\
void *in__ = (IN)->data;\
void *out__ = (OUT)->data;\
(OUT)->meta.width = (IN)->meta.height;\
(OUT)->meta.height = (IN)->meta.width;\
(IN)->data += (h__ - 1) * ((IN)->meta.width + (IN)->meta.hblank);\
for (y__ = 0; y__ < h__; y__++) {\
for (x__ = i__ = 0; x__ < w__; x__++, i__ += rw__)\
(OUT)->data[i__] = (IN)->data[x__];\
(IN)->data -= (IN)->meta.width + (IN)->meta.hblank;\
(OUT)->data += 1;\
}\
(IN)->data = in__;\
(OUT)->data = out__;\
} while (0)
/* Rotate an image 180 degrees */
#define libslim_rotate_180(OUT, IN)\
do {\
/* equivalent to flip and flop */\
size_t i__, j__;\
size_t n__ = (IN)->meta.height;\
size_t w__ = (IN)->meta.width - 1;\
void *in__ = (IN)->data;\
void *out__ = (OUT)->data;\
(OUT)->meta.width = (IN)->meta.width;\
(OUT)->meta.height = (IN)->meta.height;\
(OUT)->data += (n__ - 1) * ((OUT)->meta.width + (OUT)->meta.hblank);\
for (i__ = 0; i__ < n__; i__++) {\
for (j__ = 0; j__ <= w__; j__++)\
(OUT)->data[w__ - j__] = (IN)->data[j__];\
(IN)->data += (IN)->meta.width + (IN)->meta.hblank;\
(OUT)->data -= (OUT)->meta.width + (OUT)->meta.hblank;\
}\
(IN)->data = in__;\
(OUT)->data = out__;\
} while (0)
/* Rotate an image 270 degrees clockwise */
#define libslim_rotate_270(OUT, IN)\
do {\
/* equivalent to transpose than flip */\
size_t x__, y__, i__;\
size_t rw__ = (OUT)->meta.width + (OUT)->meta.hblank;\
size_t w__ = (IN)->meta.width;\
size_t h__ = (IN)->meta.height;\
void *in__ = (IN)->data;\
void *out__ = (OUT)->data;\
(OUT)->meta.width = (IN)->meta.height;\
(OUT)->meta.height = (IN)->meta.width;\
for (y__ = 0; y__ < h__; y__++) {\
for (x__ = 0, i__ = rw__ * (w__ - 1); x__ < w__; x__++, i__ -= rw__) \
(OUT)->data[i__] = (IN)->data[x__];\
(IN)->data += (IN)->meta.width + (IN)->meta.hblank;\
(OUT)->data += 1;\
}\
(IN)->data = in__;\
(OUT)->data = out__;\
} while (0)
/* Transpose an image along instead of across the main diagonal */
#define libslim_anti_transpose(OUT, IN)\
do {\
/* equivalent to flip than transpose than flip, or a tranpose and a 180 degree rotation */\
size_t x__, y__, i__;\
size_t rw__ = (OUT)->meta.width + (OUT)->meta.hblank;\
size_t w__ = (IN)->meta.width;\
size_t h__ = (IN)->meta.height;\
void *in__ = (IN)->data;\
void *out__ = (OUT)->data;\
(OUT)->meta.width = (IN)->meta.height;\
(OUT)->meta.height = (IN)->meta.width;\
(IN)->data += (h__ - 1) * ((IN)->meta.width + (IN)->meta.hblank);\
for (y__ = 0; y__ < h__; y__++) {\
for (x__ = 0, i__ = rw__ * (w__ - 1); x__ < w__; x__++, i__ -= rw__) \
(OUT)->data[i__] = (IN)->data[x__];\
(IN)->data -= (IN)->meta.width + (IN)->meta.hblank;\
(OUT)->data += 1;\
}\
(IN)->data = in__;\
(OUT)->data = out__;\
} while (0)
/* Swap channels in an image with 4 channels */
#define libslim_swap_channels_4(OUT, IN, IN_CH1, OUT_CH1, IN_CH2, OUT_CH2, IN_CH3, OUT_CH3, IN_CH4, OUT_CH4)\
do {\
size_t x__, y__;\
size_t h__ = (IN)->meta.height;\
size_t w__ = (IN)->meta.width;\
void *in__ = (IN)->data;\
void *out__ = (OUT)->data;\
(OUT)->meta.height = h__;\
(OUT)->meta.width = w__;\
for (y__ = 0; y__ < h__; y__++) {\
for (x__ = 0; x__ < w__; x__++) {\
(OUT)->data[x__].OUT_CH1 = (IN)->data[x__].IN_CH1;\
(OUT)->data[x__].OUT_CH2 = (IN)->data[x__].IN_CH2;\
(OUT)->data[x__].OUT_CH3 = (IN)->data[x__].IN_CH3;\
(OUT)->data[x__].OUT_CH4 = (IN)->data[x__].IN_CH4;\
}\
(IN)->data += (IN)->meta.width + (IN)->meta.hblank;\
(OUT)->data += (OUT)->meta.width + (OUT)->meta.hblank;\
}\
(IN)->data = in__;\
(OUT)->data = out__;\
} while (0)
/* Swap channels in a row of an image with 4 channels */
#define libslim_swap_channels_4_row(OUT, IN, IN_CH1, OUT_CH1, IN_CH2, OUT_CH2, IN_CH3, OUT_CH3, IN_CH4, OUT_CH4)\
do {\
size_t i__;\
size_t n__ = (IN)->meta.width;\
for (i__ = 0; i__ < n__; i__++) {\
(OUT)->data[i__].OUT_CH1 = (IN)->data[i__].IN_CH1;\
(OUT)->data[i__].OUT_CH2 = (IN)->data[i__].IN_CH2;\
(OUT)->data[i__].OUT_CH3 = (IN)->data[i__].IN_CH3;\
(OUT)->data[i__].OUT_CH4 = (IN)->data[i__].IN_CH4;\
}\
} while (0)
/* Swap channels in an image with 3 channels */
#define libslim_swap_channels_3(OUT, IN, IN_CH1, OUT_CH1, IN_CH2, OUT_CH2, IN_CH3, OUT_CH3)\
do {\
size_t x__, y__;\
size_t h__ = (IN)->meta.height;\
size_t w__ = (IN)->meta.width;\
void *in__ = (IN)->data;\
void *out__ = (OUT)->data;\
(OUT)->meta.height = h__;\
(OUT)->meta.width = w__;\
for (y__ = 0; y__ < h__; y__++) {\
for (x__ = 0; x__ < w__; x__++) {\
(OUT)->data[x__].OUT_CH1 = (IN)->data[x__].IN_CH1;\
(OUT)->data[x__].OUT_CH2 = (IN)->data[x__].IN_CH2;\
(OUT)->data[x__].OUT_CH3 = (IN)->data[x__].IN_CH3;\
}\
(IN)->data += (IN)->meta.width + (IN)->meta.hblank;\
(OUT)->data += (OUT)->meta.width + (OUT)->meta.hblank;\
}\
(IN)->data = in__;\
(OUT)->data = out__;\
} while (0)
/* Swap channels in a row of an image with 3 channels */
#define libslim_swap_channels_3_row(OUT, IN, IN_CH1, OUT_CH1, IN_CH2, OUT_CH2, IN_CH3, OUT_CH3)\
do {\
size_t i__;\
size_t n__ = (IN)->meta.width;\
for (i__ = 0; i__ < n__; i__++) {\
(OUT)->data[i__].OUT_CH1 = (IN)->data[i__].IN_CH1;\
(OUT)->data[i__].OUT_CH2 = (IN)->data[i__].IN_CH2;\
(OUT)->data[i__].OUT_CH3 = (IN)->data[i__].IN_CH3;\
}\
} while (0)
/* Swap channels in an image with 2 channels */
#define libslim_swap_channels_2(OUT, IN, IN_CH1, OUT_CH1, IN_CH2, OUT_CH2)\
do {\
size_t x__, y__;\
size_t h__ = (IN)->meta.height;\
size_t w__ = (IN)->meta.width;\
void *in__ = (IN)->data;\
void *out__ = (OUT)->data;\
(OUT)->meta.height = h__;\
(OUT)->meta.width = w__;\
for (y__ = 0; y__ < h__; y__++) {\
for (x__ = 0; x__ < w__; x__++) {\
(OUT)->data[x__].OUT_CH1 = (IN)->data[x__].IN_CH1;\
(OUT)->data[x__].OUT_CH2 = (IN)->data[x__].IN_CH2;\
}\
(IN)->data += (IN)->meta.width + (IN)->meta.hblank;\
(OUT)->data += (OUT)->meta.width + (OUT)->meta.hblank;\
}\
(IN)->data = in__;\
(OUT)->data = out__;\
} while (0)
/* Swap channels in a row of an image with 2 channels */
#define libslim_swap_channels_2_row(OUT, IN, IN_CH1, OUT_CH1, IN_CH2, OUT_CH2)\
do {\
size_t i__;\
size_t n__ = (IN)->meta.width;\
for (i__ = 0; i__ < n__; i__++) {\
(OUT)->data[i__].OUT_CH1 = (IN)->data[i__].IN_CH1;\
(OUT)->data[i__].OUT_CH2 = (IN)->data[i__].IN_CH2;\
}\
} while (0)
/* Set the values of 3 channels in all pixels in an image */
#define libslim_set_3_channels(OUT, IN, COLOUR, CH1, CH2, CH3)\
do {\
size_t x__, y__;\
size_t h__ = (IN)->meta.height;\
size_t w__ = (IN)->meta.width;\
void *in__ = (IN)->data;\
void *out__ = (OUT)->data;\
(OUT)->meta.height = h__;\
(OUT)->meta.width = w__;\
for (y__ = 0; y__ < h__; y__++) {\
for (x__ = 0; x__ < w__; x__++) {\
(OUT)->data[x__] = (IN)->data[x__];\
(OUT)->data[x__].CH1 = (COLOUR)->CH1;\
(OUT)->data[x__].CH2 = (COLOUR)->CH2;\
(OUT)->data[x__].CH3 = (COLOUR)->CH3;\
}\
(IN)->data += (IN)->meta.width + (IN)->meta.hblank;\
(OUT)->data += (OUT)->meta.width + (OUT)->meta.hblank;\
}\
(IN)->data = in__;\
(OUT)->data = out__;\
} while (0)
/* Set the values of 3 channels in all pixels in a row of an image */
#define libslim_set_3_channels_row(OUT, IN, COLOUR, CH1, CH2, CH3)\
do {\
size_t i__;\
size_t n__ = (IN)->meta.width;\
for (i__ = 0; i__ < n__; i__++) {\
(OUT)->data[i__] = (IN)->data[i__];\
(OUT)->data[i__].CH1 = (COLOUR)->CH1;\
(OUT)->data[i__].CH2 = (COLOUR)->CH2;\
(OUT)->data[i__].CH3 = (COLOUR)->CH3;\
}\
} while (0)
/* Set the values of 2 channels in all pixels in an image */
#define libslim_set_2_channels(OUT, IN, COLOUR, CH1, CH2)\
do {\
size_t x__, y__;\
size_t h__ = (IN)->meta.height;\
size_t w__ = (IN)->meta.width;\
void *in__ = (IN)->data;\
void *out__ = (OUT)->data;\
(OUT)->meta.height = h__;\
(OUT)->meta.width = w__;\
for (y__ = 0; y__ < h__; y__++) {\
for (x__ = 0; x__ < w__; x__++) {\
(OUT)->data[x__] = (IN)->data[x__];\
(OUT)->data[x__].CH1 = (COLOUR)->CH1;\
(OUT)->data[x__].CH2 = (COLOUR)->CH2;\
}\
(IN)->data += (IN)->meta.width + (IN)->meta.hblank;\
(OUT)->data += (OUT)->meta.width + (OUT)->meta.hblank;\
}\
(IN)->data = in__;\
(OUT)->data = out__;\
} while (0)
/* Set the values of 2 channels in all pixels in a row of an image */
#define libslim_set_2_channels_row(OUT, IN, COLOUR, CH1, CH2)\
do {\
size_t i__;\
size_t n__ = (IN)->meta.width;\
for (i__ = 0; i__ < n__; i__++) {\
(OUT)->data[i__] = (IN)->data[i__];\
(OUT)->data[i__].CH1 = (COLOUR)->CH1;\
(OUT)->data[i__].CH2 = (COLOUR)->CH2;\
}\
} while (0)
/* Set the values of 1 channel in all pixels in an image */
#define libslim_set_1_channel(OUT, IN, COLOUR, CH)\
do {\
size_t x__, y__;\
size_t h__ = (IN)->meta.height;\
size_t w__ = (IN)->meta.width;\
void *in__ = (IN)->data;\
void *out__ = (OUT)->data;\
(OUT)->meta.height = h__;\
(OUT)->meta.width = w__;\
for (y__ = 0; y__ < h__; y__++) {\
for (x__ = 0; x__ < w__; x__++) {\
(OUT)->data[x__] = (IN)->data[x__];\
(OUT)->data[x__].CH = (COLOUR)->CH;\
}\
(IN)->data += (IN)->meta.width + (IN)->meta.hblank;\
(OUT)->data += (OUT)->meta.width + (OUT)->meta.hblank;\
}\
(IN)->data = in__;\
(OUT)->data = out__;\
} while (0)
/* Set the values of 1 channel in all pixels in a row of an image */
#define libslim_set_1_channel_row(OUT, IN, COLOUR, CH)\
do {\
size_t i__;\
size_t n__ = (IN)->meta.width;\
for (i__ = 0; i__ < n__; i__++) {\
(OUT)->data[i__] = (IN)->data[i__];\
(OUT)->data[i__].CH = (COLOUR)->CH;\
}\
} while (0)
/* Crop an image */
#define libslim_crop(OUT, IN, LEFT, TOP, WIDTH, HEIGHT)\
do {\
size_t i__;\
size_t w__ = (WIDTH);\
size_t h__ = (HEIGHT);\
size_t rw__ = w__ * sizeof(*(IN)->data);\
void *in__ = (IN)->data;\
void *out__ = (OUT)->data;\
(OUT)->meta.width = w__;\
(OUT)->meta.height = h__;\
(IN)->data += (LEFT);\
(IN)->data += (TOP) * ((IN)->meta.width + (IN)->meta.hblank);\
for (i__ = 0; i__ < h__; i__++) {\
memcpy((OUT)->data, (IN)->data, rw__);\
(IN)->data += (IN)->meta.width + (IN)->meta.hblank;\
(OUT)->data += (OUT)->meta.width + (OUT)->meta.hblank;\
}\
(IN)->data = in__;\
(OUT)->data = out__;\
} while (0)
/* Premultiply 3 channels in all pixels in an image */
#define libslim_premultiply_3_channels(OUT, IN, CH1, CH2, CH3)\
do {\
size_t x__, y__;\
size_t h__ = (IN)->meta.height;\
size_t w__ = (IN)->meta.width;\
void *in__ = (IN)->data;\
void *out__ = (OUT)->data;\
(OUT)->meta.height = h__;\
(OUT)->meta.width = w__;\
for (y__ = 0; y__ < h__; y__++) {\
for (x__ = 0; x__ < w__; x__++) {\
(OUT)->data[x__].CH1 = (IN)->data[x__].CH1 * (IN)->data[x__].a;\
(OUT)->data[x__].CH2 = (IN)->data[x__].CH2 * (IN)->data[x__].a;\
(OUT)->data[x__].CH3 = (IN)->data[x__].CH3 * (IN)->data[x__].a;\
(OUT)->data[x__].a = (IN)->data[x__].a;\
}\
(IN)->data += (IN)->meta.width + (IN)->meta.hblank;\
(OUT)->data += (OUT)->meta.width + (OUT)->meta.hblank;\
}\
(IN)->data = in__;\
(OUT)->data = out__;\
} while (0)
/* Premultiply 3 channels in all pixels in a row of an image */
#define libslim_premultiply_3_channels_row(OUT, IN, CH1, CH2, CH3)\
do {\
size_t i__;\
size_t n__ = (IN)->meta.width;\
for (i__ = 0; i__ < n__; i__++) {\
(OUT)->data[i__].CH1 = (IN)->data[i__].CH1 * (IN)->data[i__].a;\
(OUT)->data[i__].CH2 = (IN)->data[i__].CH2 * (IN)->data[i__].a;\
(OUT)->data[i__].CH3 = (IN)->data[i__].CH3 * (IN)->data[i__].a;\
(OUT)->data[i__].a = (IN)->data[i__].a;\
}\
} while (0)
/* Premultiply 2 channels in all pixels in an image */
#define libslim_premultiply_2_channels(OUT, IN, CH1, CH2)\
do {\
size_t x__, y__;\
size_t h__ = (IN)->meta.height;\
size_t w__ = (IN)->meta.width;\
void *in__ = (IN)->data;\
void *out__ = (OUT)->data;\
(OUT)->meta.height = h__;\
(OUT)->meta.width = w__;\
for (y__ = 0; y__ < h__; y__++) {\
for (x__ = 0; x__ < w__; x__++) {\
(OUT)->data[x__].CH1 = (IN)->data[x__].CH1 * (IN)->data[x__].a;\
(OUT)->data[x__].CH2 = (IN)->data[x__].CH2 * (IN)->data[x__].a;\
(OUT)->data[x__].a = (IN)->data[x__].a;\
}\
(IN)->data += (IN)->meta.width + (IN)->meta.hblank;\
(OUT)->data += (OUT)->meta.width + (OUT)->meta.hblank;\
}\
(IN)->data = in__;\
(OUT)->data = out__;\
} while (0)
/* Premultiply 2 channels in all pixels in a row of an image */
#define libslim_premultiply_2_channels_row(OUT, IN, CH1, CH2)\
do {\
size_t i__;\
size_t n__ = (IN)->meta.width;\
for (i__ = 0; i__ < n__; i__++) {\
(OUT)->data[i__].CH1 = (IN)->data[i__].CH1 * (IN)->data[i__].a;\
(OUT)->data[i__].CH2 = (IN)->data[i__].CH2 * (IN)->data[i__].a;\
(OUT)->data[i__].a = (IN)->data[i__].a;\
}\
} while (0)
/* Premultiply 1 channel in all pixels in an image */
#define libslim_premultiply_1_channel(OUT, IN, CH)\
do {\
size_t x__, y__;\
size_t h__ = (IN)->meta.height;\
size_t w__ = (IN)->meta.width;\
void *in__ = (IN)->data;\
void *out__ = (OUT)->data;\
(OUT)->meta.height = h__;\
(OUT)->meta.width = w__;\
for (y__ = 0; y__ < h__; y__++) {\
for (x__ = 0; x__ < w__; x__++) {\
(OUT)->data[x__].CH = (IN)->data[x__].CH * (IN)->data[x__].a;\
(OUT)->data[x__].a = (IN)->data[x__].a;\
}\
(IN)->data += (IN)->meta.width + (IN)->meta.hblank;\
(OUT)->data += (OUT)->meta.width + (OUT)->meta.hblank;\
}\
(IN)->data = in__;\
(OUT)->data = out__;\
} while (0)
/* Premultiply 1 channel in all pixels in a row of an image */
#define libslim_premultiply_1_channel_row(OUT, IN, CH)\
do {\
size_t i__;\
size_t n__ = (IN)->meta.width;\
for (i__ = 0; i__ < n__; i__++) {\
(OUT)->data[i__].CH = (IN)->data[i__].CH * (IN)->data[i__].a;\
(OUT)->data[i__].a = (IN)->data[i__].a;\
}\
} while (0)
/* Unpremultiply 3 channels in all pixels in an image */
#define libslim_unpremultiply_3_channels(OUT, IN, CH1, CH2, CH3)\
do {\
size_t x__, y__;\
size_t h__ = (IN)->meta.height;\
size_t w__ = (IN)->meta.width;\
void *in__ = (IN)->data;\
void *out__ = (OUT)->data;\
(OUT)->meta.height = h__;\
(OUT)->meta.width = w__;\
for (y__ = 0; y__ < h__; y__++) {\
for (x__ = 0; x__ < w__; x__++) {\
(OUT)->data[x__] = (IN)->data[x__];\
if ((IN)->data[i__].a) {\
(OUT)->data[x__].CH1 /= (IN)->data[x__].a;\
(OUT)->data[x__].CH2 /= (IN)->data[x__].a;\
(OUT)->data[x__].CH3 /= (IN)->data[x__].a;\
}\
}\
(IN)->data += (IN)->meta.width + (IN)->meta.hblank;\
(OUT)->data += (OUT)->meta.width + (OUT)->meta.hblank;\
}\
(IN)->data = in__;\
(OUT)->data = out__;\
} while (0)
/* Unpremultiply 3 channels in all pixels in a row of an image */
#define libslim_unpremultiply_3_channels_row(OUT, IN, CH1, CH2, CH3)\
do {\
size_t i__;\
size_t n__ = (IN)->meta.width;\
for (i__ = 0; i__ < n__; i__++) {\
(OUT)->data[i__] = (IN)->data[i__];\
if ((IN)->data[i__].a) {\
(OUT)->data[i__].CH1 /= (IN)->data[i__].a;\
(OUT)->data[i__].CH2 /= (IN)->data[i__].a;\
(OUT)->data[i__].CH3 /= (IN)->data[i__].a;\
}\
}\
} while (0)
/* Unpremultiply 2 channels in all pixels in an image */
#define libslim_unpremultiply_2_channels(OUT, IN, CH1, CH2)\
do {\
size_t x__, y__;\
size_t h__ = (IN)->meta.height;\
size_t w__ = (IN)->meta.width;\
void *in__ = (IN)->data;\
void *out__ = (OUT)->data;\
(OUT)->meta.height = h__;\
(OUT)->meta.width = w__;\
for (y__ = 0; y__ < h__; y__++) {\
for (x__ = 0; x__ < w__; x__++) {\
(OUT)->data[x__] = (IN)->data[x__];\
if ((IN)->data[i__].a) {\
(OUT)->data[x__].CH1 /= (IN)->data[x__].a;\
(OUT)->data[x__].CH2 /= (IN)->data[x__].a;\
}\
}\
(IN)->data += (IN)->meta.width + (IN)->meta.hblank;\
(OUT)->data += (OUT)->meta.width + (OUT)->meta.hblank;\
}\
(IN)->data = in__;\
(OUT)->data = out__;\
} while (0)
/* Unpremultiply 2 channels in all pixels in a row of an image */
#define libslim_unpremultiply_2_channels_row(OUT, IN, CH1, CH2)\
do {\
size_t i__;\
size_t n__ = (IN)->meta.width;\
for (i__ = 0; i__ < n__; i__++) {\
(OUT)->data[i__] = (IN)->data[i__];\
if ((IN)->data[i__].a) {\
(OUT)->data[i__].CH1 /= (IN)->data[i__].a;\
(OUT)->data[i__].CH2 /= (IN)->data[i__].a;\
}\
}\
} while (0)
/* Unpremultiply 1 channel in all pixels in an image */
#define libslim_unpremultiply_1_channel(OUT, IN, CH)\
do {\
size_t x__, y__;\
size_t h__ = (IN)->meta.height;\
size_t w__ = (IN)->meta.width;\
void *in__ = (IN)->data;\
void *out__ = (OUT)->data;\
(OUT)->meta.height = h__;\
(OUT)->meta.width = w__;\
for (y__ = 0; y__ < h__; y__++) {\
for (x__ = 0; x__ < w__; x__++) {\
(OUT)->data[x__] = (IN)->data[x__];\
if ((IN)->data[i__].a)\
(OUT)->data[x__].CH /= (IN)->data[x__].a;\
}\
(IN)->data += (IN)->meta.width + (IN)->meta.hblank;\
(OUT)->data += (OUT)->meta.width + (OUT)->meta.hblank;\
}\
(IN)->data = in__;\
(OUT)->data = out__;\
} while (0)
/* Unpremultiply 1 channel in all pixels in a row of an image */
#define libslim_unpremultiply_1_channel_row(OUT, IN, CH)\
do {\
size_t i__;\
size_t n__ = (IN)->meta.width;\
for (i__ = 0; i__ < n__; i__++) {\
(OUT)->data[i__] = (IN)->data[i__];\
if ((IN)->data[i__].a)\
(OUT)->data[i__].CH /= (IN)->data[i__].a;\
}\
} while (0)
/* Unpremultiply 3 channels in all pixels in an image */
#define libslim_unpremultiply_3_channels_zero(OUT, IN, ZERO, CH1, CH2, CH3)\
do {\
size_t x__, y__;\
size_t h__ = (IN)->meta.height;\
size_t w__ = (IN)->meta.width;\
void *in__ = (IN)->data;\
void *out__ = (OUT)->data;\
(OUT)->meta.height = h__;\
(OUT)->meta.width = w__;\
for (y__ = 0; y__ < h__; y__++) {\
for (x__ = 0; x__ < w__; x__++) {\
(OUT)->data[x__] = (IN)->data[x__];\
if ((IN)->data[i__].a) {\
(OUT)->data[x__].CH1 /= (IN)->data[x__].a;\
(OUT)->data[x__].CH2 /= (IN)->data[x__].a;\
(OUT)->data[x__].CH3 /= (IN)->data[x__].a;\
} else {\
(OUT)->data[x__].CH1 = (ZERO)->CH1;\
(OUT)->data[x__].CH2 = (ZERO)->CH2;\
(OUT)->data[x__].CH3 = (ZERO)->CH3;\
}
}\
(IN)->data += (IN)->meta.width + (IN)->meta.hblank;\
(OUT)->data += (OUT)->meta.width + (OUT)->meta.hblank;\
}\
(IN)->data = in__;\
(OUT)->data = out__;\
} while (0)
/* Unpremultiply 3 channels in all pixels in a row of an image */
#define libslim_unpremultiply_3_channels_zero_row(OUT, IN, ZERO, CH1, CH2, CH3)\
do {\
size_t i__;\
size_t n__ = (IN)->meta.width;\
for (i__ = 0; i__ < n__; i__++) {\
(OUT)->data[i__] = (IN)->data[i__];\
if ((IN)->data[i__].a) {\
(OUT)->data[i__].CH1 /= (IN)->data[i__].a;\
(OUT)->data[i__].CH2 /= (IN)->data[i__].a;\
(OUT)->data[i__].CH3 /= (IN)->data[i__].a;\
} else {\
(OUT)->data[x__].CH1 = (ZERO)->CH1;\
(OUT)->data[x__].CH2 = (ZERO)->CH2;\
(OUT)->data[x__].CH3 = (ZERO)->CH3;\
}\
}\
} while (0)
/* Unpremultiply 2 channels in all pixels in an image */
#define libslim_unpremultiply_2_channels_zero(OUT, IN, ZERO, CH1, CH2)\
do {\
size_t x__, y__;\
size_t h__ = (IN)->meta.height;\
size_t w__ = (IN)->meta.width;\
void *in__ = (IN)->data;\
void *out__ = (OUT)->data;\
(OUT)->meta.height = h__;\
(OUT)->meta.width = w__;\
for (y__ = 0; y__ < h__; y__++) {\
for (x__ = 0; x__ < w__; x__++) {\
(OUT)->data[x__] = (IN)->data[x__];\
if ((IN)->data[i__].a) {\
(OUT)->data[x__].CH1 /= (IN)->data[x__].a;\
(OUT)->data[x__].CH2 /= (IN)->data[x__].a;\
} else {\
(OUT)->data[x__].CH1 = (ZERO)->CH1;\
(OUT)->data[x__].CH2 = (ZERO)->CH2;\
}\
}\
(IN)->data += (IN)->meta.width + (IN)->meta.hblank;\
(OUT)->data += (OUT)->meta.width + (OUT)->meta.hblank;\
}\
(IN)->data = in__;\
(OUT)->data = out__;\
} while (0)
/* Unpremultiply 2 channels in all pixels in a row of an image */
#define libslim_unpremultiply_2_channels_zero_row(OUT, IN, ZERO, CH1, CH2)\
do {\
size_t i__;\
size_t n__ = (IN)->meta.width;\
for (i__ = 0; i__ < n__; i__++) {\
(OUT)->data[i__] = (IN)->data[i__];\
if ((IN)->data[i__].a) {\
(OUT)->data[i__].CH1 /= (IN)->data[i__].a;\
(OUT)->data[i__].CH2 /= (IN)->data[i__].a;\
} else {\
(OUT)->data[x__].CH1 = (ZERO)->CH1;\
(OUT)->data[x__].CH2 = (ZERO)->CH2;\
}\
}\
} while (0)
/* Unpremultiply 1 channel in all pixels in an image */
#define libslim_unpremultiply_1_channel_zero(OUT, IN, ZERO, CH)\
do {\
size_t x__, y__;\
size_t h__ = (IN)->meta.height;\
size_t w__ = (IN)->meta.width;\
void *in__ = (IN)->data;\
void *out__ = (OUT)->data;\
(OUT)->meta.height = h__;\
(OUT)->meta.width = w__;\
for (y__ = 0; y__ < h__; y__++) {\
for (x__ = 0; x__ < w__; x__++) {\
(OUT)->data[x__] = (IN)->data[x__];\
if ((IN)->data[i__].a)\
(OUT)->data[x__].CH /= (IN)->data[x__].a;\
else\
(OUT)->data[x__].CH = (ZERO)->CH;\
}\
(IN)->data += (IN)->meta.width + (IN)->meta.hblank;\
(OUT)->data += (OUT)->meta.width + (OUT)->meta.hblank;\
}\
(IN)->data = in__;\
(OUT)->data = out__;\
} while (0)
/* Unpremultiply 1 channel in all pixels in a row of an image */
#define libslim_unpremultiply_1_channel_zero_row(OUT, IN, ZERO, CH)\
do {\
size_t i__;\
size_t n__ = (IN)->meta.width;\
for (i__ = 0; i__ < n__; i__++) {\
(OUT)->data[i__] = (IN)->data[i__];\
if ((IN)->data[i__].a)\
(OUT)->data[i__].CH /= (IN)->data[i__].a;\
else\
(OUT)->data[x__].CH = (ZERO)->CH;\
}\
} while (0)
#endif