home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / g / gs252src.zip / GS252 / GDEVPBM.C < prev    next >
C/C++ Source or Header  |  1992-09-07  |  11KB  |  348 lines

  1. /* Copyright (C) 1992 Aladdin Enterprises.  All rights reserved.
  2.    Distributed by Free Software Foundation, Inc.
  3.  
  4. This file is part of Ghostscript.
  5.  
  6. Ghostscript is distributed in the hope that it will be useful, but
  7. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  8. to anyone for the consequences of using it or for whether it serves any
  9. particular purpose or works at all, unless he says so in writing.  Refer
  10. to the Ghostscript General Public License for full details.
  11.  
  12. Everyone is granted permission to copy, modify and redistribute
  13. Ghostscript, but only under the conditions described in the Ghostscript
  14. General Public License.  A copy of this license is supposed to have been
  15. given to you along with Ghostscript so you can know your rights and
  16. responsibilities.  It should be in a file named COPYING.  Among other
  17. things, the copyright notice and this notice must be preserved on all
  18. copies.  */
  19.  
  20. /* gdevpbm.c */
  21. /* Portable Bit/Gray/PixMap devices for Ghostscript. */
  22. #include "gdevprn.h"
  23. #include "gxlum.h"
  24.  
  25. /* Thanks are due to Jos Vos (jos@bull.nl) for an earlier P*M driver, */
  26. /* on which this one is based. */
  27.  
  28. /* Structure for P*M devices, which extend the generic printer device. */
  29.  
  30. #define MAX_COMMENT 70            /* max user-supplied comment */
  31. struct gx_device_pbm_s {
  32.     gx_device_common;
  33.     gx_prn_device_common;
  34.     /* Additional state for P*M devices */
  35.     const char *magic;        /* "Pn" */
  36.     char comment[MAX_COMMENT + 1];    /* comment for head of file */
  37.     byte is_raw;            /* 1 if raw format, 0 if plain */
  38.     byte is_pbm;            /* 1 if bitmap, 0 if gray or pixmap */
  39. };
  40. typedef struct gx_device_pbm_s gx_device_pbm;
  41.  
  42. /* ------ The device descriptors ------ */
  43.  
  44. /*
  45.  * Standard U.S. page width and height.  A4 paper is 8.4" x 11.7".
  46.  */
  47. #define WIDTH_10THS 85
  48. #define HEIGHT_10THS 110
  49.  
  50. /*
  51.  * Default X and Y resolution.
  52.  */
  53. #define X_DPI 72
  54. #define Y_DPI 72
  55.  
  56. /* Macro for generating P*M device descriptors. */
  57. #define pbm_prn_device(procs, dev_name, magic, is_raw, num_comp, depth, max_gray, max_rgb, print_page)\
  58. {    prn_device_body(gx_device_pbm, procs, dev_name,\
  59.       WIDTH_10THS, HEIGHT_10THS, X_DPI, Y_DPI,\
  60.       0, 0, 0, 0,\
  61.       num_comp, depth, max_gray, max_rgb, max_gray + 1, max_rgb + 1,\
  62.       print_page),\
  63.     magic,\
  64.      { 0 },\
  65.     is_raw,\
  66.     (depth == 1)\
  67. }
  68.  
  69. /* For all PBM variants we do some extra things at opening time. */
  70. /* private dev_proc_open_device(gdev_pbm_open); */
  71. #define gdev_pbm_open gdev_prn_open        /* no we don't! */
  72.  
  73. /* For PGM and PPM we need our own color mapping procedures. */
  74. private dev_proc_map_rgb_color(pgm_map_rgb_color);
  75. private dev_proc_map_rgb_color(ppm_map_rgb_color);
  76. private dev_proc_map_color_rgb(pgm_map_color_rgb);
  77. private dev_proc_map_color_rgb(ppm_map_color_rgb);
  78.  
  79. /* And of course we need our own print-page routines. */
  80. private dev_proc_print_page(pbm_print_page);
  81. private dev_proc_print_page(pbm_raw_print_page);
  82. private dev_proc_print_page(pgm_print_page);
  83. private dev_proc_print_page(ppm_print_page);
  84.  
  85. /* The device procedures */
  86. private gx_device_procs pbm_procs =
  87.     prn_procs(gdev_pbm_open, gdev_prn_output_page, gdev_prn_close);
  88. private gx_device_procs pgm_procs =
  89.     prn_color_procs(gdev_pbm_open, gdev_prn_output_page, gdev_prn_close,
  90.     pgm_map_rgb_color, pgm_map_color_rgb);
  91. private gx_device_procs ppm_procs =
  92.     prn_color_procs(gdev_pbm_open, gdev_prn_output_page, gdev_prn_close,
  93.     ppm_map_rgb_color, ppm_map_color_rgb);
  94.  
  95. /* The device descriptors themselves */
  96. gx_device_pbm gs_pbm_device =
  97.   pbm_prn_device(pbm_procs, "pbm", "P1", 0, 1, 1, 1, 0,
  98.       pbm_print_page);
  99. gx_device_pbm gs_pbmraw_device =
  100.   pbm_prn_device(pbm_procs, "pbmraw", "P4", 1, 1, 1, 1, 1,
  101.       pbm_raw_print_page);
  102. gx_device_pbm gs_pgm_device =
  103.   pbm_prn_device(pgm_procs, "pgm", "P2", 0, 1, 8, 255, 0,
  104.       pgm_print_page);
  105. gx_device_pbm gs_pgmraw_device =
  106.   pbm_prn_device(pgm_procs, "pgmraw", "P5", 1, 1, 8, 255, 0,
  107.       pgm_print_page);
  108. gx_device_pbm gs_ppm_device =
  109.   pbm_prn_device(ppm_procs, "ppm", "P3", 0, 3, 24, 255, 255,
  110.       ppm_print_page);
  111. gx_device_pbm gs_ppmraw_device =
  112.   pbm_prn_device(ppm_procs, "ppmraw", "P6", 1, 3, 24, 255, 255,
  113.       ppm_print_page);
  114.  
  115. /* ------ Color mapping routines ------ */
  116.  
  117. /* Map an RGB color to a PGM gray value. */
  118. private gx_color_index
  119. pgm_map_rgb_color(gx_device *dev, ushort r, ushort g, ushort b)
  120. {    /* We round the value rather than truncating it. */
  121.     return ((r * (ulong)lum_red_weight) +
  122.         (g * (ulong)lum_green_weight) +
  123.         (b * (ulong)lum_blue_weight) +
  124.         (lum_all_weights / 2))
  125.            / lum_all_weights * dev->color_info.max_gray / gx_max_color_value;
  126. }
  127.  
  128. /* Map a PGM gray value back to an RGB color. */
  129. private int
  130. pgm_map_color_rgb(gx_device *dev, gx_color_index color, ushort prgb[3])
  131. {    gx_color_value gray =
  132.         color * gx_max_color_value / dev->color_info.max_gray;
  133.     prgb[0] = gray;
  134.     prgb[1] = gray;
  135.     prgb[2] = gray;
  136.     return 0;
  137. }
  138.  
  139. /* Map an RGB color to a PPM color tuple. */
  140. private gx_color_index
  141. ppm_map_rgb_color(gx_device *dev, ushort r, ushort g, ushort b)
  142. {    ushort bitspercolor = dev->color_info.depth / 3;
  143.     ulong max_value = (1 << bitspercolor) - 1;
  144.     return ((r * max_value / gx_max_color_value) << (bitspercolor * 2)) +
  145.            ((g * max_value / gx_max_color_value) << bitspercolor) +
  146.            (b * max_value / gx_max_color_value);
  147. }
  148.  
  149. /* Map a PPM color tuple back to an RGB color. */
  150. private int
  151. ppm_map_color_rgb(gx_device *dev, gx_color_index color, ushort prgb[3])
  152. {    ushort bitspercolor = dev->color_info.depth / 3;
  153.     ushort colormask = (1 << bitspercolor) - 1;
  154.  
  155.     prgb[0] = ((color >> (bitspercolor * 2)) & colormask) *
  156.         (ulong)gx_max_color_value / colormask;
  157.     prgb[1] = ((color >> bitspercolor) & colormask) *
  158.         (ulong)gx_max_color_value / colormask;
  159.     prgb[2] = (color & colormask) *
  160.         (ulong)gx_max_color_value / colormask;
  161.     return 0;
  162. }
  163.  
  164. /* ------ Internal routines ------ */
  165.  
  166. /* Define a "cursor" that keeps track of where we are in the page. */
  167. typedef struct pbm_cursor_s {
  168.     gx_device_pbm *dev;
  169.     int bpp;            /* bits per pixel */
  170.     uint line_size;            /* bytes per scan line */
  171.     byte *data;            /* output row buffer */
  172.     int lnum;            /* row within page */
  173. } pbm_cursor;
  174.  
  175. /* Begin a P*M output page. */
  176. /* Write the header information and initialize the cursor. */
  177. private int
  178. pbm_begin_page(gx_device_pbm *bdev, FILE *pstream, pbm_cursor _ss *pcur)
  179. {    uint line_size = gdev_prn_raster((gx_device_printer *)bdev);
  180.     byte *data = (byte *)gs_malloc(line_size, 1, "pbm_begin_page");
  181.     if ( data == 0 )
  182.         return_error(gs_error_VMerror);
  183.     fprintf(pstream, "%s\n", bdev->magic);
  184.     if ( bdev->comment[0] )
  185.         fprintf(pstream, "# %s\n", bdev->comment);
  186.     else
  187.         fprintf(pstream, "# Image generated by Ghostscript (device=%s)\n",
  188.             bdev->dname);
  189.     fprintf(pstream, "%d %d\n", bdev->width, bdev->height);
  190.     if ( !bdev->is_pbm )
  191.         fprintf(pstream, "%d\n", bdev->color_info.max_gray);
  192.     /* Initialize the cursor. */
  193.     pcur->dev = bdev;
  194.     pcur->bpp = bdev->color_info.depth;
  195.     pcur->line_size = line_size;
  196.     pcur->data = data;
  197.     pcur->lnum = 0;
  198.     return 0;
  199. }
  200.  
  201. /* Advance to the next row.  Return 0 if more, 1 if done. */
  202. private int
  203. pbm_next_row(pbm_cursor _ss *pcur)
  204. {    if ( pcur->lnum >= pcur->dev->height )
  205.        {    gs_free((char *)pcur->data, pcur->line_size, 1,
  206.             "pbm_next_row(done)");
  207.         return 1;
  208.        }
  209.     gdev_prn_copy_scan_lines((gx_device_printer *)pcur->dev,
  210.                  pcur->lnum++, pcur->data, pcur->line_size);
  211.     return 0;
  212. }
  213.  
  214. /* ------ Individual page printing routines ------ */
  215.  
  216. #define bdev ((gx_device_pbm *)pdev)
  217.  
  218. /* Print a raw monobit page. */
  219. private int
  220. pbm_raw_print_page(gx_device_printer *pdev, FILE *pstream)
  221. {    /* All the print_page routines have the same structure; */
  222.     /* only the indicated section is different. */
  223.     pbm_cursor cur;
  224.     int code = pbm_begin_page(bdev, pstream, &cur);
  225.     if ( code < 0 ) return code;
  226.     while ( !(code = pbm_next_row(&cur)) )
  227.        {
  228.         /* ---- This section changes. ---- */
  229.  
  230.         fwrite(cur.data, 1, cur.line_size, pstream);
  231.  
  232.         /* ---- End of changing section. ---- */
  233.        }
  234.     return (code < 0 ? code : 0);
  235. }
  236.  
  237. /* Print an ASCII monobit page. */
  238. private int
  239. pbm_print_page(gx_device_printer *pdev, FILE *pstream)
  240. {    pbm_cursor cur;
  241.     int code = pbm_begin_page(bdev, pstream, &cur);
  242.     if ( code < 0 ) return code;
  243.     while ( !(code = pbm_next_row(&cur)) )
  244.        {    byte *bp;
  245.         uint x, mask;
  246.         for ( bp = cur.data, x = 0, mask = 0x80; x < bdev->width;
  247.               (mask >>= 1) != 0 || (bp++, mask = 0x80)
  248.             )
  249.            {    putc((*bp & mask ? '1' : '0'), pstream);
  250.             if ( ++x == bdev->width || !(x & 63) )
  251.                 putc('\n', pstream);
  252.            }
  253.        }
  254.     return (code < 0 ? code : 0);
  255. }
  256.  
  257. /* Print a gray-mapped page. */
  258. private int
  259. pgm_print_page(gx_device_printer *pdev, FILE *pstream)
  260. {    pbm_cursor cur;
  261.     int code = pbm_begin_page(bdev, pstream, &cur);
  262.     uint mask;
  263.     if ( code < 0 ) return code;
  264.     /* Note that bpp <= 8 for raw format, bpp <= 16 for plain. */
  265.     mask = (1 << cur.bpp) - 1;
  266.     while ( !(code = pbm_next_row(&cur)) )
  267.        {    byte *bp;
  268.         uint x;
  269.         int shift;
  270.         for ( bp = cur.data, x = 0, shift = 8 - cur.bpp;
  271.               x < bdev->width;
  272.             )
  273.            {    uint pixel;
  274.             if ( shift < 0 )    /* bpp = 16 */
  275.                {    pixel = ((uint)*bp << 8) + bp[1];
  276.                 bp += 2;
  277.                }
  278.             else
  279.                {    pixel = (*bp >> shift) & mask;
  280.                 if ( (shift -= cur.bpp) < 0 )
  281.                     bp++, shift += 8;
  282.                }
  283.             ++x;
  284.             if ( bdev->is_raw )
  285.                 putc(pixel, pstream);
  286.             else
  287.                 fprintf(pstream, "%d%c", pixel,
  288.                     (x == bdev->width || !(x & 15) ?
  289.                      '\n' : ' '));
  290.            }
  291.        }
  292.     return (code < 0 ? code : 0);
  293. }
  294.  
  295. /* Print a color-mapped page. */
  296. private int
  297. ppm_print_page(gx_device_printer *pdev, FILE *pstream)
  298. {    pbm_cursor cur;
  299.     int code = pbm_begin_page(bdev, pstream, &cur);
  300.     uint bpe, mask;
  301.     if ( code < 0 ) return code;
  302.     /* Note that bpp <= 24 for raw format, bpp <= 32 for plain. */
  303.     bpe = cur.bpp / 3;        /* bits per r/g/b element */
  304.     mask = (1 << bpe) - 1;
  305.     while ( !(code = pbm_next_row(&cur)) )
  306.        {    byte *bp;
  307.         uint x;
  308.         int shift;
  309.         for ( bp = cur.data, x = 0, shift = 8 - cur.bpp;
  310.               x < bdev->width;
  311.             )
  312.            {    ulong pixel = 0;
  313.             uint r, g, b;
  314.             switch ( cur.bpp >> 3 )
  315.                {
  316.             case 3:
  317.                 pixel = (ulong)*bp << 16; bp++;
  318.                 /* falls through */
  319.             case 2:
  320.                 pixel += (uint)*bp << 8; bp++;
  321.                 /* falls through */
  322.             case 1:
  323.                 pixel += *bp; bp++;
  324.                 break;
  325.             case 0:            /* bpp == 4, bpe == 1 */
  326.                 pixel = *bp >> shift;
  327.                 if ( (shift -= cur.bpp) < 0 )
  328.                     bp++, shift += 8;
  329.                 break;
  330.                }
  331.             ++x;
  332.             b = pixel & mask;  pixel >>= bpe;
  333.             g = pixel & mask;  pixel >>= bpe;
  334.             r = pixel & mask;
  335.             if ( bdev->is_raw )
  336.                {    putc(r, pstream);
  337.                 putc(g, pstream);
  338.                 putc(b, pstream);
  339.                }
  340.             else
  341.                 fprintf(pstream, "%d %d %d%c", r, g, b,
  342.                     (x == bdev->width || !(x & 7) ?
  343.                      '\n' : ' '));
  344.            }
  345.        }
  346.     return (code < 0 ? code : 0);
  347. }
  348.