From c0b89ac5bfb90835ef01573267020e42d4fe070c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Sun, 23 Aug 2015 12:17:05 +0200 Subject: Imported Upstream version 1.8.0 --- render/Jamfile | 11 +- render/License.txt | 0 render/Readme.txt | 0 render/afiles | 0 render/makecharts.ksh | 0 render/render.c | 527 +++++++++++++++++++++++++++++++++++++++++++------- render/render.h | 99 +++++++++- render/screens.h | 0 render/thscreen.c | 14 +- render/thscreen.h | 6 +- render/timage.c | 45 ++++- 11 files changed, 618 insertions(+), 84 deletions(-) mode change 100644 => 100755 render/Jamfile mode change 100644 => 100755 render/License.txt mode change 100644 => 100755 render/Readme.txt mode change 100644 => 100755 render/afiles mode change 100644 => 100755 render/makecharts.ksh mode change 100644 => 100755 render/render.c mode change 100644 => 100755 render/render.h mode change 100644 => 100755 render/screens.h mode change 100644 => 100755 render/thscreen.c mode change 100644 => 100755 render/thscreen.h mode change 100644 => 100755 render/timage.c (limited to 'render') diff --git a/render/Jamfile b/render/Jamfile old mode 100644 new mode 100755 index ca199ab..7c9704b --- 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 old mode 100644 new mode 100755 diff --git a/render/Readme.txt b/render/Readme.txt old mode 100644 new mode 100755 diff --git a/render/afiles b/render/afiles old mode 100644 new mode 100755 diff --git a/render/makecharts.ksh b/render/makecharts.ksh old mode 100644 new mode 100755 diff --git a/render/render.c b/render/render.c old mode 100644 new mode 100755 index de34ebd..d6ab108 --- 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++) { @@ -1321,6 +1388,212 @@ color2d c[3] /* Corresponding colors */ return (prim2d *)s; } +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +/* 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. */ @@ -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; @@ -1624,6 +1925,89 @@ int add /* NZ if character is to be added */ *yinc += mat[1][0] * tx + mat[1][1] * ty; } +/* 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, @@ -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 old mode 100644 new mode 100755 index c060ebc..26b7028 --- 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); @@ -121,6 +121,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. */ @@ -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 old mode 100644 new mode 100755 diff --git a/render/thscreen.c b/render/thscreen.c old mode 100644 new mode 100755 index 8523e38..7c115f3 --- 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 old mode 100644 new mode 100755 index 9a504bc..f14a8a4 --- 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 old mode 100644 new mode 100755 index 2b610d1..20c999a --- 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"); } -- cgit v1.2.3