home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 4 / DATAFILE_PDCD4.iso / utilities / utilsm / netpbmsca / pgm / c / pgmtopbm < prev    next >
Encoding:
Text File  |  1993-10-04  |  6.5 KB  |  268 lines

  1. /* pgmtopbm.c - read a portable graymap and write a portable bitmap
  2. **
  3. ** Copyright (C) 1989 by Jef Poskanzer.
  4. **
  5. ** Permission to use, copy, modify, and distribute this software and its
  6. ** documentation for any purpose and without fee is hereby granted, provided
  7. ** that the above copyright notice appear in all copies and that both that
  8. ** copyright notice and this permission notice appear in supporting
  9. ** documentation.  This software is provided "as is" without express or
  10. ** implied warranty.
  11. */
  12.  
  13. #include "pgm.h"
  14. #include "pbm.h"
  15. #include "dithers.h"
  16.  
  17. int
  18. main( argc, argv )
  19.     int argc;
  20.     char* argv[];
  21.     {
  22.     FILE* ifp;
  23.     gray* grayrow;
  24.     register gray* gP;
  25.     bit* bitrow;
  26.     register bit* bP;
  27.     int argn, rows, cols, format, row, col, limitcol;
  28.     float fthreshval;
  29.     gray maxval;
  30.     char* usage = "[-floyd|-fs | -threshold | -dither8|-d8 |\n     -cluster3|-c3|-cluster4|-c4|-cluster8|-c8] [-value <val>] [pgmfile]";
  31.     int halftone;
  32. #define QT_FS 1
  33. #define QT_THRESH 2
  34. #define QT_DITHER8 3
  35. #define QT_CLUSTER3 4
  36. #define QT_CLUSTER4 5
  37. #define QT_CLUSTER8 6
  38.     long threshval, sum;
  39.     long* thiserr;
  40.     long* nexterr;
  41.     long* temperr;
  42. #define FS_SCALE 1024
  43. #define HALF_FS_SCALE 512
  44.     int fs_direction;
  45.  
  46.  
  47.     pgm_init( &argc, argv );
  48.  
  49.     argn = 1;
  50.     halftone = QT_FS;    /* default quantization is Floyd-Steinberg */
  51.     fthreshval = 0.5;
  52.  
  53.     while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
  54.     {
  55.     if ( pm_keymatch( argv[argn], "-fs", 2 ) ||
  56.          pm_keymatch( argv[argn], "-floyd", 2 ) )
  57.         halftone = QT_FS;
  58.     else if ( pm_keymatch( argv[argn], "-threshold", 2 ) )
  59.         halftone = QT_THRESH;
  60.     else if ( pm_keymatch( argv[argn], "-dither8", 2 ) ||
  61.               pm_keymatch( argv[argn], "-d8", 3 ) )
  62.         halftone = QT_DITHER8;
  63.     else if ( pm_keymatch( argv[argn], "-cluster3", 9 ) ||
  64.               pm_keymatch( argv[argn], "-c3", 3 ) )
  65.         halftone = QT_CLUSTER3;
  66.     else if ( pm_keymatch( argv[argn], "-cluster4", 9 ) ||
  67.               pm_keymatch( argv[argn], "-c4", 3 ) )
  68.         halftone = QT_CLUSTER4;
  69.     else if ( pm_keymatch( argv[argn], "-cluster8", 9 ) ||
  70.               pm_keymatch( argv[argn], "-c8", 3 ) )
  71.         halftone = QT_CLUSTER8;
  72.     else if ( pm_keymatch( argv[argn], "-value", 2 ) )
  73.         {
  74.         ++argn;
  75.         if ( argn == argc || sscanf( argv[argn], "%f", &fthreshval ) != 1 ||
  76.          fthreshval < 0.0 || fthreshval > 1.0 )
  77.         pm_usage( usage );
  78.         }
  79.     else
  80.         pm_usage( usage );
  81.     ++argn;
  82.     }
  83.  
  84.     if ( argn != argc )
  85.     {
  86.     ifp = pm_openr( argv[argn] );
  87.     ++argn;
  88.     }
  89.     else
  90.     ifp = stdin;
  91.  
  92.     if ( argn != argc )
  93.     pm_usage( usage );
  94.  
  95.     pgm_readpgminit( ifp, &cols, &rows, &maxval, &format );
  96.     grayrow = pgm_allocrow( cols );
  97.  
  98.     pbm_writepbminit( stdout, cols, rows, 0 );
  99.     bitrow = pbm_allocrow( cols );
  100.  
  101.     /* Initialize. */
  102.     switch ( halftone )
  103.     {
  104.     case QT_FS:
  105.     /* Initialize Floyd-Steinberg error vectors. */
  106.     thiserr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  107.     nexterr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  108.     srandom( (int) ( time( 0 ) ^ getpid( ) ) );
  109.     for ( col = 0; col < cols + 2; ++col )
  110.         thiserr[col] = ( random( ) % FS_SCALE - HALF_FS_SCALE ) / 4;
  111.         /* (random errors in [-FS_SCALE/8 .. FS_SCALE/8]) */
  112.     fs_direction = 1;
  113.     threshval = fthreshval * FS_SCALE;
  114.     break;
  115.  
  116.     case QT_THRESH:
  117.     threshval = fthreshval * maxval + 0.999999;
  118.     break;
  119.  
  120.     case QT_DITHER8:
  121.     /* Scale dither matrix. */
  122.     for ( row = 0; row < 16; ++row )
  123.         for ( col = 0; col < 16; ++col )
  124.         dither8[row][col] = dither8[row][col] * ( maxval + 1 ) / 256;
  125.     break;
  126.  
  127.     case QT_CLUSTER3:
  128.     /* Scale order-3 clustered dither matrix. */
  129.     for ( row = 0; row < 6; ++row )
  130.         for ( col = 0; col < 6; ++col )
  131.         cluster3[row][col] = cluster3[row][col] * ( maxval + 1 ) / 18;
  132.     break;
  133.  
  134.     case QT_CLUSTER4:
  135.     /* Scale order-4 clustered dither matrix. */
  136.     for ( row = 0; row < 8; ++row )
  137.         for ( col = 0; col < 8; ++col )
  138.         cluster4[row][col] = cluster4[row][col] * ( maxval + 1 ) / 32;
  139.     break;
  140.  
  141.     case QT_CLUSTER8:
  142.     /* Scale order-8 clustered dither matrix. */
  143.     for ( row = 0; row < 16; ++row )
  144.         for ( col = 0; col < 16; ++col )
  145.         cluster8[row][col] = cluster8[row][col] * ( maxval + 1 ) / 128;
  146.     break;
  147.  
  148.     default:
  149.     pm_error( "can't happen" );
  150.     }
  151.  
  152.     for ( row = 0; row < rows; ++row )
  153.     {
  154.     pgm_readpgmrow( ifp, grayrow, cols, maxval, format );
  155.  
  156.     switch ( halftone )
  157.         {
  158.         case QT_FS:
  159.         for ( col = 0; col < cols + 2; ++col )
  160.         nexterr[col] = 0;
  161.         if ( fs_direction )
  162.         {
  163.         col = 0;
  164.         limitcol = cols;
  165.         gP = grayrow;
  166.         bP = bitrow;
  167.         }
  168.         else
  169.         {
  170.         col = cols - 1;
  171.         limitcol = -1;
  172.         gP = &(grayrow[col]);
  173.         bP = &(bitrow[col]);
  174.         }
  175.         do
  176.         {
  177.         sum = ( (long) *gP * FS_SCALE ) / maxval + thiserr[col + 1];
  178.         if ( sum >= threshval )
  179.             {
  180.             *bP = PBM_WHITE;
  181.             sum = sum - threshval - HALF_FS_SCALE;
  182.             }
  183.         else
  184.             *bP = PBM_BLACK;
  185.  
  186.         if ( fs_direction )
  187.             {
  188.             thiserr[col + 2] += ( sum * 7 ) / 16;
  189.             nexterr[col    ] += ( sum * 3 ) / 16;
  190.             nexterr[col + 1] += ( sum * 5 ) / 16;
  191.             nexterr[col + 2] += ( sum     ) / 16;
  192.  
  193.             ++col;
  194.             ++gP;
  195.             ++bP;
  196.             }
  197.         else
  198.             {
  199.             thiserr[col    ] += ( sum * 7 ) / 16;
  200.             nexterr[col + 2] += ( sum * 3 ) / 16;
  201.             nexterr[col + 1] += ( sum * 5 ) / 16;
  202.             nexterr[col    ] += ( sum     ) / 16;
  203.  
  204.             --col;
  205.             --gP;
  206.             --bP;
  207.             }
  208.         }
  209.         while ( col != limitcol );
  210.         temperr = thiserr;
  211.         thiserr = nexterr;
  212.         nexterr = temperr;
  213.         fs_direction = ! fs_direction;
  214.         break;
  215.  
  216.         case QT_THRESH:
  217.         for ( col = 0, gP = grayrow, bP = bitrow; col < cols; ++col, ++gP, ++bP )
  218.         if ( *gP >= threshval )
  219.             *bP = PBM_WHITE;
  220.         else
  221.             *bP = PBM_BLACK;
  222.         break;
  223.  
  224.         case QT_DITHER8:
  225.         for ( col = 0, gP = grayrow, bP = bitrow; col < cols; ++col, ++gP, ++bP )
  226.         if ( *gP >= dither8[row % 16][col % 16] )
  227.             *bP = PBM_WHITE;
  228.         else
  229.             *bP = PBM_BLACK;
  230.         break;
  231.  
  232.         case QT_CLUSTER3:
  233.         for ( col = 0, gP = grayrow, bP = bitrow; col < cols; ++col, ++gP, ++bP )
  234.         if ( *gP >= cluster3[row % 6][col % 6] )
  235.             *bP = PBM_WHITE;
  236.         else
  237.             *bP = PBM_BLACK;
  238.         break;
  239.  
  240.         case QT_CLUSTER4:
  241.         for ( col = 0, gP = grayrow, bP = bitrow; col < cols; ++col, ++gP, ++bP )
  242.         if ( *gP >= cluster4[row % 8][col % 8] )
  243.             *bP = PBM_WHITE;
  244.         else
  245.             *bP = PBM_BLACK;
  246.         break;
  247.  
  248.         case QT_CLUSTER8:
  249.         for ( col = 0, gP = grayrow, bP = bitrow; col < cols; ++col, ++gP, ++bP )
  250.         if ( *gP >= cluster8[row % 16][col % 16] )
  251.             *bP = PBM_WHITE;
  252.         else
  253.             *bP = PBM_BLACK;
  254.         break;
  255.  
  256.         default:
  257.         pm_error( "can't happen" );
  258.         }
  259.  
  260.     pbm_writepbmrow( stdout, bitrow, cols, 0 );
  261.     }
  262.  
  263.     pm_close( ifp );
  264.     pm_close( stdout );
  265.  
  266.     exit( 0 );
  267.     }
  268.