--- /dev/null
+/*
+Render utilities
+*/
+#include "imager.h"
+
+#define RENDER_MAGIC 0x765AE
+
+typedef void (*render_color_f)(i_render *, int, int, int, unsigned char const *src, i_color const *color);
+
+#code
+
+static void IM_SUFFIX(render_color_alpha)(i_render *r, int x, int y, int width, unsigned char const *src, i_color const *color);
+static void IM_SUFFIX(render_color_13)(i_render *r, int x, int y, int width, unsigned char const *src, i_color const *color);
+
+static render_color_f IM_SUFFIX(render_color_tab)[] =
+ {
+ NULL,
+ IM_SUFFIX(render_color_13),
+ IM_SUFFIX(render_color_alpha),
+ IM_SUFFIX(render_color_13),
+ IM_SUFFIX(render_color_alpha),
+ };
+
+#/code
+
+void
+i_render_init(i_render *r, i_img *im, int width) {
+ r->magic = RENDER_MAGIC;
+ r->im = im;
+ r->width = width;
+ r->line_8 = NULL;
+ r->line_double = NULL;
+#code im->bits <= 8
+ r->IM_SUFFIX(line) = mymalloc(sizeof(i_fcolor) * width);
+#/code
+}
+
+void
+i_render_done(i_render *r) {
+ if (r->line_8)
+ myfree(r->line_8);
+ else
+ myfree(r->line_double);
+ r->magic = 0;
+}
+
+void
+i_render_color(i_render *r, int x, int y, int width, unsigned char const *src,
+ i_color const *color) {
+ i_img *im = r->im;
+ if (y < 0 || y >= im->ysize)
+ return;
+ if (x < 0) {
+ width += x;
+ src -= x;
+ x = 0;
+ }
+ if (x + width > im->xsize) {
+ width = im->xsize - x;
+ }
+ if (x >= im->xsize || x + width <= 0 || width <= 0)
+ return;
+
+ /* avoid as much work as we can */
+ while (width > 0 && *src == 0) {
+ --width;
+ ++src;
+ ++x;
+ }
+ while (width > 0 && src[width-1] == 0) {
+ --width;
+ }
+ if (!width)
+ return;
+
+ /* make sure our line buffer is big enough */
+ if (width > r->width) {
+ int new_width = r->width * 2;
+ if (new_width < width)
+ new_width = width;
+
+ if (r->line_8)
+ r->line_8 = myrealloc(r->line_8, sizeof(i_color) * new_width);
+ else
+ r->line_double = myrealloc(r->line_double, sizeof(i_fcolor) * new_width);
+ }
+
+#code r->im->bits <= 8
+ (IM_SUFFIX(render_color_tab)[im->channels])(r, x, y, width, src, color);
+#/code
+}
+
+static void
+dump_src(const char *note, unsigned char const *src, int width) {
+ int i;
+ printf("%s - %p/%d\n", note, src, width);
+ for (i = 0; i < width; ++i) {
+ printf("%02x ", src[i]);
+ }
+ putchar('\n');
+}
+
+#code
+
+static
+void
+IM_SUFFIX(render_color_13)(i_render *r, int x, int y, int width,
+ unsigned char const *src, i_color const *color) {
+ i_img *im = r->im;
+ IM_COLOR *linep = r->IM_SUFFIX(line);
+ int ch, channels = im->channels;
+ int fetch_offset;
+#undef STORE_COLOR
+#ifdef IM_EIGHT_BIT
+#define STORE_COLOR (*color)
+#else
+ i_fcolor fcolor;
+
+ for (ch = 0; ch < channels; ++ch) {
+ fcolor.channel[ch] = color->channel[ch] / 255.0;
+ }
+#define STORE_COLOR fcolor
+#endif
+
+ fetch_offset = 0;
+ while (fetch_offset < width && *src == 0xFF) {
+ *linep++ = STORE_COLOR;
+ ++src;
+ ++fetch_offset;
+ }
+ IM_GLIN(im, x+fetch_offset, x+width, y, linep);
+ while (fetch_offset < width) {
+#ifdef IM_EIGHT_BIT
+ IM_WORK_T alpha = *src++;
+#else
+ IM_WORK_T alpha = *src++ / 255.0;
+#endif
+ if (alpha == IM_SAMPLE_MAX)
+ *linep = STORE_COLOR;
+ else if (alpha) {
+ for (ch = 0; ch < channels; ++ch) {
+ linep->channel[ch] = (linep->channel[ch] * (IM_SAMPLE_MAX - alpha)
+ + STORE_COLOR.channel[ch] * alpha) / IM_SAMPLE_MAX;
+ }
+ }
+ ++linep;
+ ++fetch_offset;
+ }
+ IM_PLIN(im, x, x+width, y, r->IM_SUFFIX(line));
+}
+
+static
+void
+IM_SUFFIX(render_color_alpha)(i_render *r, int x, int y, int width,
+ unsigned char const *src, i_color const *color) {
+ IM_COLOR *linep = r->IM_SUFFIX(line);
+ int ch;
+ int alpha_channel = r->im->channels - 1;
+ int fetch_offset;
+#undef STORE_COLOR
+#ifdef IM_EIGHT_BIT
+#define STORE_COLOR (*color)
+#else
+ i_fcolor fcolor;
+
+ for (ch = 0; ch < r->im->channels; ++ch) {
+ fcolor.channel[ch] = color->channel[ch] / 255.0;
+ }
+#define STORE_COLOR fcolor
+#endif
+
+ fetch_offset = 0;
+ while (fetch_offset < width && *src == 0xFF) {
+ *linep++ = STORE_COLOR;
+ ++src;
+ ++fetch_offset;
+ }
+ IM_GLIN(r->im, x+fetch_offset, x+width, y, linep);
+ while (fetch_offset < width) {
+#ifdef IM_EIGHT_BIT
+ IM_WORK_T src_alpha = *src++;
+#else
+ IM_WORK_T src_alpha = *src++ / 255.0;
+#endif
+ if (src_alpha == IM_SAMPLE_MAX)
+ *linep = STORE_COLOR;
+ else if (src_alpha) {
+ IM_WORK_T remains = - src_alpha;
+ IM_WORK_T orig_alpha = linep->channel[alpha_channel];
+ IM_WORK_T dest_alpha = src_alpha + (remains * orig_alpha) / IM_SAMPLE_MAX;
+ for (ch = 0; ch < alpha_channel; ++ch) {
+ linep->channel[ch] = ( src_alpha * STORE_COLOR.channel[ch]
+ + remains * linep->channel[ch] * orig_alpha / IM_SAMPLE_MAX
+ ) / dest_alpha;
+ }
+ linep->channel[alpha_channel] = dest_alpha;
+ }
+ ++linep;
+ ++fetch_offset;
+ }
+ IM_PLIN(r->im, x, x+width, y, r->IM_SUFFIX(line));
+}
+
+#/code