xref: /plan9-contrib/sys/src/cmd/gs/src/gdevtfnx.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
13ff48bf5SDavid du Colombier /* Copyright (C) 1995, 2000 Aladdin Enterprises.  All rights reserved.
27dd7cddfSDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
57dd7cddfSDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: gdevtfnx.c,v 1.7 2002/02/21 22:24:52 giles Exp $ */
187dd7cddfSDavid du Colombier /* 12-bit & 24-bit RGB uncompressed TIFF driver */
197dd7cddfSDavid du Colombier #include "gdevprn.h"
207dd7cddfSDavid du Colombier #include "gdevtifs.h"
217dd7cddfSDavid du Colombier 
227dd7cddfSDavid du Colombier /*
237dd7cddfSDavid du Colombier  * Thanks to Alan Barclay <alan@escribe.co.uk> for donating the original
247dd7cddfSDavid du Colombier  * version of this code to Ghostscript.
257dd7cddfSDavid du Colombier  */
267dd7cddfSDavid du Colombier 
277dd7cddfSDavid du Colombier /* ------ The device descriptors ------ */
287dd7cddfSDavid du Colombier 
297dd7cddfSDavid du Colombier /* Default X and Y resolution */
307dd7cddfSDavid du Colombier #define X_DPI 72
317dd7cddfSDavid du Colombier #define Y_DPI 72
327dd7cddfSDavid du Colombier 
337dd7cddfSDavid du Colombier typedef struct gx_device_tiff_s {
347dd7cddfSDavid du Colombier     gx_device_common;
357dd7cddfSDavid du Colombier     gx_prn_device_common;
367dd7cddfSDavid du Colombier     gdev_tiff_state tiff;
377dd7cddfSDavid du Colombier } gx_device_tiff;
387dd7cddfSDavid du Colombier 
397dd7cddfSDavid du Colombier private dev_proc_print_page(tiff12_print_page);
407dd7cddfSDavid du Colombier private dev_proc_print_page(tiff24_print_page);
417dd7cddfSDavid du Colombier 
427dd7cddfSDavid du Colombier private const gx_device_procs tiff12_procs =
437dd7cddfSDavid du Colombier prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
447dd7cddfSDavid du Colombier 		gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb);
457dd7cddfSDavid du Colombier private const gx_device_procs tiff24_procs =
467dd7cddfSDavid du Colombier prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
477dd7cddfSDavid du Colombier 		gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb);
487dd7cddfSDavid du Colombier 
493ff48bf5SDavid du Colombier const gx_device_printer gs_tiff12nc_device = {
503ff48bf5SDavid du Colombier     prn_device_std_body(gx_device_tiff, tiff12_procs, "tiff12nc",
517dd7cddfSDavid du Colombier 			DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
527dd7cddfSDavid du Colombier 			X_DPI, Y_DPI,
537dd7cddfSDavid du Colombier 			0, 0, 0, 0,
547dd7cddfSDavid du Colombier 			24, tiff12_print_page)
557dd7cddfSDavid du Colombier };
567dd7cddfSDavid du Colombier 
573ff48bf5SDavid du Colombier const gx_device_printer gs_tiff24nc_device = {
583ff48bf5SDavid du Colombier     prn_device_std_body(gx_device_tiff, tiff24_procs, "tiff24nc",
597dd7cddfSDavid du Colombier 			DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
607dd7cddfSDavid du Colombier 			X_DPI, Y_DPI,
617dd7cddfSDavid du Colombier 			0, 0, 0, 0,
627dd7cddfSDavid du Colombier 			24, tiff24_print_page)
637dd7cddfSDavid du Colombier };
647dd7cddfSDavid du Colombier 
657dd7cddfSDavid du Colombier /* ------ Private definitions ------ */
667dd7cddfSDavid du Colombier 
677dd7cddfSDavid du Colombier /* Define our TIFF directory - sorted by tag number */
687dd7cddfSDavid du Colombier typedef struct tiff_rgb_directory_s {
697dd7cddfSDavid du Colombier     TIFF_dir_entry BitsPerSample;
707dd7cddfSDavid du Colombier     TIFF_dir_entry Compression;
717dd7cddfSDavid du Colombier     TIFF_dir_entry Photometric;
727dd7cddfSDavid du Colombier     TIFF_dir_entry FillOrder;
737dd7cddfSDavid du Colombier     TIFF_dir_entry SamplesPerPixel;
747dd7cddfSDavid du Colombier } tiff_rgb_directory;
757dd7cddfSDavid du Colombier typedef struct tiff_rgb_values_s {
767dd7cddfSDavid du Colombier     TIFF_ushort bps[3];
777dd7cddfSDavid du Colombier } tiff_rgb_values;
787dd7cddfSDavid du Colombier 
797dd7cddfSDavid du Colombier private const tiff_rgb_directory dir_rgb_template =
807dd7cddfSDavid du Colombier {
817dd7cddfSDavid du Colombier 	/* C's ridiculous rules about & and arrays require bps[0] here: */
827dd7cddfSDavid du Colombier     {TIFFTAG_BitsPerSample, TIFF_SHORT | TIFF_INDIRECT, 3, offset_of(tiff_rgb_values, bps[0])},
837dd7cddfSDavid du Colombier     {TIFFTAG_Compression, TIFF_SHORT, 1, Compression_none},
847dd7cddfSDavid du Colombier     {TIFFTAG_Photometric, TIFF_SHORT, 1, Photometric_RGB},
857dd7cddfSDavid du Colombier     {TIFFTAG_FillOrder, TIFF_SHORT, 1, FillOrder_MSB2LSB},
867dd7cddfSDavid du Colombier     {TIFFTAG_SamplesPerPixel, TIFF_SHORT, 1, 3},
877dd7cddfSDavid du Colombier };
887dd7cddfSDavid du Colombier 
893ff48bf5SDavid du Colombier private const tiff_rgb_values val_12_template = {
907dd7cddfSDavid du Colombier     {4, 4, 4}
917dd7cddfSDavid du Colombier };
927dd7cddfSDavid du Colombier 
933ff48bf5SDavid du Colombier private const tiff_rgb_values val_24_template = {
947dd7cddfSDavid du Colombier     {8, 8, 8}
957dd7cddfSDavid du Colombier };
967dd7cddfSDavid du Colombier 
977dd7cddfSDavid du Colombier /* ------ Private functions ------ */
987dd7cddfSDavid du Colombier 
997dd7cddfSDavid du Colombier private int
tiff12_print_page(gx_device_printer * pdev,FILE * file)1007dd7cddfSDavid du Colombier tiff12_print_page(gx_device_printer * pdev, FILE * file)
1017dd7cddfSDavid du Colombier {
1023ff48bf5SDavid du Colombier     gx_device_tiff *const tfdev = (gx_device_tiff *)pdev;
1037dd7cddfSDavid du Colombier     int code;
1047dd7cddfSDavid du Colombier 
1057dd7cddfSDavid du Colombier     /* Write the page directory. */
1067dd7cddfSDavid du Colombier     code = gdev_tiff_begin_page(pdev, &tfdev->tiff, file,
1077dd7cddfSDavid du Colombier 				(const TIFF_dir_entry *)&dir_rgb_template,
1087dd7cddfSDavid du Colombier 			  sizeof(dir_rgb_template) / sizeof(TIFF_dir_entry),
1097dd7cddfSDavid du Colombier 				(const byte *)&val_12_template,
1103ff48bf5SDavid du Colombier 				sizeof(val_12_template), 0);
1117dd7cddfSDavid du Colombier     if (code < 0)
1127dd7cddfSDavid du Colombier 	return code;
1137dd7cddfSDavid du Colombier 
1147dd7cddfSDavid du Colombier     /* Write the page data. */
1157dd7cddfSDavid du Colombier     {
1167dd7cddfSDavid du Colombier 	int y;
1177dd7cddfSDavid du Colombier 	int raster = gdev_prn_raster(pdev);
1187dd7cddfSDavid du Colombier 	byte *line = gs_alloc_bytes(pdev->memory, raster, "tiff12_print_page");
1197dd7cddfSDavid du Colombier 	byte *row;
1207dd7cddfSDavid du Colombier 
1217dd7cddfSDavid du Colombier 	if (line == 0)
1227dd7cddfSDavid du Colombier 	    return_error(gs_error_VMerror);
1237dd7cddfSDavid du Colombier 
1247dd7cddfSDavid du Colombier 	for (y = 0; y < pdev->height; ++y) {
1257dd7cddfSDavid du Colombier 	    const byte *src;
1267dd7cddfSDavid du Colombier 	    byte *dest;
1277dd7cddfSDavid du Colombier 	    int x;
1287dd7cddfSDavid du Colombier 
1297dd7cddfSDavid du Colombier 	    code = gdev_prn_get_bits(pdev, y, line, &row);
1307dd7cddfSDavid du Colombier 	    if (code < 0)
1317dd7cddfSDavid du Colombier 		break;
1327dd7cddfSDavid du Colombier 
1337dd7cddfSDavid du Colombier 	    for (src = row, dest = line, x = 0; x < raster;
1347dd7cddfSDavid du Colombier 		 src += 6, dest += 3, x += 6
1357dd7cddfSDavid du Colombier 		) {
1367dd7cddfSDavid du Colombier 		dest[0] = (src[0] & 0xf0) | (src[1] >> 4);
1377dd7cddfSDavid du Colombier 		dest[1] = (src[2] & 0xf0) | (src[3] >> 4);
1387dd7cddfSDavid du Colombier 		dest[2] = (src[4] & 0xf0) | (src[5] >> 4);
1397dd7cddfSDavid du Colombier 	    }
1403ff48bf5SDavid du Colombier 	    fwrite(line, 1, (pdev->width * 3 + 1) >> 1, file);
1417dd7cddfSDavid du Colombier 	}
1427dd7cddfSDavid du Colombier 
1433ff48bf5SDavid du Colombier 	gdev_tiff_end_strip(&tfdev->tiff, file);
1447dd7cddfSDavid du Colombier 	gdev_tiff_end_page(&tfdev->tiff, file);
1457dd7cddfSDavid du Colombier 	gs_free_object(pdev->memory, line, "tiff12_print_page");
1467dd7cddfSDavid du Colombier     }
1477dd7cddfSDavid du Colombier 
1487dd7cddfSDavid du Colombier     return code;
1497dd7cddfSDavid du Colombier }
1507dd7cddfSDavid du Colombier 
1517dd7cddfSDavid du Colombier private int
tiff24_print_page(gx_device_printer * pdev,FILE * file)1527dd7cddfSDavid du Colombier tiff24_print_page(gx_device_printer * pdev, FILE * file)
1537dd7cddfSDavid du Colombier {
1543ff48bf5SDavid du Colombier     gx_device_tiff *const tfdev = (gx_device_tiff *)pdev;
1557dd7cddfSDavid du Colombier     int code;
1567dd7cddfSDavid du Colombier 
1577dd7cddfSDavid du Colombier     /* Write the page directory. */
1587dd7cddfSDavid du Colombier     code = gdev_tiff_begin_page(pdev, &tfdev->tiff, file,
1597dd7cddfSDavid du Colombier 				(const TIFF_dir_entry *)&dir_rgb_template,
1607dd7cddfSDavid du Colombier 			  sizeof(dir_rgb_template) / sizeof(TIFF_dir_entry),
1617dd7cddfSDavid du Colombier 				(const byte *)&val_24_template,
1623ff48bf5SDavid du Colombier 				sizeof(val_24_template), 0);
1637dd7cddfSDavid du Colombier     if (code < 0)
1647dd7cddfSDavid du Colombier 	return code;
1657dd7cddfSDavid du Colombier 
1667dd7cddfSDavid du Colombier     /* Write the page data. */
1677dd7cddfSDavid du Colombier     {
1687dd7cddfSDavid du Colombier 	int y;
1697dd7cddfSDavid du Colombier 	int raster = gdev_prn_raster(pdev);
1707dd7cddfSDavid du Colombier 	byte *line = gs_alloc_bytes(pdev->memory, raster, "tiff24_print_page");
1717dd7cddfSDavid du Colombier 	byte *row;
1727dd7cddfSDavid du Colombier 
1737dd7cddfSDavid du Colombier 	if (line == 0)
1747dd7cddfSDavid du Colombier 	    return_error(gs_error_VMerror);
1757dd7cddfSDavid du Colombier 	for (y = 0; y < pdev->height; ++y) {
1767dd7cddfSDavid du Colombier 	    code = gdev_prn_get_bits(pdev, y, line, &row);
1777dd7cddfSDavid du Colombier 	    if (code < 0)
1787dd7cddfSDavid du Colombier 		break;
1797dd7cddfSDavid du Colombier 	    fwrite((char *)row, raster, 1, file);
1807dd7cddfSDavid du Colombier 	}
1813ff48bf5SDavid du Colombier 	gdev_tiff_end_strip(&tfdev->tiff, file);
1827dd7cddfSDavid du Colombier 	gdev_tiff_end_page(&tfdev->tiff, file);
1837dd7cddfSDavid du Colombier 	gs_free_object(pdev->memory, line, "tiff24_print_page");
1847dd7cddfSDavid du Colombier     }
1857dd7cddfSDavid du Colombier 
1867dd7cddfSDavid du Colombier     return code;
1877dd7cddfSDavid du Colombier }
188