summaryrefslogtreecommitdiff
path: root/render
diff options
context:
space:
mode:
Diffstat (limited to 'render')
-rwxr-xr-x[-rw-r--r--]render/Jamfile11
-rwxr-xr-x[-rw-r--r--]render/License.txt0
-rwxr-xr-x[-rw-r--r--]render/Readme.txt0
-rwxr-xr-x[-rw-r--r--]render/afiles0
-rwxr-xr-x[-rw-r--r--]render/makecharts.ksh0
-rwxr-xr-x[-rw-r--r--]render/render.c527
-rwxr-xr-x[-rw-r--r--]render/render.h99
-rwxr-xr-x[-rw-r--r--]render/screens.h0
-rwxr-xr-x[-rw-r--r--]render/thscreen.c14
-rwxr-xr-x[-rw-r--r--]render/thscreen.h6
-rwxr-xr-x[-rw-r--r--]render/timage.c45
11 files changed, 618 insertions, 84 deletions
diff --git a/render/Jamfile b/render/Jamfile
index ca199ab..7c9704b 100644..100755
--- a/render/Jamfile
+++ b/render/Jamfile
@@ -18,15 +18,22 @@ InstallBin $(DESTDIR)$(PREFIX)/bin : $(Executables) ;
#InstallFile $(DESTDIR)$(PREFIX)/h : $(Headers) ;
#InstallLib $(DESTDIR)$(PREFIX)/lib : $(Libraries) ;
+DEFINES += RENDER_TIFF RENDER_PNG ;
+
HDRS = ../h ../numlib $(TIFFINC) $(PNGINC) ;
+if [ GLOB [ NormPaths . ] : vimage.c ] {
+ EXTRASRC = vimage.c ;
+ MainVariant vimage : vimage.c : : STANDALONE_TEST : : : librender ../numlib/libnum
+ $(TIFFLIB) $(JPEGLIB) $(PNGLIB) $(ZLIB) ;
+}
+
# 2D Rendering library
-Library librender : render.c thscreen.c ;
+Library librender : render.c thscreen.c $(EXTRASRC) ;
Main timage : timage.c : : : : : librender ../numlib/libnum
$(TIFFLIB) $(JPEGLIB) $(PNGLIB) $(ZLIB) ;
-
if $(BUILD_JUNK) {
Main tt : tt.c : : : ../plot : : ../numlib/libnum ../plot/libplot ;
}
diff --git a/render/License.txt b/render/License.txt
index a871fcf..a871fcf 100644..100755
--- a/render/License.txt
+++ b/render/License.txt
diff --git a/render/Readme.txt b/render/Readme.txt
index 6ed3ea7..6ed3ea7 100644..100755
--- a/render/Readme.txt
+++ b/render/Readme.txt
diff --git a/render/afiles b/render/afiles
index 26a7384..26a7384 100644..100755
--- a/render/afiles
+++ b/render/afiles
diff --git a/render/makecharts.ksh b/render/makecharts.ksh
index 98ceb11..98ceb11 100644..100755
--- a/render/makecharts.ksh
+++ b/render/makecharts.ksh
diff --git a/render/render.c b/render/render.c
index de34ebd..d6ab108 100644..100755
--- a/render/render.c
+++ b/render/render.c
@@ -37,8 +37,12 @@
#include "aconfig.h"
#include "sort.h"
#include "numlib.h"
-#include "tiffio.h"
-#include "png.h"
+#ifdef RENDER_TIFF
+# include "tiffio.h"
+#endif /* TIFF */
+#ifdef RENDER_PNG
+# include "png.h"
+#endif /* PNG */
#include "render.h"
#include "thscreen.h"
@@ -98,6 +102,8 @@ static void cvt_Lab_to_CIELAB16(double *out, double *in) {
}
/* ------------------------------------------------------------- */
+#ifdef RENDER_PNG
+
/* PNG memory write support */
typedef struct {
unsigned char *buf;
@@ -127,6 +133,8 @@ static void mem_flush_data(png_structp png_ptr) {
return;
}
+#endif /* PNG */
+
/* ------------------------------------------------------------- */
#ifdef CCTEST_PATTERN
@@ -241,8 +249,10 @@ static void render2d_del(render2d *s) {
/* Add a primitive */
static void render2d_add(render2d *s, prim2d *p) {
- if (p == NULL)
- error("render2d: Adding NULL primitive");
+ if (p == NULL) {
+ a1loge(g_log, 1, "render2d: Adding NULL primitive\n");
+ return;
+ }
p->next = s->head;
s->head = p;
@@ -291,8 +301,8 @@ static int colordiff(render2d *s, color2d c1, color2d c2) {
return 0;
}
-#define MIXPOW 1.3
-#define OSAMLS 16
+#define MIXPOW 2.0 // Blending power
+#define OSAMLS 16 // [16] Oversampling
/* Render and write to a TIFF or PNG file or memory buffer */
/* Return NZ on error */
@@ -304,6 +314,7 @@ static int render2d_write(
size_t *olen, /* pointer to returned length of data in buffer */
rend_format fmt /* Output format, tiff/png, file/memory */
) {
+#ifdef RENDER_TIFF
TIFF *wh = NULL;
uint16 samplesperpixel = 0, bitspersample = 0;
uint16 extrasamples = 0; /* Extra "alpha" samples */
@@ -311,8 +322,9 @@ static int render2d_write(
uint16 photometric = 0;
uint16 inkset = 0xffff;
char *inknames = NULL;
- tdata_t *outbuf = NULL;
+#endif
+#ifdef RENDER_PNG
FILE *png_fp = NULL;
png_mem_info png_minfo = { NULL, 0, 0 };
png_structp png_ptr = NULL;
@@ -320,7 +332,9 @@ static int render2d_write(
png_uint_32 png_width = 0, png_height = 0;
int png_bit_depth = 0, png_color_type = 0;
int png_samplesperpixel = 0;
+#endif
+ unsigned char *outbuf = NULL;
unsigned char *dithbuf16 = NULL; /* 16 bit buffer for dithering */
thscreens *screen = NULL; /* dithering object */
int foundfg; /* Found a forground object in this line */
@@ -356,6 +370,7 @@ static int render2d_write(
return 1;
if (fmt == tiff_file) {
+#ifdef RENDER_TIFF
switch (s->csp) {
case w_2d: /* Video style grey */
samplesperpixel = 1;
@@ -399,10 +414,13 @@ static int render2d_write(
inknames = NULL; // ~~99 should fix this
break;
default:
- error("render2d: Illegal colorspace for TIFF file '%s'",filename);
+ a1loge(g_log, 1, "render2d: Illegal colorspace for TIFF file '%s'\n",filename);
+ return 1;
+ }
+ if (samplesperpixel != s->ncc) {
+ a1loge(g_log, 1, "render2d: mismatched number of color components\n");
+ return 1;
}
- if (samplesperpixel != s->ncc)
- error("render2d: mismatched number of color components");
switch (s->dpth) {
case bpc8_2d: /* 8 bits per component */
@@ -412,11 +430,14 @@ static int render2d_write(
bitspersample = 16;
break;
default:
- error("render2d: Illegal bits per component for TIFF file '%s'",filename);
+ a1loge(g_log, 1, "render2d: Illegal bits per component for TIFF file '%s'\n",filename);
+ return 1;
}
- if ((wh = TIFFOpen(filename, "w")) == NULL)
- error("render2d: Can\'t create TIFF file '%s'!",filename);
+ if ((wh = TIFFOpen(filename, "w")) == NULL) {
+ a1loge(g_log, 1, "render2d: Can\'t create TIFF file '%s'!\n",filename);
+ return 1;
+ }
TIFFSetField(wh, TIFFTAG_IMAGEWIDTH, s->pw);
TIFFSetField(wh, TIFFTAG_IMAGELENGTH, s->ph);
@@ -446,9 +467,15 @@ static int render2d_write(
/* Allocate one TIFF line buffer */
outbuf = _TIFFmalloc(TIFFScanlineSize(wh));
+#else
+ a1loge(g_log, 1, "render2d: TIFF format not compiled in\n");
+ return 1;
+
+#endif /* !TIFF */
} else if (fmt == png_file
|| fmt == png_mem) {
+#ifdef RENDER_PNG
char *nmode = "w";
#if !defined(O_CREAT) && !defined(_O_CREAT)
@@ -468,7 +495,8 @@ static int render2d_write(
png_bit_depth = 16;
break;
default:
- error("render2d: Illegal bits per component for PNG file '%s'",filename);
+ a1loge(g_log, 1, "render2d: Illegal bits per component for PNG file '%s'\n",filename);
+ return 1;
}
switch (s->csp) {
@@ -481,17 +509,22 @@ static int render2d_write(
png_samplesperpixel = 3;
break;
default:
- error("render2d: Illegal colorspace for PNG file '%s'",filename);
+ a1loge(g_log, 1, "render2d: Illegal colorspace for PNG file '%s'\n",filename);
+ return 1;
}
if (fmt == png_file) {
- if ((png_fp = fopen(filename, nmode)) == NULL)
- error("render2d: Can\'t create PNG file '%s'!",filename);
+ if ((png_fp = fopen(filename, nmode)) == NULL) {
+ a1loge(g_log, 1, "render2d: Can\'t create PNG file '%s'!\n",filename);
+ return 1;
+ }
}
if ((png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
- NULL, NULL, NULL)) == NULL)
- error("render2d: png_create_write_struct failed");
+ NULL, NULL, NULL)) == NULL) {
+ a1loge(g_log, 1, "render2d: png_create_write_struct failed\n");
+ return 1;
+ }
if (fmt == png_file) {
png_init_io(png_ptr, png_fp);
@@ -499,7 +532,8 @@ static int render2d_write(
if ((png_info = png_create_info_struct(png_ptr)) == NULL) {
png_destroy_write_struct(&png_ptr, &png_info);
- error("render2d: png_create_info_struct failed");
+ a1loge(g_log, 1, "render2d: png_create_info_struct failed\n");
+ return 1;
}
if (setjmp(png_jmpbuf(png_ptr))) {
@@ -556,11 +590,19 @@ static int render2d_write(
}
/* Allocate one PNG line buffer */
- if ((outbuf = malloc((png_bit_depth >> 3) * png_samplesperpixel * s->pw) ) == NULL)
- error("malloc of PNG line buffer failed");
+ if ((outbuf = malloc((png_bit_depth >> 3) * png_samplesperpixel * s->pw) ) == NULL) {
+ a1loge(g_log, 1, "malloc of PNG line buffer failed\n");
+ return 1;
+ }
+#else
+ a1loge(g_log, 1, "render2d: PNG format not compiled in\n\n");
+ return 1;
+#endif /* !PNG */
+
} else {
- error("render2d: Illegal output format %d",fmt);
+ a1loge(g_log, 1, "render2d: Illegal output format %d\n",fmt);
+ return 1;
}
/* Allocate pixel value storage for aliasing detection */
@@ -581,11 +623,11 @@ static int render2d_write(
}
if ((screen = new_thscreens(0, s->ncc, 1.0, 79, scie_16, 8, LEVELS, olevs,
scoo_l, OVERLAP, s->pw, NULL, NULL,
- s->dither == 2 ? 1 : 0, s->quant, s->qcntx)) == NULL)
+ s->dither == 2 ? 1 : 0, s->quant, s->qcntx, s->mxerr)) == NULL)
#else
if ((screen = new_thscreens(0, s->ncc, 1.0, 79, scie_16, 8, 256, NULL,
scoo_l, OVERLAP, s->pw, NULL, NULL,
- s->dither == 2 ? 1 : 0, s->quant, s->qcntx)) == NULL)
+ s->dither == 2 ? 1 : 0, s->quant, s->qcntx, s->mxerr)) == NULL)
#endif
return 1;
if ((dithbuf16 = malloc(s->pw * s->ncc * 2)) == NULL)
@@ -836,26 +878,24 @@ static int render2d_write(
unsigned char *op = ((unsigned char *)outbuf);
/* Copy pixels up to first non-BG */
- for (x = 0; x < s->pw; x++, ip += s->ncc, op += s->ncc) {
- if (pixv1[x][PRIX2D] == -1) {
+ for (st = 0; st < s->pw; st++, ip += s->ncc, op += s->ncc) {
+ if (pixv1[st][PRIX2D] == -1) {
for (j = 0; j < s->ncc; j++)
op[j] = (ip[j] * 255 + 128)/65535;
} else {
- st = x;
break;
}
}
- if (x < s->pw) { /* If there are FG pixels */
+ if (st < s->pw) { /* If there are some FG pixels */
/* Copy down to first non-BG */
ip = ((unsigned short *)dithbuf16) + (s->pw-1) * s->ncc;
op = ((unsigned char *)outbuf) + (s->pw-1) * s->ncc;
- for (x = s->pw-1; x > st; x--, ip -= s->ncc, op -= s->ncc) {
- if (pixv1[x][PRIX2D] == -1) {
+ for (ed = s->pw-1; ed >= st; ed--, ip -= s->ncc, op -= s->ncc) {
+ if (pixv1[ed][PRIX2D] == -1) {
for (j = 0; j < s->ncc; j++)
op[j] = (ip[j] * 255 + 128)/65535;
} else {
- ed = x;
break;
}
}
@@ -891,12 +931,18 @@ static int render2d_write(
}
#endif
if (fmt == tiff_file) {
- if (TIFFWriteScanline(wh, outbuf, y, 0) < 0)
- error ("Failed to write TIFF file '%s' line %d",filename,y);
+#ifdef RENDER_TIFF
+ if (TIFFWriteScanline(wh, outbuf, y, 0) < 0) {
+ a1loge(g_log, 1, "Failed to write TIFF file '%s' line %d\n",filename,y);
+ return 1;
+ }
+#endif /* TIFF */
} else if (fmt == png_file
|| fmt == png_mem) {
+#ifdef RENDER_PNG
png_bytep pixdata = (png_bytep)outbuf;
png_write_rows(png_ptr, &pixdata, 1);
+#endif /* PNG */
}
}
@@ -920,12 +966,15 @@ static int render2d_write(
screen->del(screen);
if (fmt == tiff_file) {
+#ifdef RENDER_TIFF
_TIFFfree(outbuf);
TIFFClose(wh); /* Close Output file */
+#endif /* TIFF */
} else if (fmt == png_file
|| fmt == png_mem) {
+#ifdef RENDER_PNG
free(outbuf);
png_write_end(png_ptr, NULL);
// png_destroy_info_struct(png_ptr, &png_info);
@@ -936,6 +985,7 @@ static int render2d_write(
*obuf = png_minfo.buf;
*olen = png_minfo.off;
}
+#endif /* PNG */
}
so->del(so);
@@ -955,7 +1005,8 @@ int nd, /* Number of channels if c = ncol */
depth2d dpth, /* Pixel depth */
int dither, /* Dither flag, 1 = ordered, 2 = error diffusion, | 0x8000 to dither FG only */
void (*quant)(void *qcntx, double *out, double *in), /* optional quantization func. for edith */
-void *qcntx
+void *qcntx,
+double mxerr /* Maximum error diffusion error */
) {
render2d *s;
@@ -973,10 +1024,16 @@ void *qcntx
}
w = s->fw - s->lm - s->rm;
h = s->fh - s->tm - s->bm;
- if (w < 0.0)
- error("render2d: Left & Right margines %f %f exceed width %f",s->lm,s->rm,s->fw);
- if (h < 0.0)
- error("render2d: Top & Bottom margines %f %f exceed height %f",s->tm,s->bm,s->fh);
+ if (w < 0.0) {
+ a1loge(g_log, 1, "render2d: Left & Right margines %f %f exceed width %f\n",s->lm,s->rm,s->fw);
+ free(s);
+ return NULL;
+ }
+ if (h < 0.0) {
+ a1loge(g_log, 1, "render2d: Top & Bottom margines %f %f exceed height %f\n",s->tm,s->bm,s->fh);
+ free(s);
+ return NULL;
+ }
s->hres = hres;
s->vres = vres;
s->csp = csp;
@@ -986,6 +1043,7 @@ void *qcntx
s->dithfgo = 0x8000 & dither;
s->quant = quant;
s->qcntx = qcntx;
+ s->mxerr = mxerr;
s->del = render2d_del;
s->set_defc = render2d_set_defc;
@@ -1015,12 +1073,18 @@ void *qcntx
break;
case ncol_2d:
case ncol_a_2d:
- if (nd > MXCH2D)
- error("render2d: Too many color chanels %d, max is %d",nd,MXCH2D);
+ if (nd > MXCH2D) {
+ a1loge(g_log, 1, "render2d: Too many color chanels %d, max is %d\n",nd,MXCH2D);
+ free(s);
+ return NULL;
+ }
s->ncc = nd;
break;
- default:
- error("render2d: Illegal colorspace");
+ default: {
+ a1loge(g_log, 1, "render2d: Illegal colorspace\n");
+ free(s);
+ return NULL;
+ }
}
return s;
}
@@ -1309,8 +1373,11 @@ color2d c[3] /* Corresponding colors */
tt[1][i] = vv[i][1];
tt[2][i] = 1.0;
}
- if (inverse3x3(s->be, tt))
- error("trivs2d: Matrix inversion failed");
+ if (inverse3x3(s->be, tt)) {
+ a1loge(g_log, 1, "trivs2d: Matrix inversion failed\n");
+ free(s);
+ return NULL;
+ }
/* Copy vertex colors */
for (i = 0; i < 3; i++) {
@@ -1322,6 +1389,212 @@ color2d c[3] /* Corresponding colors */
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Flat shaded rectangle */
+
+/* Render the polyangle object at location. Return nz if in primitive */
+static int poly2d_rend(prim2d *ss, color2d rv, double x, double y) {
+ poly2d *s = (poly2d *)ss;
+ int i, j, pip = 0;
+
+ /* Classic point in polygon test */
+ for (i = 0, j = s->n-1; i < s->n; j = i++) {
+ if ( ((s->co[i][1] > y) != (s->co[j][1] > y))
+ && (x < (s->co[j][0] - s->co[i][0]) * (y - s->co[i][1])
+ / (s->co[j][1] - s->co[i][1]) + s->co[i][0]))
+ pip = !pip;
+ }
+ if (pip == 0)
+ return 0;
+
+ for (j = 0; j < s->ncc; j++)
+ rv[j] = s->c[j];
+
+ rv[PRIX2D] = s->ix;
+
+ return 1;
+}
+
+prim2d *new_poly2d(
+render2d *ss,
+int n,
+double v[][2],
+color2d c
+) {
+ int i, j;
+ poly2d *s;
+
+ if (n < 3)
+ return NULL;
+
+ /* Allocate array at end to hold vertex locations */
+ if ((s = (poly2d *)calloc(1, sizeof(poly2d) + (n-1) * 2 * sizeof(double))) == NULL) {
+ return NULL;
+ }
+
+ /* Set bounding box and coords */
+ s->x0 = 1e38;
+ s->y0 = 1e38;
+ s->x1 = -1e39;
+ s->y1 = -1e39;
+ for (i = 0; i < n; i++) {
+ double x, y;
+ x = v[i][0] - ss->lm; /* Account for margines */
+ y = v[i][1] - ss->bm;
+ if (x < s->x0)
+ s->x0 = x;
+ if (y < s->y0)
+ s->y0 = y;
+ if (x > s->x1)
+ s->x1 = x;
+ if (y > s->y1)
+ s->y1 = y;
+ s->co[i][0] = x;
+ s->co[i][1] = y;
+ }
+ s->n = n;
+
+
+ s->ncc = ss->ncc;
+ s->del = prim2d_del;
+ s->rend = poly2d_rend;
+
+ for (j = 0; j < s->ncc; j++)
+ s->c[j] = c[j];
+
+ return (prim2d *)s;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Flat shaded disk/circle */
+
+/* Render the disk object at location. Return nz if in primitive */
+static int disk2d_rend(prim2d *ss, color2d rv, double x, double y) {
+ disk2d *s = (disk2d *)ss;
+ int j;
+ double rr;
+
+ /* Position relative to center */
+ x -= s->cx;
+ y -= s->cy;
+
+ /* Radius squared */
+ rr = x * x + y * y;
+
+ /* Within outer and inner radius suqared ? */
+ if (rr > s->orr
+ || (s->irr > 0.0 && rr < s->irr))
+ return 0;
+
+ for (j = 0; j < s->ncc; j++)
+ rv[j] = s->c[j];
+
+ rv[PRIX2D] = s->ix;
+
+ return 1;
+}
+
+/* Center and radius */
+prim2d *new_disk2d(
+render2d *ss,
+double x,
+double y,
+double r,
+color2d c
+) {
+ int j;
+ disk2d *s;
+
+ if ((s = (disk2d *)calloc(1, sizeof(disk2d))) == NULL) {
+ return NULL;
+ }
+
+ /* Account for margines */
+ x -= ss->lm;
+ y -= ss->bm;
+
+ s->ncc = ss->ncc;
+ s->del = prim2d_del;
+ s->rend = disk2d_rend;
+
+ s->cx = x;
+ s->cy = y;
+
+ /* Outer radius squared */
+ s->orr = r * r;
+ s->irr = 0.0;
+
+ /* Set bounding box */
+ s->x0 = x - r;
+ s->y0 = y - r;
+ s->x1 = x + r;
+ s->y1 = y + r;
+
+ /* Copy color */
+ for (j = 0; j < s->ncc; j++)
+ s->c[j] = c[j];
+
+ return (prim2d *)s;
+}
+
+disk2d *clone_disk2d(disk2d *s) {
+ disk2d *d;
+ if ((d = (disk2d *)calloc(1, sizeof(disk2d))) == NULL) {
+ return NULL;
+ }
+
+ *d = *s;
+
+ return d;
+}
+
+/* Center, radius and line width */
+void add_circle2d(render2d *ss, double x, double y, double r, double w, color2d c) {
+ disk2d *s1, *s2, *s3, *s4;
+ double a, b;
+
+ w *= 0.5; /* half width */
+
+ /* Disk at outer extent of line width */
+ s1 = (disk2d *)new_disk2d(ss, x, y, r + w, c);
+
+ /* Inner radius at inner extend of line width */
+ if (w < r) {
+ s1->irr = (r-w) * (r-w);
+ }
+
+ /* Make 4 copies with tighter bounding boxes */
+ s2 = clone_disk2d(s1);
+ s3 = clone_disk2d(s1);
+ s4 = clone_disk2d(s1);
+
+ a = 0.5 * sqrt(2.0); /* Half width of box */
+ b = (1.0 - a); /* Height of box */
+ a *= r;
+ b *= r;
+
+ s1->x0 = s1->cx - a - w;
+ s1->x1 = s1->cx + a + w;
+ s1->y1 = s1->y0 + b + 2.0 * w;
+
+ s2->x1 = s2->cx + a + w;
+ s2->x0 = s2->cx - a - w;
+ s2->y0 = s2->y1 - b - 2.0 * w;
+
+ s3->x1 = s3->x0 + b + 2.0 * w;
+ s3->y0 = s3->cy - a - w;
+ s3->y1 = s3->cy + a + w;
+
+ s4->x0 = s4->x1 - b - 2.0 * w;
+ s4->y0 = s4->cy - a - w;
+ s4->y1 = s4->cy + a + w;
+
+ ss->add(ss, (prim2d *)s1);
+ ss->add(ss, (prim2d *)s2);
+ ss->add(ss, (prim2d *)s3);
+ ss->add(ss, (prim2d *)s4);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* A single Rounded end line. Mainly for supporting Hershey text output. */
/* Render the line object at this location */
@@ -1538,28 +1811,9 @@ hyfont fonts[];
double h2dbl(unsigned char c) { return (double)(c-'R'); }
-/* Add a text character at the given location using lines */
-static void add_char_imp(
-render2d *s,
-double *xinc, /* Add increment to next character */
-double *yinc,
-font2d fo, /* Font to use */
-char ch, /* Character code to be printed */
-double x, double y, /* Location of bottom left of normal orientation text */
-double h, /* Height of text in normal orientation */
-int or, /* Orintation, 0 = right, 1 = down, 2 = left, 3 = right */
-color2d c, /* Color of text */
-int add /* NZ if character is to be added */
-) {
- hyfont *fp = &fonts[fo];
- char *cp = fp->enc[ch % 128];
- double lm, rm;
- double x0, y0, x1 = 0.0, y1 = 0.0;
- int got1 = 0;
- double w = fp->sw * h;
- double tx, ty;
- double mat[2][2]; /* Transformation matrix */
-
+/* Convert orientation 0 = right, 1 = down, 2 = left, 3 = right */
+/* into transform matrix */
+static void or2mat(double mat[2][2], int or) {
if (or == 0) {
mat[0][0] = 1.0;
mat[0][1] = 0.0;
@@ -1581,6 +1835,53 @@ int add /* NZ if character is to be added */
mat[1][0] = 1.0;
mat[1][1] = 0.0;
}
+}
+
+/* Convert an angle in radians */
+/* into transform matrix */
+static void rad2mat(double mat[2][2], double rad) {
+ double sinv = sin(rad);
+ double cosv = cos(rad);
+ mat[0][0] = cosv;
+ mat[0][1] = -sinv;
+ mat[1][0] = sinv;
+ mat[1][1] = cosv;
+}
+
+/* Convert an angle in degrees (0 = right) */
+/* into transform matrix */
+void deg2mat(double mat[2][2], double a) {
+ double rad = a * 3.1415926/180.0;
+ rad2mat(mat, rad);
+}
+
+/* Convert a vector into a rotation matrix */
+void vec2mat(double mat[2][2], double dx, double dy) {
+ double rad = atan2(dy, dx);
+ rad2mat(mat, rad);
+}
+
+/* Add a text character at the given location using lines */
+static void add_char_imp(
+render2d *s,
+double *xinc, /* Add increment to next character */
+double *yinc,
+font2d fo, /* Font to use */
+char ch, /* Character code to be printed */
+double x, double y, /* Location of bottom left of normal orientation text */
+double h, /* Height of text in normal orientation */
+double mat[2][2], /* Unity transformation matrix */
+color2d c, /* Color of text */
+int add /* NZ if character is to be added */
+) {
+ hyfont *fp = &fonts[fo];
+ char *cp = fp->enc[ch % 128];
+ double lm, rm;
+ double x0, y0, x1 = 0.0, y1 = 0.0;
+ int got1 = 0;
+ double w = fp->sw * h;
+ double tx, ty;
+
if (cp[0] == '\000' || cp[1] == '\000') {
if (xinc != NULL && yinc != NULL) {
*xinc = 0.0;
@@ -1625,6 +1926,89 @@ int add /* NZ if character is to be added */
}
/* Add a text character at the given location using lines */
+/* (matrix orientation version) */
+void add_char2dmat(
+render2d *s,
+double *xinc, /* Add increment to next character */
+double *yinc,
+font2d fo, /* Font to use */
+char ch, /* Character code to be printed */
+double x, double y, /* Location of bottom left of normal orientation text */
+double h, /* Height of text in normal orientation */
+double mat[2][2], /* Unity orientation matrix */
+color2d c /* Color of text */
+) {
+ add_char_imp(s, xinc, yinc, fo, ch, x, y, h, mat, c, 1);
+}
+
+/* Return the total width of the character without adding it */
+/* (matrix orientation version) */
+void meas_char2dmat(
+render2d *s,
+double *xinc, /* Add increment to next character */
+double *yinc,
+font2d fo, /* Font to use */
+char ch, /* Character code to be printed */
+double h, /* Height of text in normal orientation */
+double mat[2][2] /* Unity orientation matrix */
+) {
+ color2d c;
+ add_char_imp(s, xinc, yinc, fo, ch, 0.0, 0.0, h, mat, c, 0);
+}
+
+/* Add a string from the given location using lines. */
+/* Return the total width of the string */
+/* (matrix orientation version) */
+void add_string2dmat(
+render2d *s,
+double *xinc, /* Add increment to next character */
+double *yinc,
+font2d fo, /* Font to use */
+char *string, /* Character code to be printed */
+double x, double y, /* Location of bottom left of normal orientation text */
+double h, /* Height of text in normal orientation */
+double mat[2][2], /* Unity orientation matrix */
+color2d c /* Color of text */
+) {
+ char *ch;
+ double xoff = 0.0, yoff = 0.0;
+
+ for (ch = string; *ch != '\000'; ch++) {
+ add_char2dmat(s, &xoff, &yoff, fo, *ch, x + xoff, y + yoff, h, mat, c);
+ }
+
+ if (xinc != NULL)
+ *xinc = xoff;
+ if (yinc != NULL)
+ *yinc = yoff;
+}
+
+/* Return the total width of the string without adding it */
+/* (matrix orientation version) */
+void meas_string2dmat(
+struct _render2d *s,
+double *xinc, /* Add increment to next character */
+double *yinc,
+font2d fo, /* Font to use */
+char *string, /* Character code to be printed */
+double h, /* Height of text in normal orientation */
+double mat[2][2] /* Unity orientation matrix */
+) {
+ char *ch;
+ double xoff = 0.0, yoff = 0.0;
+
+ for (ch = string; *ch != '\000'; ch++) {
+ meas_char2dmat(s, &xoff, &yoff, fo, *ch, h, mat);
+ }
+
+ if (xinc != NULL)
+ *xinc = xoff;
+ if (yinc != NULL)
+ *yinc = yoff;
+}
+
+
+/* Add a text character at the given location using lines */
void add_char2d(
render2d *s,
double *xinc, /* Add increment to next character */
@@ -1636,7 +2020,10 @@ double h, /* Height of text in normal orientation */
int or, /* Orintation, 0 = right, 1 = down, 2 = left, 3 = right */
color2d c /* Color of text */
) {
- add_char_imp(s, xinc, yinc, fo, ch, x, y, h, or, c, 1);
+ double mat[2][2];
+
+ or2mat(mat, or);
+ add_char_imp(s, xinc, yinc, fo, ch, x, y, h, mat, c, 1);
}
/* Return the total width of the character without adding it */
@@ -1649,9 +2036,11 @@ char ch, /* Character code to be printed */
double h, /* Height of text in normal orientation */
int or /* Orintation, 0 = right, 1 = down, 2 = left, 3 = right */
) {
+ double mat[2][2];
color2d c;
- add_char_imp(s, xinc, yinc, fo, ch, 0.0, 0.0, h, or, c, 0);
+ or2mat(mat, or);
+ add_char_imp(s, xinc, yinc, fo, ch, 0.0, 0.0, h, mat, c, 0);
}
/* Add a string from the given location using lines. */
diff --git a/render/render.h b/render/render.h
index c060ebc..26b7028 100644..100755
--- a/render/render.h
+++ b/render/render.h
@@ -90,8 +90,8 @@ struct _rect2d {
PRIM_STRUCT
double rx0, ry0, rx1, ry1; /* Rectangle verticies */
color2d c; /* Color of rectangle (if dpat == NULL) */
- double (*dpat)[MXPATSIZE][MXPATSIZE][TOTC2D];
- int dp_w, dp_h;
+ double (*dpat)[MXPATSIZE][MXPATSIZE][TOTC2D]; /* Special for ChromeCast experiments */
+ int dp_w, dp_h; /* dpat dimensions */
}; typedef struct _rect2d rect2d;
prim2d *new_rect2d(struct _render2d *s, double x, double y, double w, double h, color2d c);
@@ -122,6 +122,48 @@ struct _trivs2d {
prim2d *new_trivs2d(struct _render2d *s, double v[3][2], color2d c[3]);
/* ------------------------------------ */
+/* Polygon */
+
+/* Solid polygon primitive */
+struct _poly2d {
+ PRIM_STRUCT
+ color2d c; /* Color of polyangle (if dpat == NULL) */
+ int n; /* Number of verticies */
+ double co[1][2]; /* Array of [n][2] verticies */
+}; typedef struct _poly2d poly2d;
+
+prim2d *new_poly2d(struct _render2d *s, int n, double v[][2], color2d c);
+
+#ifdef NEVER
+int pnpoly(int nvert, float *vertx, float *verty, float testx, float testy) {
+ int i, j, c = 0;
+ for (i = 0, j = nvert-1; i < nvert; j = i++) {
+ if ( ((verty[i]>testy) != (verty[j]>testy)) &&
+ (testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) )
+ c = !c;
+ }
+ return c;
+}
+
+#endif // NEVER
+
+/* ------------------------------------ */
+
+/* Circular disk/line primitive */
+struct _disk2d {
+ PRIM_STRUCT
+ double cx, cy; /* Center */
+ color2d c; /* Color of disk/line */
+ double orr, irr; /* Outer radius squared, inner radius squared (0.0 if disk) */
+}; typedef struct _disk2d disk2d;
+
+/* Center and radius */
+prim2d *new_disk2d(struct _render2d *s, double x, double y, double r, color2d c);
+
+/* Center, radius and line width */
+void add_circle2d(struct _render2d *s, double x, double y, double r, double w, color2d c);
+
+/* ------------------------------------ */
/* A single line. */
struct _line2d {
@@ -137,6 +179,7 @@ struct _line2d {
prim2d *new_line2d(struct _render2d *s, double x0, double y0, double x1, double y1, double w, int cap, color2d c);
/* ------------------------------------ */
+/* Comound primitives */
/* add a dashed line */
void add_dashed_line2d(
@@ -185,6 +228,54 @@ double h, /* Height of text in normal orientation */
int or /* Orintation, 0 = right, 1 = down, 2 = left, 3 = up */
);
+
+/* Convert an angle in degrees (0 = right) */
+/* into transform matrix */
+void deg2mat(double mat[2][2], double a);
+
+/* Convert a vector into a rotation matrix */
+void vec2mat(double mat[2][2], double dx, double dy);
+
+/* Add a text character at the given location using lines */
+/* (matrix orientation version) */
+void add_char2dmat(
+struct _render2d *s,
+double *xinc, /* Return increment in position for next character */
+double *yinc,
+font2d fo, /* Font to use */
+char ch, /* Character code to be printed */
+double x, double y, /* Location of bottom left of normal orientation text */
+double h, /* Height of text in normal orientation */
+double mat[2][2], /* Unity orientation matrix */
+color2d c /* Color of text */
+);
+
+/* Add a string from the given location using lines. */
+/* (matrix orientation version) */
+void add_string2dmat(
+struct _render2d *s,
+double *xinc, /* Return increment in position for next character */
+double *yinc,
+font2d fo, /* Font to use */
+char *string, /* Character code to be printed */
+double x, double y, /* Location of bottom left of normal orientation text */
+double h, /* Height of text in normal orientation */
+double mat[2][2], /* Unity orientation matrix */
+color2d c /* Color of text */
+);
+
+/* Return the total width of the string without adding it */
+/* (matrix orientation version) */
+void meas_string2dmat(
+struct _render2d *s,
+double *xinc, /* Return increment in position for next character */
+double *yinc,
+font2d fo, /* Font to use */
+char *string, /* Character code to be printed */
+double h, /* Height of text in normal orientation */
+double mat[2][2] /* Unity orientation matrix */
+);
+
/* ------------------------------------ */
/* Type of output to save to. */
@@ -214,6 +305,7 @@ struct _render2d {
int dithfgo; /* Dither F.G. only flag */
void (*quant)(void *qcntx, double *out, double *in); /* optional quantization func. for edith */
void *qcntx;
+ double mxerr; /* Maximum error diffusion error */
color2d defc; /* Default color value */
@@ -256,7 +348,8 @@ render2d *new_render2d(
int dither, /* Dither flag, 1 = ordered, 2 = error diffusion, | 0x8000 to dither FG only */
/* | 0x4000 don't anti-alias by averaging pixels together. */
void (*quant)(void *qcntx, double *out, double *in), /* optional quantization func. for edith */
- void *qcntx
+ void *qcntx,
+ double mxerr /* Maximum error diffusion error */
);
#endif /* RENDER2D_H */
diff --git a/render/screens.h b/render/screens.h
index 353597b..353597b 100644..100755
--- a/render/screens.h
+++ b/render/screens.h
diff --git a/render/thscreen.c b/render/thscreen.c
index 8523e38..7c115f3 100644..100755
--- a/render/thscreen.c
+++ b/render/thscreen.c
@@ -130,6 +130,16 @@ void screen_edscreens(
for (; ip != ein1; ip += pinc, op += pinc, x += xinc) {
double ov[THMXCH2D], tv[THMXCH2D], ev[THMXCH2D];
+ /* Limit error propogation if asked */
+ if (t->mxerr != 0.0) {
+ for (j = 0; j < t->np; j++) {
+ if (t->ebuf[j][x] < -t->mxerr)
+ t->ebuf[j][x] = -t->mxerr;
+ else if (t->ebuf[j][x] > t->mxerr)
+ t->ebuf[j][x] = t->mxerr;
+ }
+ }
+
/* For each plane */
for (j = 0; j < t->np; j++) {
tv[j] = t->luts[j][ip[j]] / 65535.0; /* 0.0 - 1.0 value */
@@ -253,7 +263,8 @@ thscreens *new_thscreens(
double (**lutfunc)(void *cntx, double in), /* List of callback functions, NULL if none */
int edif, /* nz if using error diffusion */
void (*quant)(void *qcntx, double *out, double *in), /* optional quantization func. for edif */
- void *qcntx
+ void *qcntx,
+ double mxerr /* If error diffusion anf != 0, max error to propogate */
) {
thscreens *t;
int i, bi = -1;
@@ -287,6 +298,7 @@ thscreens *new_thscreens(
t->qcntx = qcntx;
t->mxwidth = mxwidth;
+ t->mxerr = mxerr;
t->lastyoff = -1;
/* Allocate and initialise a next line error buffer. */
diff --git a/render/thscreen.h b/render/thscreen.h
index 9a504bc..f14a8a4 100644..100755
--- a/render/thscreen.h
+++ b/render/thscreen.h
@@ -59,7 +59,8 @@ struct _thscreens {
/* ebuf[][-1] is used for next pixel error */
void (*quant)(void *qcntx, double *out, double *in); /* optional quantization func. for edif */
- void *qcntx; /* Context for quant */
+ void *qcntx; /* Context for quant */
+ double mxerr; /* if != 0, max error to propogate */
sobol *so; /* Random number generator for error diffusion */
@@ -99,7 +100,8 @@ thscreens *new_thscreens(
double (**lutfunc)(void *cntx, double in), /* List of callback function, NULL if none */
int edif, /* nz if using error diffusion */
void (*quant)(void *qcntx, double *out, double *in), /* optional quantization func. for edif */
- void *qcntx
+ void *qcntx,
+ double mxerr /* If error diffusion anf != 0, max error to propogate */
);
/* ---------------------------- */
diff --git a/render/timage.c b/render/timage.c
index 2b610d1..20c999a 100644..100755
--- a/render/timage.c
+++ b/render/timage.c
@@ -39,7 +39,7 @@
#include "render.h"
#define DEF_DPI 200
-#define DITHER 0 /* 1 for test 8 bit dithering, 2 for test error diffusion */
+#define DITHER 0x8002 /* [0] 1 for test 8 bit dithering, 2 for test error diffusion */
/* 0x8001 for dithering FG only, 0x8002 for err. diff. FG only */
#undef PNG_MEM /* Test PNG save to memory */
@@ -76,7 +76,7 @@ int main(int argc, char *argv[]) {
char outname[MAXNAMEL+1] = { 0 }; /* Output TIFF name */
render2d *r;
color2d c;
- double vv[4][2];
+ double vv[6][2];
color2d cc[4];
double gbf = 1.0; /* Grey blend factor */
double w, h; /* Size of page in mm */
@@ -184,7 +184,7 @@ int main(int argc, char *argv[]) {
if (cmyk)
error("CMYK not supported for test chart");
- if ((r = new_render2d(w, h, NULL, res, res, rgb_2d, 0, depth, DITHER, NULL, NULL)) == NULL) {
+ if ((r = new_render2d(w, h, NULL, res, res, rgb_2d, 0, depth, DITHER, NULL, NULL, 0.0)) == NULL) {
error("new_render2d() failed");
}
@@ -248,6 +248,36 @@ int main(int argc, char *argv[]) {
cc[2][2] = 0.0;
r->add(r, new_trivs2d(r, vv, cc));
+ /* A circular disk right of the shaded triangle */
+ c[0] = 0.0; /* Cyan */
+ c[1] = 1.0;
+ c[2] = 1.0;
+ r->add(r, new_disk2d(r, 65.0, 29.0, 9.0, c));
+
+ /* A circle right of the disk */
+ c[0] = 1.0; /* Magenta */
+ c[1] = 0.0;
+ c[2] = 1.0;
+ add_circle2d(r, 90.0, 29.0, 9.0, 2.0, c);
+
+
+ /* A polygon */
+ c[0] = 0.8; /* Brown */
+ c[1] = 0.8;
+ c[2] = 0.2;
+
+ vv[0][0] = 115.0;
+ vv[0][1] = 20.0;
+ vv[1][0] = 130.0;
+ vv[1][1] = 20.0;
+ vv[2][0] = 140.0;
+ vv[2][1] = 35.0;
+ vv[3][0] = 125.0;
+ vv[3][1] = 25.0;
+ vv[4][0] = 110.0;
+ vv[4][1] = 40.0;
+ r->add(r, new_poly2d(r, 5, vv, c));
+
/* A diagonal wide line */
c[0] = 0.0;
c[1] = 0.0;
@@ -274,11 +304,12 @@ int main(int argc, char *argv[]) {
/* A test string */
add_string2d(r, NULL, NULL, fo, "Testing 1234", 10.0, 70.0, 7.0, 3, c);
+ /* The full font */
{
double x, y;
char chars[33];
- x = 10.0;
+ x = 15.0;
y = 125.0;
for (j = 0; j < 4; j++) {
for (i = 0; i < 32; i++)
@@ -309,7 +340,7 @@ int main(int argc, char *argv[]) {
h = (1.0 + 2.0 * bb) * hh;
w = (4.0 * bb + 0.25 + 2.0 * r3o2) * hh;
- if ((r = new_render2d(w, h, NULL, res, res, cmyk ? cmyk_2d : rgb_2d, 0, depth, DITHER, NULL, NULL)) == NULL) {
+ if ((r = new_render2d(w, h, NULL, res, res, cmyk ? cmyk_2d : rgb_2d, 0, depth, DITHER, NULL, NULL, 0.0)) == NULL) {
error("new_render2d() failed");
}
@@ -577,7 +608,7 @@ int main(int argc, char *argv[]) {
h = (1.0 + 2.0 * bb) * hh;
w = (2.0 * bb + 0.20 * 7.0) * hh;
- if ((r = new_render2d(w, h, NULL, res, res, rgb_2d, 0, depth, DITHER, NULL, NULL)) == NULL) {
+ if ((r = new_render2d(w, h, NULL, res, res, rgb_2d, 0, depth, DITHER, NULL, NULL, 0.0)) == NULL) {
error("new_render2d() failed");
}
@@ -647,7 +678,7 @@ int main(int argc, char *argv[]) {
bs = (bb * hh)/(schart + 1.0);
ss = hh * (1.0 - bb)/schart;
- if ((r = new_render2d(w, h, NULL, res, res, lab_2d, 0, depth, DITHER, NULL, NULL)) == NULL) {
+ if ((r = new_render2d(w, h, NULL, res, res, lab_2d, 0, depth, DITHER, NULL, NULL, 0.0)) == NULL) {
error("new_render2d() failed");
}