/* Copyright (C) 1995, 2000 artofcode LLC. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA, 02111-1307. */ /*$Id: gdevtfnx.c,v 1.5.2.1.2.1 2003/01/17 00:49:01 giles Exp $ */ /* 12-bit & 24-bit RGB uncompressed TIFF driver */ #include "gdevprn.h" #include "gdevtifs.h" /* * Thanks to Alan Barclay for donating the original * version of this code to Ghostscript. */ /* ------ The device descriptors ------ */ /* Default X and Y resolution */ #define X_DPI 72 #define Y_DPI 72 typedef struct gx_device_tiff_s { gx_device_common; gx_prn_device_common; gdev_tiff_state tiff; } gx_device_tiff; private dev_proc_print_page(tiff12_print_page); private dev_proc_print_page(tiff24_print_page); private const gx_device_procs tiff12_procs = prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close, gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb); private const gx_device_procs tiff24_procs = prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close, gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb); const gx_device_printer gs_tiff12nc_device = { prn_device_std_body(gx_device_tiff, tiff12_procs, "tiff12nc", DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, X_DPI, Y_DPI, 0, 0, 0, 0, 24, tiff12_print_page) }; const gx_device_printer gs_tiff24nc_device = { prn_device_std_body(gx_device_tiff, tiff24_procs, "tiff24nc", DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, X_DPI, Y_DPI, 0, 0, 0, 0, 24, tiff24_print_page) }; /* ------ Private definitions ------ */ /* Define our TIFF directory - sorted by tag number */ typedef struct tiff_rgb_directory_s { TIFF_dir_entry BitsPerSample; TIFF_dir_entry Compression; TIFF_dir_entry Photometric; TIFF_dir_entry FillOrder; TIFF_dir_entry SamplesPerPixel; } tiff_rgb_directory; typedef struct tiff_rgb_values_s { TIFF_ushort bps[3]; } tiff_rgb_values; private const tiff_rgb_directory dir_rgb_template = { /* C's ridiculous rules about & and arrays require bps[0] here: */ {TIFFTAG_BitsPerSample, TIFF_SHORT | TIFF_INDIRECT, 3, offset_of(tiff_rgb_values, bps[0])}, {TIFFTAG_Compression, TIFF_SHORT, 1, Compression_none}, {TIFFTAG_Photometric, TIFF_SHORT, 1, Photometric_RGB}, {TIFFTAG_FillOrder, TIFF_SHORT, 1, FillOrder_MSB2LSB}, {TIFFTAG_SamplesPerPixel, TIFF_SHORT, 1, 3}, }; private const tiff_rgb_values val_12_template = { {4, 4, 4} }; private const tiff_rgb_values val_24_template = { {8, 8, 8} }; /* ------ Private functions ------ */ private int tiff12_print_page(gx_device_printer * pdev, FILE * file) { gx_device_tiff *const tfdev = (gx_device_tiff *)pdev; int code; /* Write the page directory. */ code = gdev_tiff_begin_page(pdev, &tfdev->tiff, file, (const TIFF_dir_entry *)&dir_rgb_template, sizeof(dir_rgb_template) / sizeof(TIFF_dir_entry), (const byte *)&val_12_template, sizeof(val_12_template), 0); if (code < 0) return code; /* Write the page data. */ { int y; int raster = gdev_prn_raster(pdev); byte *line = gs_alloc_bytes(pdev->memory, raster, "tiff12_print_page"); byte *row; if (line == 0) return_error(gs_error_VMerror); for (y = 0; y < pdev->height; ++y) { const byte *src; byte *dest; int x; code = gdev_prn_get_bits(pdev, y, line, &row); if (code < 0) break; for (src = row, dest = line, x = 0; x < raster; src += 6, dest += 3, x += 6 ) { dest[0] = (src[0] & 0xf0) | (src[1] >> 4); dest[1] = (src[2] & 0xf0) | (src[3] >> 4); dest[2] = (src[4] & 0xf0) | (src[5] >> 4); } fwrite(line, 1, (pdev->width * 3 + 1) >> 1, file); } gdev_tiff_end_strip(&tfdev->tiff, file); gdev_tiff_end_page(&tfdev->tiff, file); gs_free_object(pdev->memory, line, "tiff12_print_page"); } return code; } private int tiff24_print_page(gx_device_printer * pdev, FILE * file) { gx_device_tiff *const tfdev = (gx_device_tiff *)pdev; int code; /* Write the page directory. */ code = gdev_tiff_begin_page(pdev, &tfdev->tiff, file, (const TIFF_dir_entry *)&dir_rgb_template, sizeof(dir_rgb_template) / sizeof(TIFF_dir_entry), (const byte *)&val_24_template, sizeof(val_24_template), 0); if (code < 0) return code; /* Write the page data. */ { int y; int raster = gdev_prn_raster(pdev); byte *line = gs_alloc_bytes(pdev->memory, raster, "tiff24_print_page"); byte *row; if (line == 0) return_error(gs_error_VMerror); for (y = 0; y < pdev->height; ++y) { code = gdev_prn_get_bits(pdev, y, line, &row); if (code < 0) break; fwrite((char *)row, raster, 1, file); } gdev_tiff_end_strip(&tfdev->tiff, file); gdev_tiff_end_page(&tfdev->tiff, file); gs_free_object(pdev->memory, line, "tiff24_print_page"); } return code; }