home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 309.lha / PBM_PLUS / ppm / ppmscale.c < prev    next >
C/C++ Source or Header  |  1980-12-04  |  8KB  |  327 lines

  1. /* ppmscale.c - read a portable pixmap and scale it
  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. #else    SYSV
  17. #include <strings.h>
  18. #endif    SYSV
  19. #include "ppm.h"
  20.  
  21. #define SCALE 4096
  22. #define HALFSCALE 2048
  23.  
  24. #define max(a,b) ((a) > (b) ? (a) : (b))
  25.  
  26. main( argc, argv )
  27. int argc;
  28. char *argv[];
  29.     {
  30.     FILE *ifd;
  31.     pixel **pixels, **temppixels, *newpixelrow;
  32.     register pixel *pP, *npP;
  33.     int argn, specxscale, specyscale, specxsize, specysize;
  34.     int rows, cols, newrows, newcols;
  35.     register int row, col, newrow, neednew;
  36.     pixval maxval;
  37.     float xscale, yscale;
  38.     long sxscale, syscale;
  39.     register long fractofill, fracleft;
  40.     char *usage = "<s> [ppmfile]\n            -xsize|width|-ysize|-height <s> [ppmfile]\n            -xscale|-yscale <s> [ppmfile]\n            -xscale|-xsize|-width <s> -yscale|-ysize|-height <s> [ppmfile]";
  41.  
  42.     pm_progname = argv[0];
  43.  
  44.     argn = 1;
  45.     specxscale = specyscale = specxsize = specysize = 0;
  46.  
  47.     while ( argn + 1 < argc && argv[argn][0] == '-' )
  48.     {
  49.     if ( strncmp(argv[argn],"-xscale",max(strlen(argv[argn]),4)) == 0 )
  50.         {
  51.         if ( specxsize )
  52.         pm_error(
  53.             "only one of -xsize/-width and -xscale may be specified",
  54.             0,0,0,0,0 );
  55.         if ( sscanf( argv[argn+1], "%g", &xscale ) != 1 )
  56.         pm_usage( usage );
  57.         if ( xscale <= 0.0 )
  58.         pm_error( "x scale must be greater than 0", 0,0,0,0,0 );
  59.         specxscale = 1;
  60.         }
  61.     else if ( strncmp(argv[argn],"-yscale",max(strlen(argv[argn]),4)) == 0 )
  62.         {
  63.         if ( specysize )
  64.         pm_error(
  65.             "only one of -ysize/-height and -yscale may be specified",
  66.             0,0,0,0,0 );
  67.         if ( sscanf( argv[argn+1], "%g", &yscale ) != 1 )
  68.         pm_usage( usage );
  69.         if ( yscale <= 0.0 )
  70.         pm_error( "y scale must be greater than 0", 0,0,0,0,0 );
  71.         specyscale = 1;
  72.         }
  73.     else if ( strncmp(argv[argn],"-xsize",max(strlen(argv[argn]),4)) == 0 ||
  74.               strncmp(argv[argn],"-width",max(strlen(argv[argn]),2)) == 0 )
  75.         {
  76.         if ( specxscale )
  77.         pm_error(
  78.             "only one of -xscale and -xsize/-width may be specified",
  79.             0,0,0,0,0 );
  80.         if ( sscanf( argv[argn+1], "%d", &newcols ) != 1 )
  81.         pm_usage( usage );
  82.         if ( newcols <= 0 )
  83.         pm_error( "new width must be greater than 0", 0,0,0,0,0 );
  84.         specxsize = 1;
  85.         }
  86.     else if ( strncmp(argv[argn],"-ysize",max(strlen(argv[argn]),4)) == 0 ||
  87.               strncmp(argv[argn],"-height",max(strlen(argv[argn]),2)) == 0 )
  88.         {
  89.         if ( specyscale )
  90.         pm_error(
  91.             "only one of -yscale and -ysize/-height may be specified",
  92.             0,0,0,0,0 );
  93.         if ( sscanf( argv[argn+1], "%d", &newrows ) != 1 )
  94.         pm_usage( usage );
  95.         if ( newrows <= 0 )
  96.         pm_error( "new height must be greater than 0", 0,0,0,0,0 );
  97.         specysize = 1;
  98.         }
  99.     else
  100.         pm_usage( usage );
  101.     argn += 2;
  102.     }
  103.  
  104.     if ( ! ( specxscale || specyscale || specxsize || specysize ) )
  105.     {
  106.     /* No flags specified, so a single scale factor is required. */
  107.     if ( argn == argc )
  108.         pm_usage( usage );
  109.     if ( sscanf( argv[argn], "%g", &xscale ) != 1 )
  110.         pm_usage( usage );
  111.     if ( xscale <= 0.0 )
  112.         pm_error( "scale must be greater than 0", 0,0,0,0,0 );
  113.     argn++;
  114.     yscale = xscale;
  115.     specxscale = specyscale = 1;
  116.     }
  117.  
  118.     /* Now get input file. */
  119.     if ( argn != argc )
  120.     {
  121.     ifd = pm_openr( argv[argn] );
  122.     argn++;
  123.     }
  124.     else
  125.     ifd = stdin;
  126.  
  127.     if ( argn != argc )
  128.     pm_usage( usage );
  129.  
  130.     ppm_pbmmaxval = 255;    /* use larger value for better results */
  131.     pixels = ppm_readppm( ifd, &cols, &rows, &maxval );
  132.  
  133.     pm_close( ifd );
  134.  
  135.     /* Compute all sizes and scales. */
  136.     if ( specxsize )
  137.     xscale = (float) newcols / (float) cols;
  138.     else if ( specxscale )
  139.     newcols = cols * xscale + 0.999;
  140.  
  141.     if ( specysize )
  142.     yscale = (float) newrows / (float) rows;
  143.     else if ( specyscale )
  144.     newrows = rows * yscale + 0.999;
  145.     else
  146.     if ( specxsize )
  147.         {
  148.         yscale = xscale;
  149.         newrows = rows * yscale + 0.999;
  150.         }
  151.     else
  152.         {
  153.         yscale = 1.0;
  154.         newrows = rows;
  155.         }
  156.     
  157.     if ( ! ( specxsize || specxscale ) )
  158.     if ( specysize )
  159.         {
  160.         xscale = yscale;
  161.         newcols = cols * xscale + 0.999;
  162.         }
  163.     else
  164.         {
  165.         xscale = 1.0;
  166.         newcols = cols;
  167.         }
  168.  
  169.     sxscale = xscale * SCALE;
  170.     syscale = yscale * SCALE;
  171.  
  172.     /* First scale Y from pixels into temppixels. */
  173.     if ( newrows == rows )    /* shortcut Y scaling if possible */
  174.     temppixels = pixels;
  175.     else
  176.     {
  177.     temppixels = ppm_allocarray( cols, newrows );
  178.     for ( col = 0; col < cols; col++ )
  179.         {
  180.         register long r, g, b;
  181.  
  182.         newrow = 0;
  183.         npP = &(temppixels[newrow][col]);
  184.         fractofill = SCALE;
  185.         r = g = b = HALFSCALE;
  186.         neednew = 0;
  187.         for ( row = 0; row < rows; row++ )
  188.         {
  189.         pP = &(pixels[row][col]);
  190.         fracleft = syscale;
  191.         while ( fracleft >= fractofill )
  192.             {
  193.             if ( neednew )
  194.             {
  195.             newrow++;
  196.             npP = &(temppixels[newrow][col]);
  197.             r = g = b = HALFSCALE;
  198.             neednew = 0;
  199.             }
  200.             r += fractofill * PPM_GETR( *pP );
  201.             g += fractofill * PPM_GETG( *pP );
  202.             b += fractofill * PPM_GETB( *pP );
  203.             r /= SCALE;
  204.             g /= SCALE;
  205.             b /= SCALE;
  206.             if ( r > maxval ) r = maxval;
  207.             if ( g > maxval ) g = maxval;
  208.             if ( b > maxval ) b = maxval;
  209.             PPM_ASSIGN( *npP, r, g, b );
  210.             fracleft -= fractofill;
  211.             fractofill = SCALE;
  212.             neednew = 1;
  213.             }
  214.         if ( fracleft > 0 )
  215.             {
  216.             if ( neednew )
  217.             {
  218.             newrow++;
  219.             npP = &(temppixels[newrow][col]);
  220.             r = g = b = HALFSCALE;
  221.             neednew = 0;
  222.             }
  223.             r += fracleft * PPM_GETR( *pP );
  224.             g += fracleft * PPM_GETG( *pP );
  225.             b += fracleft * PPM_GETB( *pP );
  226.             fractofill -= fracleft;
  227.             }
  228.         }
  229.         if ( fractofill > 0 )
  230.         {
  231.         pP = &(pixels[rows-1][col]);
  232.         r += fractofill * PPM_GETR( *pP );
  233.         g += fractofill * PPM_GETG( *pP );
  234.         b += fractofill * PPM_GETB( *pP );
  235.         }
  236.         if ( ! neednew )
  237.         {
  238.         r /= SCALE;
  239.         g /= SCALE;
  240.         b /= SCALE;
  241.         if ( r > maxval ) r = maxval;
  242.         if ( g > maxval ) g = maxval;
  243.         if ( b > maxval ) b = maxval;
  244.         PPM_ASSIGN( *npP, r, g, b );
  245.         }
  246.         }
  247.     ppm_freearray( pixels, rows );
  248.     }
  249.  
  250.     /* Now scale X and write it out. */
  251.     if ( newcols == cols )    /* shortcut X scaling if possible */
  252.     ppm_writeppm( stdout, temppixels, newcols, newrows, maxval );
  253.     else
  254.     {
  255.     ppm_writeppminit( stdout, newcols, newrows, maxval );
  256.     newpixelrow = ppm_allocrow( newcols );
  257.     for ( row = 0; row < newrows; row++ )
  258.         {
  259.         register long r, g, b;
  260.  
  261.         npP = newpixelrow;
  262.         fractofill = SCALE;
  263.         r = g = b = HALFSCALE;
  264.         neednew = 0;
  265.         for ( col = 0, pP = temppixels[row]; col < cols; col++, pP++ )
  266.         {
  267.         fracleft = sxscale;
  268.         while ( fracleft >= fractofill )
  269.             {
  270.             if ( neednew )
  271.             {
  272.             npP++;
  273.             r = g = b = HALFSCALE;
  274.             neednew = 0;
  275.             }
  276.             r += fractofill * PPM_GETR( *pP );
  277.             g += fractofill * PPM_GETG( *pP );
  278.             b += fractofill * PPM_GETB( *pP );
  279.             r /= SCALE;
  280.             g /= SCALE;
  281.             b /= SCALE;
  282.             if ( r > maxval ) r = maxval;
  283.             if ( g > maxval ) g = maxval;
  284.             if ( b > maxval ) b = maxval;
  285.             PPM_ASSIGN( *npP, r, g, b );
  286.             fracleft -= fractofill;
  287.             fractofill = SCALE;
  288.             neednew = 1;
  289.             }
  290.         if ( fracleft > 0 )
  291.             {
  292.             if ( neednew )
  293.             {
  294.             npP++;
  295.             r = g = b = HALFSCALE;
  296.             neednew = 0;
  297.             }
  298.             r += fracleft * PPM_GETR( *pP );
  299.             g += fracleft * PPM_GETG( *pP );
  300.             b += fracleft * PPM_GETB( *pP );
  301.             fractofill -= fracleft;
  302.             }
  303.         }
  304.         if ( fractofill > 0 )
  305.         {
  306.         pP--;
  307.         r += fractofill * PPM_GETR( *pP );
  308.         g += fractofill * PPM_GETG( *pP );
  309.         b += fractofill * PPM_GETB( *pP );
  310.         }
  311.         if ( ! neednew )
  312.         {
  313.         r /= SCALE;
  314.         g /= SCALE;
  315.         b /= SCALE;
  316.         if ( r > maxval ) r = maxval;
  317.         if ( g > maxval ) g = maxval;
  318.         if ( b > maxval ) b = maxval;
  319.         PPM_ASSIGN( *npP, r, g, b );
  320.         }
  321.         ppm_writeppmrow( stdout, newpixelrow, newcols, maxval );
  322.         }
  323.     }
  324.  
  325.     exit( 0 );
  326.     }
  327.