17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier * Copyright (c) 1998 by Lucent Technologies.
37dd7cddfSDavid du Colombier * Permission to use, copy, modify, and distribute this software for any
47dd7cddfSDavid du Colombier * purpose without fee is hereby granted, provided that this entire notice
57dd7cddfSDavid du Colombier * is included in all copies of any software which is or includes a copy
67dd7cddfSDavid du Colombier * or modification of this software.
77dd7cddfSDavid du Colombier *
87dd7cddfSDavid du Colombier * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
97dd7cddfSDavid du Colombier * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
107dd7cddfSDavid du Colombier * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
117dd7cddfSDavid du Colombier * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
127dd7cddfSDavid du Colombier */
137dd7cddfSDavid du Colombier
147dd7cddfSDavid du Colombier /*
157dd7cddfSDavid du Colombier * gdevifno.c: gs device to generate inferno bitmaps
167dd7cddfSDavid du Colombier * Russ Cox <rsc@plan9.bell-labs.com>, 3/25/98
177dd7cddfSDavid du Colombier * Updated to fit in the standard GS distribution, 5/14/98
187dd7cddfSDavid du Colombier */
197dd7cddfSDavid du Colombier
207dd7cddfSDavid du Colombier #include "gdevprn.h"
217dd7cddfSDavid du Colombier #include "gsparam.h"
227dd7cddfSDavid du Colombier #include "gxlum.h"
237dd7cddfSDavid du Colombier #include <stdlib.h>
247dd7cddfSDavid du Colombier #undef printf
257dd7cddfSDavid du Colombier
267dd7cddfSDavid du Colombier #define nil ((void*)0)
277dd7cddfSDavid du Colombier enum {
287dd7cddfSDavid du Colombier ERROR = -2
297dd7cddfSDavid du Colombier };
307dd7cddfSDavid du Colombier
317dd7cddfSDavid du Colombier typedef struct WImage WImage;
327dd7cddfSDavid du Colombier typedef struct Rectangle Rectangle;
337dd7cddfSDavid du Colombier typedef struct Point Point;
347dd7cddfSDavid du Colombier
357dd7cddfSDavid du Colombier struct Point {
367dd7cddfSDavid du Colombier int x;
377dd7cddfSDavid du Colombier int y;
387dd7cddfSDavid du Colombier };
397dd7cddfSDavid du Colombier
407dd7cddfSDavid du Colombier struct Rectangle {
417dd7cddfSDavid du Colombier Point min;
427dd7cddfSDavid du Colombier Point max;
437dd7cddfSDavid du Colombier };
447dd7cddfSDavid du Colombier private Point ZP = { 0, 0 };
457dd7cddfSDavid du Colombier
467dd7cddfSDavid du Colombier private WImage* initwriteimage(FILE *f, Rectangle r, int ldepth);
477dd7cddfSDavid du Colombier private int writeimageblock(WImage *w, uchar *data, int ndata);
487dd7cddfSDavid du Colombier private int bytesperline(Rectangle, int);
497dd7cddfSDavid du Colombier private int rgb2cmap(int, int, int);
507dd7cddfSDavid du Colombier private long cmap2rgb(int);
517dd7cddfSDavid du Colombier
527dd7cddfSDavid du Colombier #define X_DPI 100
537dd7cddfSDavid du Colombier #define Y_DPI 100
547dd7cddfSDavid du Colombier
557dd7cddfSDavid du Colombier private dev_proc_map_rgb_color(inferno_rgb2cmap);
567dd7cddfSDavid du Colombier private dev_proc_map_color_rgb(inferno_cmap2rgb);
577dd7cddfSDavid du Colombier private dev_proc_open_device(inferno_open);
587dd7cddfSDavid du Colombier private dev_proc_close_device(inferno_close);
597dd7cddfSDavid du Colombier private dev_proc_print_page(inferno_print_page);
607dd7cddfSDavid du Colombier private dev_proc_put_params(inferno_put_params);
617dd7cddfSDavid du Colombier private dev_proc_get_params(inferno_get_params);
627dd7cddfSDavid du Colombier
637dd7cddfSDavid du Colombier typedef struct inferno_device_s {
647dd7cddfSDavid du Colombier gx_device_common;
657dd7cddfSDavid du Colombier gx_prn_device_common;
667dd7cddfSDavid du Colombier int dither;
677dd7cddfSDavid du Colombier
687dd7cddfSDavid du Colombier int ldepth;
697dd7cddfSDavid du Colombier int lastldepth;
707dd7cddfSDavid du Colombier int cmapcall;
717dd7cddfSDavid du Colombier } inferno_device;
727dd7cddfSDavid du Colombier
737dd7cddfSDavid du Colombier enum {
747dd7cddfSDavid du Colombier Nbits = 8,
757dd7cddfSDavid du Colombier Bitmask = (1<<Nbits)-1,
767dd7cddfSDavid du Colombier };
777dd7cddfSDavid du Colombier
787dd7cddfSDavid du Colombier private const gx_device_procs inferno_procs =
797dd7cddfSDavid du Colombier prn_color_params_procs(inferno_open, gdev_prn_output_page, gdev_prn_close,
807dd7cddfSDavid du Colombier inferno_rgb2cmap, inferno_cmap2rgb,
817dd7cddfSDavid du Colombier gdev_prn_get_params, gdev_prn_put_params);
827dd7cddfSDavid du Colombier /*
837dd7cddfSDavid du Colombier inferno_get_params, inferno_put_params);
847dd7cddfSDavid du Colombier */
857dd7cddfSDavid du Colombier
867dd7cddfSDavid du Colombier
877dd7cddfSDavid du Colombier inferno_device far_data gs_inferno_device =
887dd7cddfSDavid du Colombier { prn_device_body(inferno_device, inferno_procs, "inferno",
897dd7cddfSDavid du Colombier DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
907dd7cddfSDavid du Colombier X_DPI, Y_DPI,
917dd7cddfSDavid du Colombier 0,0,0,0, /* margins */
927dd7cddfSDavid du Colombier 3, /* 3 = RGB, 1 = gray, 4 = CMYK */
937dd7cddfSDavid du Colombier Nbits*3, /* # of bits per pixel */
947dd7cddfSDavid du Colombier (1<<Nbits)-1, /* # of distinct gray levels. */
957dd7cddfSDavid du Colombier (1<<Nbits)-1, /* # of distinct color levels. */
967dd7cddfSDavid du Colombier 1<<Nbits, /* dither gray ramp size. used in alpha? */
977dd7cddfSDavid du Colombier 1<<Nbits, /* dither color ramp size. used in alpha? */
987dd7cddfSDavid du Colombier inferno_print_page),
997dd7cddfSDavid du Colombier 1,
1007dd7cddfSDavid du Colombier };
1017dd7cddfSDavid du Colombier
1027dd7cddfSDavid du Colombier /*
1037dd7cddfSDavid du Colombier * ghostscript asks us how to convert between
1047dd7cddfSDavid du Colombier * rgb and color map entries
1057dd7cddfSDavid du Colombier */
1067dd7cddfSDavid du Colombier private gx_color_index
inferno_rgb2cmap(gx_device * dev,gx_color_value rgb[3])107*593dc095SDavid du Colombier inferno_rgb2cmap(gx_device *dev, gx_color_value rgb[3]) {
1087dd7cddfSDavid du Colombier int shift;
1097dd7cddfSDavid du Colombier inferno_device *idev;
1107dd7cddfSDavid du Colombier ulong red, green, blue;
1117dd7cddfSDavid du Colombier
1127dd7cddfSDavid du Colombier idev = (inferno_device*) dev;
1137dd7cddfSDavid du Colombier
1147dd7cddfSDavid du Colombier shift = gx_color_value_bits - Nbits;
115*593dc095SDavid du Colombier red = rgb[0] >> shift;
116*593dc095SDavid du Colombier green = rgb[1] >> shift;
117*593dc095SDavid du Colombier blue = rgb[2] >> shift;
1187dd7cddfSDavid du Colombier
1197dd7cddfSDavid du Colombier /*
1207dd7cddfSDavid du Colombier * we keep track of what ldepth bitmap this is by watching
1217dd7cddfSDavid du Colombier * what colors gs asks for.
1227dd7cddfSDavid du Colombier *
1237dd7cddfSDavid du Colombier * one catch: sometimes print_page gets called more than one
1247dd7cddfSDavid du Colombier * per page (for multiple copies) without cmap calls inbetween.
1257dd7cddfSDavid du Colombier * if idev->cmapcall is 0 when print_page gets called, it uses
1267dd7cddfSDavid du Colombier * the ldepth of the last page.
1277dd7cddfSDavid du Colombier */
1287dd7cddfSDavid du Colombier if(red == green && green == blue) {
1297dd7cddfSDavid du Colombier if(red == 0 || red == Bitmask)
1307dd7cddfSDavid du Colombier ;
1317dd7cddfSDavid du Colombier else if(red == Bitmask/3 || red == 2*Bitmask/3) {
1327dd7cddfSDavid du Colombier if(idev->ldepth < 1)
1337dd7cddfSDavid du Colombier idev->ldepth = 1;
1347dd7cddfSDavid du Colombier } else {
1357dd7cddfSDavid du Colombier if(idev->ldepth < 2)
1367dd7cddfSDavid du Colombier idev->ldepth = 2;
1377dd7cddfSDavid du Colombier }
1387dd7cddfSDavid du Colombier } else
1397dd7cddfSDavid du Colombier idev->ldepth = 3;
1407dd7cddfSDavid du Colombier
1417dd7cddfSDavid du Colombier idev->cmapcall = 1;
1427dd7cddfSDavid du Colombier return (blue << (2*Nbits)) | (green << Nbits) | red;
1437dd7cddfSDavid du Colombier }
1447dd7cddfSDavid du Colombier
1457dd7cddfSDavid du Colombier private int
inferno_cmap2rgb(gx_device * dev,gx_color_index color,gx_color_value rgb[3])146*593dc095SDavid du Colombier inferno_cmap2rgb(gx_device *dev, gx_color_index color,
147*593dc095SDavid du Colombier gx_color_value rgb[3]) {
1487dd7cddfSDavid du Colombier int shift, i;
1497dd7cddfSDavid du Colombier inferno_device *idev;
1507dd7cddfSDavid du Colombier
1517dd7cddfSDavid du Colombier if((ulong)color > 0xFFFFFF)
1527dd7cddfSDavid du Colombier return_error(gs_error_rangecheck);
1537dd7cddfSDavid du Colombier
1547dd7cddfSDavid du Colombier idev = (inferno_device*) dev;
1557dd7cddfSDavid du Colombier shift = gx_color_value_bits - Nbits;
1567dd7cddfSDavid du Colombier
1577dd7cddfSDavid du Colombier rgb[2] = ((color >> (2*Nbits)) & Bitmask) << shift;
1587dd7cddfSDavid du Colombier rgb[1] = ((color >> Nbits) & Bitmask) << shift;
1597dd7cddfSDavid du Colombier rgb[0] = (color & Bitmask) << shift;
1607dd7cddfSDavid du Colombier
1617dd7cddfSDavid du Colombier return 0;
1627dd7cddfSDavid du Colombier }
1637dd7cddfSDavid du Colombier
1647dd7cddfSDavid du Colombier private int
inferno_put_param_int(gs_param_list * plist,gs_param_name pname,int * pv,int minval,int maxval,int ecode)1657dd7cddfSDavid du Colombier inferno_put_param_int(gs_param_list *plist, gs_param_name pname, int *pv,
1667dd7cddfSDavid du Colombier int minval, int maxval, int ecode)
1677dd7cddfSDavid du Colombier {
1687dd7cddfSDavid du Colombier int code, value;
1697dd7cddfSDavid du Colombier switch(code = param_read_int(plist, pname, &value)) {
1707dd7cddfSDavid du Colombier default:
1717dd7cddfSDavid du Colombier return code;
1727dd7cddfSDavid du Colombier
1737dd7cddfSDavid du Colombier case 1:
1747dd7cddfSDavid du Colombier return ecode;
1757dd7cddfSDavid du Colombier
1767dd7cddfSDavid du Colombier case 0:
1777dd7cddfSDavid du Colombier if(value < minval || value > maxval)
1787dd7cddfSDavid du Colombier param_signal_error(plist, pname, gs_error_rangecheck);
1797dd7cddfSDavid du Colombier *pv = value;
1807dd7cddfSDavid du Colombier return (ecode < 0 ? ecode : 1);
1817dd7cddfSDavid du Colombier }
1827dd7cddfSDavid du Colombier }
1837dd7cddfSDavid du Colombier
1847dd7cddfSDavid du Colombier private int
inferno_get_params(gx_device * pdev,gs_param_list * plist)1857dd7cddfSDavid du Colombier inferno_get_params(gx_device *pdev, gs_param_list *plist)
1867dd7cddfSDavid du Colombier {
1877dd7cddfSDavid du Colombier int code;
1887dd7cddfSDavid du Colombier inferno_device *idev;
1897dd7cddfSDavid du Colombier
1907dd7cddfSDavid du Colombier idev = (inferno_device*) pdev;
1917dd7cddfSDavid du Colombier // printf("inferno_get_params dither %d\n", idev->dither);
1927dd7cddfSDavid du Colombier
1937dd7cddfSDavid du Colombier if((code = gdev_prn_get_params(pdev, plist)) < 0
1947dd7cddfSDavid du Colombier || (code = param_write_int(plist, "Dither", &idev->dither)) < 0)
1957dd7cddfSDavid du Colombier return code;
1967dd7cddfSDavid du Colombier printf("getparams: dither=%d\n", idev->dither);
1977dd7cddfSDavid du Colombier return code;
1987dd7cddfSDavid du Colombier }
1997dd7cddfSDavid du Colombier
2007dd7cddfSDavid du Colombier private int
inferno_put_params(gx_device * pdev,gs_param_list * plist)2017dd7cddfSDavid du Colombier inferno_put_params(gx_device * pdev, gs_param_list * plist)
2027dd7cddfSDavid du Colombier {
2037dd7cddfSDavid du Colombier int code;
2047dd7cddfSDavid du Colombier int dither;
2057dd7cddfSDavid du Colombier inferno_device *idev;
2067dd7cddfSDavid du Colombier
2077dd7cddfSDavid du Colombier printf("inferno_put_params\n");
2087dd7cddfSDavid du Colombier
2097dd7cddfSDavid du Colombier idev = (inferno_device*)pdev;
2107dd7cddfSDavid du Colombier dither = idev->dither;
2117dd7cddfSDavid du Colombier
2127dd7cddfSDavid du Colombier code = inferno_put_param_int(plist, "Dither", &dither, 0, 1, 0);
2137dd7cddfSDavid du Colombier if(code < 0)
2147dd7cddfSDavid du Colombier return code;
2157dd7cddfSDavid du Colombier
2167dd7cddfSDavid du Colombier idev->dither = dither;
2177dd7cddfSDavid du Colombier return 0;
2187dd7cddfSDavid du Colombier }
2197dd7cddfSDavid du Colombier
2207dd7cddfSDavid du Colombier /*
2217dd7cddfSDavid du Colombier * dithering tables courtesy of john hobby
2227dd7cddfSDavid du Colombier */
2237dd7cddfSDavid du Colombier /* The following constants and tables define the mapping from fine-grained RGB
2247dd7cddfSDavid du Colombier triplets to 8-bit values based on the standard Plan 9 color map.
2257dd7cddfSDavid du Colombier */
2267dd7cddfSDavid du Colombier #define Rlevs 16 /* number of levels to cut red value into */
2277dd7cddfSDavid du Colombier #define Glevs 16
2287dd7cddfSDavid du Colombier #define Blevs 16
2297dd7cddfSDavid du Colombier #define Mlevs 16
2307dd7cddfSDavid du Colombier #define Rfactor 1 /* multiple of red level in p9color[] index */
2317dd7cddfSDavid du Colombier #define Gfactor Rlevs
2327dd7cddfSDavid du Colombier #define Bfactor (Rlevs*Glevs)
2337dd7cddfSDavid du Colombier
2347dd7cddfSDavid du Colombier ulong p9color[Rlevs*Glevs*Blevs]; /* index blue most sig, red least sig */
2357dd7cddfSDavid du Colombier
init_p9color(void)2367dd7cddfSDavid du Colombier void init_p9color(void) /* init at run time since p9color[] is so big */
2377dd7cddfSDavid du Colombier {
2387dd7cddfSDavid du Colombier int r, g, b, o;
2397dd7cddfSDavid du Colombier ulong* cur = p9color;
2407dd7cddfSDavid du Colombier for (b=0; b<16; b++) {
2417dd7cddfSDavid du Colombier for (g=0; g<16; g++) {
2427dd7cddfSDavid du Colombier int m0 = (b>g) ? b : g;
2437dd7cddfSDavid du Colombier for (r=0; r<16; r++) {
2447dd7cddfSDavid du Colombier int V, M, rM, gM, bM, m;
2457dd7cddfSDavid du Colombier int m1 = (r>m0) ? r : m0;
2467dd7cddfSDavid du Colombier V=m1&3; M=(m1-V)<<1;
2477dd7cddfSDavid du Colombier if (m1==0) m1=1;
2487dd7cddfSDavid du Colombier m = m1 << 3;
2497dd7cddfSDavid du Colombier rM=r*M; gM=g*M; bM=b*M;
2507dd7cddfSDavid du Colombier *cur = 0;
2517dd7cddfSDavid du Colombier for (o=7*m1; o>0; o-=2*m1) {
2527dd7cddfSDavid du Colombier int rr=(rM+o)/m, gg=(gM+o)/m, bb=(bM+o)/m;
2537dd7cddfSDavid du Colombier int ij = (rr<<6) + (V<<4) + ((V-rr+(gg<<2)+bb)&15);
2547dd7cddfSDavid du Colombier *cur = (*cur << 8) + 255-ij;
2557dd7cddfSDavid du Colombier }
2567dd7cddfSDavid du Colombier cur++;
2577dd7cddfSDavid du Colombier }
2587dd7cddfSDavid du Colombier }
2597dd7cddfSDavid du Colombier }
2607dd7cddfSDavid du Colombier }
2617dd7cddfSDavid du Colombier
2627dd7cddfSDavid du Colombier /*
2637dd7cddfSDavid du Colombier * inferno_open() is supposed to initialize the device.
2647dd7cddfSDavid du Colombier * there's not much to do.
2657dd7cddfSDavid du Colombier */
2667dd7cddfSDavid du Colombier private int
inferno_open(gx_device * dev)267*593dc095SDavid du Colombier inferno_open(gx_device *dev)
2687dd7cddfSDavid du Colombier {
2697dd7cddfSDavid du Colombier int code;
2707dd7cddfSDavid du Colombier inferno_device *idev;
2717dd7cddfSDavid du Colombier
2727dd7cddfSDavid du Colombier idev = (inferno_device*) dev;
2737dd7cddfSDavid du Colombier idev->cmapcall = 0;
2747dd7cddfSDavid du Colombier idev->ldepth = 0;
2757dd7cddfSDavid du Colombier
2767dd7cddfSDavid du Colombier // printf("inferno_open gs_inferno_device.dither = %d idev->dither = %d\n",
2777dd7cddfSDavid du Colombier // gs_inferno_device.dither, idev->dither);
2787dd7cddfSDavid du Colombier init_p9color();
2797dd7cddfSDavid du Colombier
2807dd7cddfSDavid du Colombier return gdev_prn_open(dev);
2817dd7cddfSDavid du Colombier }
2827dd7cddfSDavid du Colombier
2837dd7cddfSDavid du Colombier /*
2847dd7cddfSDavid du Colombier * inferno_print_page() is called once for each page
2857dd7cddfSDavid du Colombier * (actually once for each copy of each page, but we won't
2867dd7cddfSDavid du Colombier * worry about that).
2877dd7cddfSDavid du Colombier */
2887dd7cddfSDavid du Colombier private int
inferno_print_page(gx_device_printer * pdev,FILE * f)289*593dc095SDavid du Colombier inferno_print_page(gx_device_printer *pdev, FILE *f)
2907dd7cddfSDavid du Colombier {
2917dd7cddfSDavid du Colombier uchar *buf; /* [8192*3*8/Nbits] BUG: malloc this */
2927dd7cddfSDavid du Colombier uchar *p;
2937dd7cddfSDavid du Colombier WImage *w;
2947dd7cddfSDavid du Colombier int bpl, y;
2957dd7cddfSDavid du Colombier int x, xmod;
2967dd7cddfSDavid du Colombier int ldepth;
2977dd7cddfSDavid du Colombier int ppb[] = {8, 4, 2, 1}; /* pixels per byte */
2987dd7cddfSDavid du Colombier int bpp[] = {1, 2, 4, 8}; /* bits per pixel */
2997dd7cddfSDavid du Colombier int gsbpl;
3007dd7cddfSDavid du Colombier int dither;
3017dd7cddfSDavid du Colombier ulong u;
3027dd7cddfSDavid du Colombier ushort us;
3037dd7cddfSDavid du Colombier Rectangle rect;
3047dd7cddfSDavid du Colombier inferno_device *idev;
3057dd7cddfSDavid du Colombier ulong r, g, b;
3067dd7cddfSDavid du Colombier
3077dd7cddfSDavid du Colombier gsbpl = gdev_prn_raster(pdev);
308*593dc095SDavid du Colombier buf = gs_malloc(pdev->memory, gsbpl, 1, "inferno_print_page");
3097dd7cddfSDavid du Colombier
3107dd7cddfSDavid du Colombier if(buf == nil) {
311*593dc095SDavid du Colombier errprintf("out of memory\n");
3127dd7cddfSDavid du Colombier return_error(gs_error_Fatal);
3137dd7cddfSDavid du Colombier }
3147dd7cddfSDavid du Colombier
3157dd7cddfSDavid du Colombier idev = (inferno_device *) pdev;
3167dd7cddfSDavid du Colombier if(idev->cmapcall) {
3177dd7cddfSDavid du Colombier idev->lastldepth = idev->ldepth;
3187dd7cddfSDavid du Colombier idev->ldepth = 0;
3197dd7cddfSDavid du Colombier idev->cmapcall = 0;
3207dd7cddfSDavid du Colombier }
3217dd7cddfSDavid du Colombier ldepth = idev->lastldepth;
3227dd7cddfSDavid du Colombier dither = idev->dither;
3237dd7cddfSDavid du Colombier
3247dd7cddfSDavid du Colombier if(pdev->color_info.anti_alias.graphics_bits || pdev->color_info.anti_alias.text_bits)
3257dd7cddfSDavid du Colombier if(ldepth < 2)
3267dd7cddfSDavid du Colombier ldepth = 2;
3277dd7cddfSDavid du Colombier
3287dd7cddfSDavid du Colombier // printf("inferno_print_page dither %d ldepth %d idither %d\n", dither, ldepth, gs_inferno_device.dither);
3297dd7cddfSDavid du Colombier rect.min = ZP;
3307dd7cddfSDavid du Colombier rect.max.x = pdev->width;
3317dd7cddfSDavid du Colombier rect.max.y = pdev->height;
3327dd7cddfSDavid du Colombier bpl = bytesperline(rect, ldepth);
3337dd7cddfSDavid du Colombier w = initwriteimage(f, rect, ldepth);
3347dd7cddfSDavid du Colombier if(w == nil) {
335*593dc095SDavid du Colombier errprintf("initwriteimage failed\n");
3367dd7cddfSDavid du Colombier return_error(gs_error_Fatal);
3377dd7cddfSDavid du Colombier }
3387dd7cddfSDavid du Colombier
3397dd7cddfSDavid du Colombier /*
3407dd7cddfSDavid du Colombier * i wonder if it is faster to put the switch around the for loops
3417dd7cddfSDavid du Colombier * to save all the ldepth lookups.
3427dd7cddfSDavid du Colombier */
3437dd7cddfSDavid du Colombier for(y=0; y<pdev->height; y++) {
3447dd7cddfSDavid du Colombier gdev_prn_get_bits(pdev, y, buf, &p);
3457dd7cddfSDavid du Colombier for(x=0; x<pdev->width; x++) {
3467dd7cddfSDavid du Colombier b = p[3*x];
3477dd7cddfSDavid du Colombier g = p[3*x+1];
3487dd7cddfSDavid du Colombier r = p[3*x+2];
3497dd7cddfSDavid du Colombier us = ((b>>4) << 8) | ((g>>4) << 4) | (r>>4);
3507dd7cddfSDavid du Colombier switch(ldepth) {
3517dd7cddfSDavid du Colombier case 3:
3527dd7cddfSDavid du Colombier if(1 || dither){
3537dd7cddfSDavid du Colombier u = p9color[us];
3547dd7cddfSDavid du Colombier /* the ulong in p9color is a 2x2 matrix. pull the entry
3557dd7cddfSDavid du Colombier * u[x%2][y%2], more or less.
3567dd7cddfSDavid du Colombier */
3577dd7cddfSDavid du Colombier p[x] = u >> (8*((y%2)+2*(x%2)));
3587dd7cddfSDavid du Colombier } else {
3597dd7cddfSDavid du Colombier p[x] = rgb2cmap(r, g, b);
3607dd7cddfSDavid du Colombier }
3617dd7cddfSDavid du Colombier break;
3627dd7cddfSDavid du Colombier case 2:
3637dd7cddfSDavid du Colombier us = ~us;
3647dd7cddfSDavid du Colombier if((x%2) == 0)
3657dd7cddfSDavid du Colombier p[x/2] = us & 0xf;
3667dd7cddfSDavid du Colombier else
3677dd7cddfSDavid du Colombier p[x/2] = (p[x/2]<<4)|(us&0xf);
3687dd7cddfSDavid du Colombier break;
3697dd7cddfSDavid du Colombier case 1:
3707dd7cddfSDavid du Colombier return_error(gs_error_Fatal);
3717dd7cddfSDavid du Colombier case 0:
3727dd7cddfSDavid du Colombier us = ~us;
3737dd7cddfSDavid du Colombier if((x%8) == 0)
3747dd7cddfSDavid du Colombier p[x/8] = us & 0x1;
3757dd7cddfSDavid du Colombier else
3767dd7cddfSDavid du Colombier p[x/8] = (p[x/8]<<1)|(us&0x1);
3777dd7cddfSDavid du Colombier break;
3787dd7cddfSDavid du Colombier }
3797dd7cddfSDavid du Colombier }
3807dd7cddfSDavid du Colombier
3817dd7cddfSDavid du Colombier /* pad last byte over if we didn't fill it */
3827dd7cddfSDavid du Colombier xmod = pdev->width % ppb[ldepth];
3837dd7cddfSDavid du Colombier if(xmod)
3847dd7cddfSDavid du Colombier p[(x-1)/ppb[ldepth]] <<= ((ppb[ldepth]-xmod)*bpp[ldepth]);
3857dd7cddfSDavid du Colombier if(writeimageblock(w, p, bpl) == ERROR) {
386*593dc095SDavid du Colombier gs_free(pdev->memory, buf, gsbpl, 1, "inferno_print_page");
3877dd7cddfSDavid du Colombier return_error(gs_error_Fatal);
3887dd7cddfSDavid du Colombier }
3897dd7cddfSDavid du Colombier }
3907dd7cddfSDavid du Colombier if(writeimageblock(w, nil, 0) == ERROR) {
391*593dc095SDavid du Colombier gs_free(pdev->memory, buf, gsbpl, 1, "inferno_print_page");
3927dd7cddfSDavid du Colombier return_error(gs_error_Fatal);
3937dd7cddfSDavid du Colombier }
3947dd7cddfSDavid du Colombier
395*593dc095SDavid du Colombier gs_free(pdev->memory, buf, gsbpl, 1, "inferno_print_page");
3967dd7cddfSDavid du Colombier return 0;
3977dd7cddfSDavid du Colombier }
3987dd7cddfSDavid du Colombier
3997dd7cddfSDavid du Colombier /*
4007dd7cddfSDavid du Colombier * this is a modified version of the image compressor
4017dd7cddfSDavid du Colombier * from fb/bit2enc. it is modified only in that it
4027dd7cddfSDavid du Colombier * now compiles as part of gs.
4037dd7cddfSDavid du Colombier */
4047dd7cddfSDavid du Colombier
4057dd7cddfSDavid du Colombier /*
4067dd7cddfSDavid du Colombier * Compressed image file parameters
4077dd7cddfSDavid du Colombier */
4087dd7cddfSDavid du Colombier #define NMATCH 3 /* shortest match possible */
4097dd7cddfSDavid du Colombier #define NRUN (NMATCH+31) /* longest match possible */
4107dd7cddfSDavid du Colombier #define NMEM 1024 /* window size */
4117dd7cddfSDavid du Colombier #define NDUMP 128 /* maximum length of dump */
4127dd7cddfSDavid du Colombier #define NCBLOCK 6000 /* size of compressed blocks */
4137dd7cddfSDavid du Colombier
4147dd7cddfSDavid du Colombier #define HSHIFT 3 /* HSHIFT==5 runs slightly faster, but hash table is 64x bigger */
4157dd7cddfSDavid du Colombier #define NHASH (1<<(HSHIFT*NMATCH))
4167dd7cddfSDavid du Colombier #define HMASK (NHASH-1)
4177dd7cddfSDavid du Colombier #define hupdate(h, c) ((((h)<<HSHIFT)^(c))&HMASK)
4187dd7cddfSDavid du Colombier
4197dd7cddfSDavid du Colombier typedef struct Dump Dump;
4207dd7cddfSDavid du Colombier typedef struct Hlist Hlist;
4217dd7cddfSDavid du Colombier
4227dd7cddfSDavid du Colombier struct Hlist{
4237dd7cddfSDavid du Colombier ulong p;
4247dd7cddfSDavid du Colombier Hlist *next, *prev;
4257dd7cddfSDavid du Colombier };
4267dd7cddfSDavid du Colombier
4277dd7cddfSDavid du Colombier struct Dump {
4287dd7cddfSDavid du Colombier int ndump;
4297dd7cddfSDavid du Colombier uchar *dumpbuf;
4307dd7cddfSDavid du Colombier uchar buf[1+NDUMP];
4317dd7cddfSDavid du Colombier };
4327dd7cddfSDavid du Colombier
4337dd7cddfSDavid du Colombier struct WImage {
4347dd7cddfSDavid du Colombier FILE *f;
4357dd7cddfSDavid du Colombier
4367dd7cddfSDavid du Colombier /* image attributes */
4377dd7cddfSDavid du Colombier Rectangle origr, r;
4387dd7cddfSDavid du Colombier int bpl;
4397dd7cddfSDavid du Colombier
4407dd7cddfSDavid du Colombier /* output buffer */
4417dd7cddfSDavid du Colombier uchar outbuf[NCBLOCK], *outp, *eout, *loutp;
4427dd7cddfSDavid du Colombier
4437dd7cddfSDavid du Colombier /* sliding input window */
4447dd7cddfSDavid du Colombier /*
4457dd7cddfSDavid du Colombier * ibase is the pointer to where the beginning of
4467dd7cddfSDavid du Colombier * the input "is" in memory. whenever we "slide" the
4477dd7cddfSDavid du Colombier * buffer N bytes, what we are actually doing is
4487dd7cddfSDavid du Colombier * decrementing ibase by N.
4497dd7cddfSDavid du Colombier * the ulongs in the Hlist structures are just
4507dd7cddfSDavid du Colombier * pointers relative to ibase.
4517dd7cddfSDavid du Colombier */
4527dd7cddfSDavid du Colombier uchar *inbuf; /* inbuf should be at least NMEM+NRUN+NMATCH long */
4537dd7cddfSDavid du Colombier uchar *ibase;
4547dd7cddfSDavid du Colombier int minbuf; /* size of inbuf (malloc'ed bytes) */
4557dd7cddfSDavid du Colombier int ninbuf; /* size of inbuf (filled bytes) */
4567dd7cddfSDavid du Colombier ulong line; /* the beginning of the line we are currently encoding,
4577dd7cddfSDavid du Colombier * relative to inbuf (NOT relative to ibase) */
4587dd7cddfSDavid du Colombier
4597dd7cddfSDavid du Colombier /* raw dump buffer */
4607dd7cddfSDavid du Colombier Dump dump;
4617dd7cddfSDavid du Colombier
4627dd7cddfSDavid du Colombier /* hash tables */
4637dd7cddfSDavid du Colombier Hlist hash[NHASH];
4647dd7cddfSDavid du Colombier Hlist chain[NMEM], *cp;
4657dd7cddfSDavid du Colombier int h;
4667dd7cddfSDavid du Colombier int needhash;
4677dd7cddfSDavid du Colombier };
4687dd7cddfSDavid du Colombier
4697dd7cddfSDavid du Colombier private void
zerohash(WImage * w)4707dd7cddfSDavid du Colombier zerohash(WImage *w)
4717dd7cddfSDavid du Colombier {
4727dd7cddfSDavid du Colombier memset(w->hash, 0, sizeof(w->hash));
4737dd7cddfSDavid du Colombier memset(w->chain, 0, sizeof(w->chain));
4747dd7cddfSDavid du Colombier w->cp=w->chain;
4757dd7cddfSDavid du Colombier w->needhash = 1;
4767dd7cddfSDavid du Colombier }
4777dd7cddfSDavid du Colombier
4787dd7cddfSDavid du Colombier private int
addbuf(WImage * w,uchar * buf,int nbuf)4797dd7cddfSDavid du Colombier addbuf(WImage *w, uchar *buf, int nbuf)
4807dd7cddfSDavid du Colombier {
4817dd7cddfSDavid du Colombier int n;
4827dd7cddfSDavid du Colombier if(buf == nil || w->outp+nbuf > w->eout) {
4837dd7cddfSDavid du Colombier if(w->loutp==w->outbuf){ /* can't really happen -- we checked line length above */
484*593dc095SDavid du Colombier errprintf("buffer too small for line\n");
4857dd7cddfSDavid du Colombier return ERROR;
4867dd7cddfSDavid du Colombier }
4877dd7cddfSDavid du Colombier n=w->loutp-w->outbuf;
4887dd7cddfSDavid du Colombier fprintf(w->f, "%11d %11d ", w->r.max.y, n);
4897dd7cddfSDavid du Colombier fwrite(w->outbuf, 1, n, w->f);
4907dd7cddfSDavid du Colombier w->r.min.y=w->r.max.y;
4917dd7cddfSDavid du Colombier w->outp=w->outbuf;
4927dd7cddfSDavid du Colombier w->loutp=w->outbuf;
4937dd7cddfSDavid du Colombier zerohash(w);
4947dd7cddfSDavid du Colombier return -1;
4957dd7cddfSDavid du Colombier }
4967dd7cddfSDavid du Colombier
4977dd7cddfSDavid du Colombier memmove(w->outp, buf, nbuf);
4987dd7cddfSDavid du Colombier w->outp += nbuf;
4997dd7cddfSDavid du Colombier return nbuf;
5007dd7cddfSDavid du Colombier }
5017dd7cddfSDavid du Colombier
5027dd7cddfSDavid du Colombier /* return 0 on success, -1 if buffer is full */
5037dd7cddfSDavid du Colombier private int
flushdump(WImage * w)5047dd7cddfSDavid du Colombier flushdump(WImage *w)
5057dd7cddfSDavid du Colombier {
5067dd7cddfSDavid du Colombier int n = w->dump.ndump;
5077dd7cddfSDavid du Colombier
5087dd7cddfSDavid du Colombier if(n == 0)
5097dd7cddfSDavid du Colombier return 0;
5107dd7cddfSDavid du Colombier
5117dd7cddfSDavid du Colombier w->dump.buf[0] = 0x80|(n-1);
5127dd7cddfSDavid du Colombier if((n=addbuf(w, w->dump.buf, n+1)) == ERROR)
5137dd7cddfSDavid du Colombier return ERROR;
5147dd7cddfSDavid du Colombier if(n < 0)
5157dd7cddfSDavid du Colombier return -1;
5167dd7cddfSDavid du Colombier w->dump.ndump = 0;
5177dd7cddfSDavid du Colombier return 0;
5187dd7cddfSDavid du Colombier }
5197dd7cddfSDavid du Colombier
5207dd7cddfSDavid du Colombier private void
updatehash(WImage * w,uchar * p,uchar * ep)5217dd7cddfSDavid du Colombier updatehash(WImage *w, uchar *p, uchar *ep)
5227dd7cddfSDavid du Colombier {
5237dd7cddfSDavid du Colombier uchar *q;
5247dd7cddfSDavid du Colombier Hlist *cp;
5257dd7cddfSDavid du Colombier Hlist *hash;
5267dd7cddfSDavid du Colombier int h;
5277dd7cddfSDavid du Colombier
5287dd7cddfSDavid du Colombier hash = w->hash;
5297dd7cddfSDavid du Colombier cp = w->cp;
5307dd7cddfSDavid du Colombier h = w->h;
5317dd7cddfSDavid du Colombier for(q=p; q<ep; q++) {
5327dd7cddfSDavid du Colombier if(cp->prev)
5337dd7cddfSDavid du Colombier cp->prev->next = cp->next;
5347dd7cddfSDavid du Colombier cp->next = hash[h].next;
5357dd7cddfSDavid du Colombier cp->prev = &hash[h];
5367dd7cddfSDavid du Colombier cp->prev->next = cp;
5377dd7cddfSDavid du Colombier if(cp->next)
5387dd7cddfSDavid du Colombier cp->next->prev = cp;
5397dd7cddfSDavid du Colombier cp->p = q - w->ibase;
5407dd7cddfSDavid du Colombier if(++cp == w->chain+NMEM)
5417dd7cddfSDavid du Colombier cp = w->chain;
5427dd7cddfSDavid du Colombier if(&q[NMATCH] < &w->inbuf[w->ninbuf])
5437dd7cddfSDavid du Colombier h = hupdate(h, q[NMATCH]);
5447dd7cddfSDavid du Colombier }
5457dd7cddfSDavid du Colombier w->cp = cp;
5467dd7cddfSDavid du Colombier w->h = h;
5477dd7cddfSDavid du Colombier }
5487dd7cddfSDavid du Colombier
5497dd7cddfSDavid du Colombier /*
5507dd7cddfSDavid du Colombier * attempt to process a line of input,
5517dd7cddfSDavid du Colombier * returning the number of bytes actually processed.
5527dd7cddfSDavid du Colombier *
5537dd7cddfSDavid du Colombier * if the output buffer needs to be flushed, we flush
5547dd7cddfSDavid du Colombier * the buffer and return 0.
5557dd7cddfSDavid du Colombier * otherwise we return bpl
5567dd7cddfSDavid du Colombier */
5577dd7cddfSDavid du Colombier private int
gobbleline(WImage * w)5587dd7cddfSDavid du Colombier gobbleline(WImage *w)
5597dd7cddfSDavid du Colombier {
5607dd7cddfSDavid du Colombier int runlen, n, offs;
5617dd7cddfSDavid du Colombier uchar *eline, *es, *best, *p, *s, *t;
5627dd7cddfSDavid du Colombier Hlist *hp;
5637dd7cddfSDavid du Colombier uchar buf[2];
5647dd7cddfSDavid du Colombier int rv;
5657dd7cddfSDavid du Colombier
5667dd7cddfSDavid du Colombier if(w->needhash) {
5677dd7cddfSDavid du Colombier w->h = 0;
5687dd7cddfSDavid du Colombier for(n=0; n!=NMATCH; n++)
5697dd7cddfSDavid du Colombier w->h = hupdate(w->h, w->inbuf[w->line+n]);
5707dd7cddfSDavid du Colombier w->needhash = 0;
5717dd7cddfSDavid du Colombier }
5727dd7cddfSDavid du Colombier w->dump.ndump=0;
5737dd7cddfSDavid du Colombier eline=w->inbuf+w->line+w->bpl;
5747dd7cddfSDavid du Colombier for(p=w->inbuf+w->line;p!=eline;){
5757dd7cddfSDavid du Colombier es = (eline < p+NRUN) ? eline : p+NRUN;
5767dd7cddfSDavid du Colombier
5777dd7cddfSDavid du Colombier best=nil;
5787dd7cddfSDavid du Colombier runlen=0;
5797dd7cddfSDavid du Colombier /* hash table lookup */
5807dd7cddfSDavid du Colombier for(hp=w->hash[w->h].next;hp;hp=hp->next){
5817dd7cddfSDavid du Colombier /*
5827dd7cddfSDavid du Colombier * the next block is an optimization of
5837dd7cddfSDavid du Colombier * for(s=p, t=w->ibase+hp->p; s<es && *s == *t; s++, t++)
5847dd7cddfSDavid du Colombier * ;
5857dd7cddfSDavid du Colombier */
5867dd7cddfSDavid du Colombier
5877dd7cddfSDavid du Colombier { uchar *ss, *tt;
5887dd7cddfSDavid du Colombier s = p+runlen;
5897dd7cddfSDavid du Colombier t = w->ibase+hp->p+runlen;
5907dd7cddfSDavid du Colombier for(ss=s, tt=t; ss>=p && *ss == *tt; ss--, tt--)
5917dd7cddfSDavid du Colombier ;
5927dd7cddfSDavid du Colombier if(ss < p)
5937dd7cddfSDavid du Colombier while(s<es && *s == *t)
5947dd7cddfSDavid du Colombier s++, t++;
5957dd7cddfSDavid du Colombier }
5967dd7cddfSDavid du Colombier
5977dd7cddfSDavid du Colombier n = s-p;
5987dd7cddfSDavid du Colombier
5997dd7cddfSDavid du Colombier if(n > runlen) {
6007dd7cddfSDavid du Colombier runlen = n;
6017dd7cddfSDavid du Colombier best = w->ibase+hp->p;
6027dd7cddfSDavid du Colombier if(p+runlen == es)
6037dd7cddfSDavid du Colombier break;
6047dd7cddfSDavid du Colombier }
6057dd7cddfSDavid du Colombier }
6067dd7cddfSDavid du Colombier
6077dd7cddfSDavid du Colombier /*
6087dd7cddfSDavid du Colombier * if we didn't find a long enough run, append to
6097dd7cddfSDavid du Colombier * the raw dump buffer
6107dd7cddfSDavid du Colombier */
6117dd7cddfSDavid du Colombier if(runlen<NMATCH){
6127dd7cddfSDavid du Colombier if(w->dump.ndump==NDUMP) {
6137dd7cddfSDavid du Colombier if((rv = flushdump(w)) == ERROR)
6147dd7cddfSDavid du Colombier return ERROR;
6157dd7cddfSDavid du Colombier if(rv < 0)
6167dd7cddfSDavid du Colombier return 0;
6177dd7cddfSDavid du Colombier }
6187dd7cddfSDavid du Colombier w->dump.dumpbuf[w->dump.ndump++]=*p;
6197dd7cddfSDavid du Colombier runlen=1;
6207dd7cddfSDavid du Colombier }else{
6217dd7cddfSDavid du Colombier /*
6227dd7cddfSDavid du Colombier * otherwise, assuming the dump buffer is empty,
6237dd7cddfSDavid du Colombier * add the compressed rep.
6247dd7cddfSDavid du Colombier */
6257dd7cddfSDavid du Colombier if((rv = flushdump(w)) == ERROR)
6267dd7cddfSDavid du Colombier return ERROR;
6277dd7cddfSDavid du Colombier if(rv < 0)
6287dd7cddfSDavid du Colombier return 0;
6297dd7cddfSDavid du Colombier offs=p-best-1;
6307dd7cddfSDavid du Colombier buf[0] = ((runlen-NMATCH)<<2)|(offs>>8);
6317dd7cddfSDavid du Colombier buf[1] = offs&0xff;
6327dd7cddfSDavid du Colombier if(addbuf(w, buf, 2) < 0)
6337dd7cddfSDavid du Colombier return 0;
6347dd7cddfSDavid du Colombier }
6357dd7cddfSDavid du Colombier
6367dd7cddfSDavid du Colombier /*
6377dd7cddfSDavid du Colombier * add to hash tables what we just encoded
6387dd7cddfSDavid du Colombier */
6397dd7cddfSDavid du Colombier updatehash(w, p, p+runlen);
6407dd7cddfSDavid du Colombier p += runlen;
6417dd7cddfSDavid du Colombier }
6427dd7cddfSDavid du Colombier
6437dd7cddfSDavid du Colombier if((rv = flushdump(w)) == ERROR)
6447dd7cddfSDavid du Colombier return ERROR;
6457dd7cddfSDavid du Colombier if(rv < 0)
6467dd7cddfSDavid du Colombier return 0;
6477dd7cddfSDavid du Colombier w->line += w->bpl;
6487dd7cddfSDavid du Colombier w->loutp=w->outp;
6497dd7cddfSDavid du Colombier w->r.max.y++;
6507dd7cddfSDavid du Colombier return w->bpl;
6517dd7cddfSDavid du Colombier }
6527dd7cddfSDavid du Colombier
6537dd7cddfSDavid du Colombier private uchar*
shiftwindow(WImage * w,uchar * data,uchar * edata)6547dd7cddfSDavid du Colombier shiftwindow(WImage *w, uchar *data, uchar *edata)
6557dd7cddfSDavid du Colombier {
6567dd7cddfSDavid du Colombier int n, m;
6577dd7cddfSDavid du Colombier
6587dd7cddfSDavid du Colombier /* shift window over */
6597dd7cddfSDavid du Colombier if(w->line > NMEM) {
6607dd7cddfSDavid du Colombier n = w->line-NMEM;
6617dd7cddfSDavid du Colombier memmove(w->inbuf, w->inbuf+n, w->ninbuf-n);
6627dd7cddfSDavid du Colombier w->line -= n;
6637dd7cddfSDavid du Colombier w->ibase -= n;
6647dd7cddfSDavid du Colombier w->ninbuf -= n;
6657dd7cddfSDavid du Colombier }
6667dd7cddfSDavid du Colombier
6677dd7cddfSDavid du Colombier /* fill right with data if available */
6687dd7cddfSDavid du Colombier if(w->minbuf > w->ninbuf && edata > data) {
6697dd7cddfSDavid du Colombier m = w->minbuf - w->ninbuf;
6707dd7cddfSDavid du Colombier if(edata-data < m)
6717dd7cddfSDavid du Colombier m = edata-data;
6727dd7cddfSDavid du Colombier memmove(w->inbuf+w->ninbuf, data, m);
6737dd7cddfSDavid du Colombier data += m;
6747dd7cddfSDavid du Colombier w->ninbuf += m;
6757dd7cddfSDavid du Colombier }
6767dd7cddfSDavid du Colombier
6777dd7cddfSDavid du Colombier return data;
6787dd7cddfSDavid du Colombier }
6797dd7cddfSDavid du Colombier
6807dd7cddfSDavid du Colombier private WImage*
initwriteimage(FILE * f,Rectangle r,int ldepth)6817dd7cddfSDavid du Colombier initwriteimage(FILE *f, Rectangle r, int ldepth)
6827dd7cddfSDavid du Colombier {
6837dd7cddfSDavid du Colombier WImage *w;
6847dd7cddfSDavid du Colombier int n, bpl;
6857dd7cddfSDavid du Colombier
6867dd7cddfSDavid du Colombier bpl = bytesperline(r, ldepth);
6877dd7cddfSDavid du Colombier if(r.max.y <= r.min.y || r.max.x <= r.min.x || bpl <= 0) {
688*593dc095SDavid du Colombier errprintf("bad rectangle, ldepth");
6897dd7cddfSDavid du Colombier return nil;
6907dd7cddfSDavid du Colombier }
6917dd7cddfSDavid du Colombier
6927dd7cddfSDavid du Colombier n = NMEM+NMATCH+NRUN+bpl*2;
6937dd7cddfSDavid du Colombier w = malloc(n+sizeof(*w));
6947dd7cddfSDavid du Colombier if(w == nil)
6957dd7cddfSDavid du Colombier return nil;
6967dd7cddfSDavid du Colombier w->inbuf = (uchar*) &w[1];
6977dd7cddfSDavid du Colombier w->ibase = w->inbuf;
6987dd7cddfSDavid du Colombier w->line = 0;
6997dd7cddfSDavid du Colombier w->minbuf = n;
7007dd7cddfSDavid du Colombier w->ninbuf = 0;
7017dd7cddfSDavid du Colombier w->origr = r;
7027dd7cddfSDavid du Colombier w->r = r;
7037dd7cddfSDavid du Colombier w->r.max.y = w->r.min.y;
7047dd7cddfSDavid du Colombier w->eout = w->outbuf+sizeof(w->outbuf);
7057dd7cddfSDavid du Colombier w->outp = w->loutp = w->outbuf;
7067dd7cddfSDavid du Colombier w->bpl = bpl;
7077dd7cddfSDavid du Colombier w->f = f;
7087dd7cddfSDavid du Colombier w->dump.dumpbuf = w->dump.buf+1;
7097dd7cddfSDavid du Colombier w->dump.ndump = 0;
7107dd7cddfSDavid du Colombier zerohash(w);
7117dd7cddfSDavid du Colombier
7127dd7cddfSDavid du Colombier fprintf(f, "compressed\n%11d %11d %11d %11d %11d ",
7137dd7cddfSDavid du Colombier ldepth, r.min.x, r.min.y, r.max.x, r.max.y);
7147dd7cddfSDavid du Colombier return w;
7157dd7cddfSDavid du Colombier }
7167dd7cddfSDavid du Colombier
7177dd7cddfSDavid du Colombier private int
writeimageblock(WImage * w,uchar * data,int ndata)7187dd7cddfSDavid du Colombier writeimageblock(WImage *w, uchar *data, int ndata)
7197dd7cddfSDavid du Colombier {
7207dd7cddfSDavid du Colombier uchar *edata;
7217dd7cddfSDavid du Colombier
7227dd7cddfSDavid du Colombier if(data == nil) { /* end of data, flush everything */
7237dd7cddfSDavid du Colombier while(w->line < w->ninbuf)
7247dd7cddfSDavid du Colombier if(gobbleline(w) == ERROR)
7257dd7cddfSDavid du Colombier return ERROR;
7267dd7cddfSDavid du Colombier addbuf(w, nil, 0);
7277dd7cddfSDavid du Colombier if(w->r.min.y != w->origr.max.y) {
728*593dc095SDavid du Colombier errprintf("not enough data supplied to writeimage\n");
7297dd7cddfSDavid du Colombier }
7307dd7cddfSDavid du Colombier free(w);
7317dd7cddfSDavid du Colombier return 0;
7327dd7cddfSDavid du Colombier }
7337dd7cddfSDavid du Colombier
7347dd7cddfSDavid du Colombier edata = data+ndata;
7357dd7cddfSDavid du Colombier data = shiftwindow(w, data, edata);
7367dd7cddfSDavid du Colombier while(w->ninbuf >= w->line+w->bpl+NMATCH) {
7377dd7cddfSDavid du Colombier if(gobbleline(w) == ERROR)
7387dd7cddfSDavid du Colombier return ERROR;
7397dd7cddfSDavid du Colombier data = shiftwindow(w, data, edata);
7407dd7cddfSDavid du Colombier }
7417dd7cddfSDavid du Colombier if(data != edata) {
7427dd7cddfSDavid du Colombier fprintf(w->f, "data != edata. uh oh\n");
7437dd7cddfSDavid du Colombier return ERROR; /* can't happen */
7447dd7cddfSDavid du Colombier }
7457dd7cddfSDavid du Colombier return 0;
7467dd7cddfSDavid du Colombier }
7477dd7cddfSDavid du Colombier
7487dd7cddfSDavid du Colombier /*
7497dd7cddfSDavid du Colombier * functions from the Plan9/Brazil drawing libraries
7507dd7cddfSDavid du Colombier */
7517dd7cddfSDavid du Colombier private int
bytesperline(Rectangle r,int ld)7527dd7cddfSDavid du Colombier bytesperline(Rectangle r, int ld)
7537dd7cddfSDavid du Colombier {
7547dd7cddfSDavid du Colombier ulong ws, l, t;
7557dd7cddfSDavid du Colombier int bits = 8;
7567dd7cddfSDavid du Colombier
7577dd7cddfSDavid du Colombier ws = bits>>ld; /* pixels per unit */
7587dd7cddfSDavid du Colombier if(r.min.x >= 0){
7597dd7cddfSDavid du Colombier l = (r.max.x+ws-1)/ws;
7607dd7cddfSDavid du Colombier l -= r.min.x/ws;
7617dd7cddfSDavid du Colombier }else{ /* make positive before divide */
7627dd7cddfSDavid du Colombier t = (-r.min.x)+ws-1;
7637dd7cddfSDavid du Colombier t = (t/ws)*ws;
7647dd7cddfSDavid du Colombier l = (t+r.max.x+ws-1)/ws;
7657dd7cddfSDavid du Colombier }
7667dd7cddfSDavid du Colombier return l;
7677dd7cddfSDavid du Colombier }
7687dd7cddfSDavid du Colombier
7697dd7cddfSDavid du Colombier private int
rgb2cmap(int cr,int cg,int cb)7707dd7cddfSDavid du Colombier rgb2cmap(int cr, int cg, int cb)
7717dd7cddfSDavid du Colombier {
7727dd7cddfSDavid du Colombier int r, g, b, v, cv;
7737dd7cddfSDavid du Colombier
7747dd7cddfSDavid du Colombier if(cr < 0)
7757dd7cddfSDavid du Colombier cr = 0;
7767dd7cddfSDavid du Colombier else if(cr > 255)
7777dd7cddfSDavid du Colombier cr = 255;
7787dd7cddfSDavid du Colombier if(cg < 0)
7797dd7cddfSDavid du Colombier cg = 0;
7807dd7cddfSDavid du Colombier else if(cg > 255)
7817dd7cddfSDavid du Colombier cg = 255;
7827dd7cddfSDavid du Colombier if(cb < 0)
7837dd7cddfSDavid du Colombier cb = 0;
7847dd7cddfSDavid du Colombier else if(cb > 255)
7857dd7cddfSDavid du Colombier cb = 255;
7867dd7cddfSDavid du Colombier r = cr>>6;
7877dd7cddfSDavid du Colombier g = cg>>6;
7887dd7cddfSDavid du Colombier b = cb>>6;
7897dd7cddfSDavid du Colombier cv = cr;
7907dd7cddfSDavid du Colombier if(cg > cv)
7917dd7cddfSDavid du Colombier cv = cg;
7927dd7cddfSDavid du Colombier if(cb > cv)
7937dd7cddfSDavid du Colombier cv = cb;
7947dd7cddfSDavid du Colombier v = (cv>>4)&3;
7957dd7cddfSDavid du Colombier return 255-((((r<<2)+v)<<4)+(((g<<2)+b+v-r)&15));
7967dd7cddfSDavid du Colombier }
7977dd7cddfSDavid du Colombier
7987dd7cddfSDavid du Colombier /*
7997dd7cddfSDavid du Colombier * go the other way; not currently used.
8007dd7cddfSDavid du Colombier *
8017dd7cddfSDavid du Colombier private long
8027dd7cddfSDavid du Colombier cmap2rgb(int c)
8037dd7cddfSDavid du Colombier {
8047dd7cddfSDavid du Colombier int j, num, den, r, g, b, v, rgb;
8057dd7cddfSDavid du Colombier
8067dd7cddfSDavid du Colombier c = 255-c;
8077dd7cddfSDavid du Colombier r = c>>6;
8087dd7cddfSDavid du Colombier v = (c>>4)&3;
8097dd7cddfSDavid du Colombier j = (c-v+r)&15;
8107dd7cddfSDavid du Colombier g = j>>2;
8117dd7cddfSDavid du Colombier b = j&3;
8127dd7cddfSDavid du Colombier den=r;
8137dd7cddfSDavid du Colombier if(g>den)
8147dd7cddfSDavid du Colombier den=g;
8157dd7cddfSDavid du Colombier if(b>den)
8167dd7cddfSDavid du Colombier den=b;
8177dd7cddfSDavid du Colombier if(den==0) {
8187dd7cddfSDavid du Colombier v *= 17;
8197dd7cddfSDavid du Colombier rgb = (v<<16)|(v<<8)|v;
8207dd7cddfSDavid du Colombier }
8217dd7cddfSDavid du Colombier else{
8227dd7cddfSDavid du Colombier num=17*(4*den+v);
8237dd7cddfSDavid du Colombier rgb = ((r*num/den)<<16)|((g*num/den)<<8)|(b*num/den);
8247dd7cddfSDavid du Colombier }
8257dd7cddfSDavid du Colombier return rgb;
8267dd7cddfSDavid du Colombier }
8277dd7cddfSDavid du Colombier *
8287dd7cddfSDavid du Colombier *
8297dd7cddfSDavid du Colombier */
8307dd7cddfSDavid du Colombier
831