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