home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / netpbma.zip / pbm / pbmpscale.c < prev    next >
C/C++ Source or Header  |  1993-10-04  |  6KB  |  193 lines

  1. /* pbmpscale.c - pixel scaling with jagged edge smoothing.
  2.  * AJCD 13/8/90
  3.  */
  4.  
  5. #include <stdio.h>
  6. #include "pbm.h"
  7.  
  8. /* prototypes */
  9. void nextrow_pscale ARGS((FILE *ifd, int row));
  10. int corner ARGS((int pat));
  11.  
  12. /* input bitmap size and storage */
  13. int rows, columns, format ;
  14. bit *inrow[3] ;
  15.  
  16. #define thisrow (1)
  17.  
  18. /* compass directions from west clockwise */
  19. int xd_pscale[] = { -1, -1,  0,  1, 1, 1, 0, -1 } ;
  20. int yd_pscale[] = {  0, -1, -1, -1, 0, 1, 1,  1 } ;
  21.  
  22. /* starting positions for corners */
  23. #define NE(f) ((f) & 3)
  24. #define SE(f) (((f) >> 2) & 3)
  25. #define SW(f) (((f) >> 4) & 3)
  26. #define NW(f) (((f) >> 6) & 3)
  27.  
  28. typedef unsigned short sixteenbits ;
  29.  
  30. /* list of corner patterns; bit 7 is current colour, bits 0-6 are squares
  31.  * around (excluding square behind), going clockwise.
  32.  * The high byte of the patterns is a mask, which determines which bits are
  33.  * not ignored.
  34.  */
  35.  
  36. sixteenbits patterns[] = { 0x0000, 0xd555,         /* no corner */
  37.                            0x0001, 0xffc1, 0xd514, /* normal corner */
  38.                            0x0002, 0xd554, 0xd515, /* reduced corners */
  39.                            0xbea2, 0xdfc0, 0xfd81,
  40.                            0xfd80, 0xdf80,
  41.                            0x0003, 0xbfa1, 0xfec2 /* reduced if > 1 */
  42.                            };
  43.  
  44. /* search for corner patterns, return type of corner found:
  45.  *  0 = no corner,
  46.  *  1 = normal corner,
  47.  *  2 = reduced corner,
  48.  *  3 = reduced if cutoff > 1
  49.  */
  50.  
  51. int corner(pat)
  52.      int pat;
  53. {
  54.    register int i, r=0;
  55.    for (i = 0; i < sizeof(patterns)/sizeof(sixteenbits); i++)
  56.       if (patterns[i] < 0x100)
  57.          r = patterns[i];
  58.       else if ((pat & (patterns[i] >> 8)) ==
  59.                (patterns[i] & (patterns[i] >> 8)))
  60.          return r;
  61.    return 0;
  62. }
  63.  
  64. /* get a new row
  65.  */
  66.  
  67. void nextrow_pscale(ifd, row)
  68.      FILE *ifd;
  69.      int row;
  70. {
  71.    bit *shuffle = inrow[0] ;
  72.    inrow[0] = inrow[1];
  73.    inrow[1] = inrow[2];
  74.    inrow[2] = shuffle ;
  75.    if (row < rows) {
  76.       if (shuffle == NULL)
  77.          inrow[2] = shuffle = pbm_allocrow(columns);
  78.       pbm_readpbmrow(ifd, inrow[2], columns, format) ;
  79.    } else inrow[2] = NULL; /* discard storage */
  80.  
  81. }
  82.  
  83. int
  84. main(argc, argv)
  85.      int argc;
  86.      char *argv[];
  87. {
  88.    FILE *ifd;
  89.    register bit *outrow;
  90.    register int row, col, i, k;
  91.    int scale, cutoff, ucutoff ;
  92.    unsigned char *flags;
  93.  
  94.    pbm_init( &argc, argv );
  95.  
  96.    if (argc < 2)
  97.       pm_usage("scale [pbmfile]");
  98.  
  99.    scale = atoi(argv[1]);
  100.    if (scale < 1)
  101.       pm_perror("bad scale (< 1)");
  102.  
  103.    if (argc == 3)
  104.       ifd = pm_openr(argv[2]);
  105.    else
  106.       ifd = stdin ;
  107.  
  108.    inrow[0] = inrow[1] = inrow[2] = NULL;
  109.    pbm_readpbminit(ifd, &columns, &rows, &format) ;
  110.  
  111.    outrow = pbm_allocrow(columns*scale) ;
  112.    flags = (unsigned char *)malloc(sizeof(unsigned char)*columns) ;
  113.    if (flags == NULL) pm_perror("out of memory") ;
  114.  
  115.    pbm_writepbminit(stdout, columns*scale, rows*scale, 0) ;
  116.  
  117.    cutoff = scale / 2;
  118.    ucutoff = scale - 1 - cutoff;
  119.    nextrow_pscale(ifd, 0);
  120.    for (row = 0; row < rows; row++) {
  121.       nextrow_pscale(ifd, row+1);
  122.       for (col = 0; col < columns; col++) {
  123.          flags[col] = 0 ;
  124.          for (i = 0; i != 8; i += 2) {
  125.             int vec = inrow[thisrow][col] != PBM_WHITE;
  126.             for (k = 0; k < 7; k++) {
  127.                int x = col + xd_pscale[(k+i)&7] ;
  128.                int y = thisrow + yd_pscale[(k+i)&7] ;
  129.                vec <<= 1;
  130.                if (x >=0 && x < columns && inrow[y])
  131.                   vec |= (inrow[y][x] != PBM_WHITE) ;
  132.             }
  133.             flags[col] |= corner(vec)<<i ;
  134.          }
  135.       }
  136.       for (i = 0; i < scale; i++) {
  137.          bit *ptr = outrow ;
  138.          int zone = (i > ucutoff) - (i < cutoff) ;
  139.          int cut = (zone < 0) ? (cutoff - i) :
  140.                    (zone > 0) ? (i - ucutoff) : 0 ;
  141.  
  142.          for (col = 0; col < columns; col++) {
  143.             int pix = inrow[thisrow][col] ;
  144.             int flag = flags[col] ;
  145.             int cutl, cutr ;
  146.  
  147.             switch (zone) {
  148.             case -1:
  149.                switch (NW(flag)) {
  150.                case 0: cutl = 0; break;
  151.                case 1: cutl = cut; break;
  152.                case 2: cutl = cut ? cut-1 : 0; break;
  153.                case 3: cutl = (cut && cutoff > 1) ? cut-1 : cut; break;
  154.                }
  155.                switch (NE(flag)) {
  156.                case 0: cutr = 0; break;
  157.                case 1: cutr = cut; break;
  158.                case 2: cutr = cut ? cut-1 : 0; break;
  159.                case 3: cutr = (cut && cutoff > 1) ? cut-1 : cut; break;
  160.                }
  161.                break;
  162.             case 0:
  163.                cutl = cutr = 0;
  164.                break ;
  165.             case 1:
  166.                switch (SW(flag)) {
  167.                case 0: cutl = 0; break;
  168.                case 1: cutl = cut; break;
  169.                case 2: cutl = cut ? cut-1 : 0; break;
  170.                case 3: cutl = (cut && cutoff > 1) ? cut-1 : cut; break;
  171.                }
  172.                switch (SE(flag)) {
  173.                case 0: cutr = 0; break;
  174.                case 1: cutr = cut; break;
  175.                case 2: cutr = cut ? cut-1 : 0; break;
  176.                case 3: cutr = (cut && cutoff > 1) ? cut-1 : cut; break;
  177.                }
  178.                break;
  179.             }
  180.             for (k = 0; k < cutl; k++) /* left part */
  181.                *ptr++ = !pix ;
  182.             for (k = 0; k < scale-cutl-cutr; k++)  /* centre part */
  183.                *ptr++ = pix ;
  184.             for (k = 0; k < cutr; k++) /* right part */
  185.                *ptr++ = !pix ;
  186.          }
  187.          pbm_writepbmrow(stdout, outrow, scale*columns, 0) ;
  188.       }
  189.    }
  190.    pm_close(ifd);
  191.    exit(0);
  192. }
  193.