home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / NETWORK / netpbm_src.lzh / NETPBM / PNM / pnmrotate.c < prev    next >
C/C++ Source or Header  |  1996-11-18  |  10KB  |  333 lines

  1. /* pnmrotate.c - read a portable anymap and rotate it by some angle
  2. **
  3. ** Copyright (C) 1989, 1991 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 <math.h>
  14. #include "pnm.h"
  15. #ifndef M_PI
  16. #define M_PI    3.14159265358979323846
  17. #endif /*M_PI*/
  18.  
  19. #define SCALE 4096
  20. #define HALFSCALE 2048
  21.  
  22. int
  23. main( argc, argv )
  24.     int argc;
  25.     char* argv[];
  26.     {
  27.     FILE* ifp;
  28.     xel* xelrow;
  29.     xel** temp1xels;
  30.     xel** temp2xels;
  31.     xel* newxelrow;
  32.     register xel* xP;
  33.     register xel* nxP;
  34.     xel bgxel, prevxel, x;
  35.     int argn, rows, cols, format, newformat, newrows;
  36.     int tempcols, newcols, yshearjunk, x2shearjunk, row, col, new;
  37.     xelval maxval;
  38.     int antialias;
  39.     float fangle, xshearfac, yshearfac, new0;
  40.     int intnew0;
  41.     register long fracnew0, omfracnew0;
  42.     char* usage = "[-noantialias] <angle> [pnmfile]";
  43.  
  44.     pnm_init( &argc, argv );
  45.  
  46.     argn = 1;
  47.     antialias = 1;
  48.  
  49.     if ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' &&
  50.      ( argv[argn][1] < '0' || argv[argn][1] > '9' ) )
  51.         {
  52.         if ( pm_keymatch( argv[argn], "-antialias", 2 ) )
  53.             antialias = 1;
  54.         else if ( pm_keymatch( argv[argn], "-noantialias", 2 ) )
  55.             antialias = 0;
  56.         else
  57.             pm_usage( usage );
  58.         ++argn;
  59.         }
  60.  
  61.     if ( argn == argc )
  62.     pm_usage( usage );
  63.     if ( sscanf( argv[argn], "%f", &fangle ) != 1 )
  64.     pm_usage( usage );
  65.     ++argn;
  66.     if ( fangle < -90.0 || fangle > 90.0 )
  67.     pm_error( "angle must be between -90 and 90" );
  68.     fangle = fangle * M_PI / 180.0;    /* convert to radians */
  69.  
  70.     xshearfac = tan( fangle / 2.0 );
  71.     if ( xshearfac < 0.0 )
  72.     xshearfac = -xshearfac;
  73.     yshearfac = sin( fangle );
  74.     if ( yshearfac < 0.0 )
  75.     yshearfac = -yshearfac;
  76.  
  77.     if ( argn != argc )
  78.     {
  79.     ifp = pm_openr( argv[argn] );
  80.     ++argn;
  81.     }
  82.     else
  83.     ifp = stdin;
  84.  
  85.     if ( argn != argc )
  86.     pm_usage( usage );
  87.  
  88.     pnm_pbmmaxval = PNM_MAXMAXVAL;  /* use larger value for better results */
  89.     pnm_readpnminit( ifp, &cols, &rows, &maxval, &format );
  90.     xelrow = pnm_allocrow( cols );
  91.  
  92.     /* Promote PBM files to PGM. */
  93.     if ( antialias && PNM_FORMAT_TYPE(format) == PBM_TYPE )
  94.     {
  95.         newformat = PGM_TYPE;
  96.     pm_message( "promoting from PBM to PGM - use -noantialias to avoid this" );
  97.     }
  98.     else
  99.         newformat = format;
  100.  
  101.     tempcols = rows * xshearfac + cols + 0.999999;
  102.     yshearjunk = ( tempcols - cols ) * yshearfac;
  103.     newrows = tempcols * yshearfac + rows + 0.999999;
  104.     x2shearjunk = ( newrows - rows - yshearjunk ) * xshearfac;
  105.     newrows -= 2 * yshearjunk;
  106.     newcols = newrows * xshearfac + tempcols + 0.999999 - 2 * x2shearjunk;
  107.  
  108.     bgxel = pnm_backgroundxelrow( xelrow, cols, maxval, format );
  109.  
  110.     /* First shear X into temp1xels. */
  111.     temp1xels = pnm_allocarray( tempcols, rows );
  112.     for ( row = 0; row < rows; ++row )
  113.     {
  114.     pnm_readpnmrow( ifp, xelrow, cols, maxval, format );
  115.     if ( fangle > 0 )
  116.         new0 = row * xshearfac;
  117.     else
  118.         new0 = ( rows - row ) * xshearfac;
  119.     intnew0 = (int) new0;
  120.  
  121.     if ( antialias )
  122.         {
  123.         fracnew0 = ( new0 - intnew0 ) * SCALE;
  124.         omfracnew0 = SCALE - fracnew0;
  125.  
  126.         for ( col = 0, nxP = temp1xels[row]; col < tempcols; ++col, ++nxP )
  127.         *nxP = bgxel;
  128.  
  129.         prevxel = bgxel;
  130.         for ( col = 0, nxP = &(temp1xels[row][intnew0]), xP = xelrow;
  131.           col < cols; ++col, ++nxP, ++xP )
  132.         {
  133.                 switch ( PNM_FORMAT_TYPE(format) )
  134.                     {
  135.                     case PPM_TYPE:
  136.             PPM_ASSIGN( *nxP,
  137.             ( fracnew0 * PPM_GETR(prevxel) + omfracnew0 * PPM_GETR(*xP) + HALFSCALE ) / SCALE,
  138.             ( fracnew0 * PPM_GETG(prevxel) + omfracnew0 * PPM_GETG(*xP) + HALFSCALE ) / SCALE,
  139.             ( fracnew0 * PPM_GETB(prevxel) + omfracnew0 * PPM_GETB(*xP) + HALFSCALE ) / SCALE );
  140.                     break;
  141.  
  142.                     default:
  143.             PNM_ASSIGN1( *nxP,
  144.             ( fracnew0 * PNM_GET1(prevxel) + omfracnew0 * PNM_GET1(*xP) + HALFSCALE ) / SCALE );
  145.                     break;
  146.                     }
  147.         prevxel = *xP;
  148.         }
  149.         if ( fracnew0 > 0 && intnew0 + cols < tempcols )
  150.         {
  151.                 switch ( PNM_FORMAT_TYPE(format) )
  152.                     {
  153.                     case PPM_TYPE:
  154.             PPM_ASSIGN( *nxP,
  155.             ( fracnew0 * PPM_GETR(prevxel) + omfracnew0 * PPM_GETR(bgxel) + HALFSCALE ) / SCALE,
  156.             ( fracnew0 * PPM_GETG(prevxel) + omfracnew0 * PPM_GETG(bgxel) + HALFSCALE ) / SCALE,
  157.             ( fracnew0 * PPM_GETB(prevxel) + omfracnew0 * PPM_GETB(bgxel) + HALFSCALE ) / SCALE );
  158.                     break;
  159.  
  160.                     default:
  161.                     PNM_ASSIGN1( *nxP,
  162.                         ( fracnew0 * PNM_GET1(prevxel) + omfracnew0 * PNM_GET1(bgxel) + HALFSCALE ) / SCALE );
  163.                     break;
  164.                     }
  165.         }
  166.         }
  167.     else
  168.         {
  169.         for ( col = 0, nxP = temp1xels[row]; col < intnew0; ++col, ++nxP )
  170.         *nxP = bgxel;
  171.         for ( col = 0, xP = xelrow; col < cols; ++col, ++nxP, ++xP )
  172.         *nxP = *xP;
  173.         for ( col = intnew0 + cols; col < tempcols; ++col, ++nxP )
  174.         *nxP = bgxel;
  175.         }
  176.     }
  177.     pm_close( ifp );
  178.     pnm_freerow( xelrow );
  179.  
  180.     /* Now inverse shear Y from temp1 into temp2. */
  181.     temp2xels = pnm_allocarray( tempcols, newrows );
  182.     for ( col = 0; col < tempcols; ++col )
  183.     {
  184.     if ( fangle > 0 )
  185.         new0 = ( tempcols - col ) * yshearfac;
  186.     else
  187.         new0 = col * yshearfac;
  188.     intnew0 = (int) new0;
  189.     fracnew0 = ( new0 - intnew0 ) * SCALE;
  190.     omfracnew0 = SCALE - fracnew0;
  191.     intnew0 -= yshearjunk;
  192.  
  193.     for ( row = 0; row < newrows; ++row )
  194.         temp2xels[row][col] = bgxel;
  195.  
  196.     if ( antialias )
  197.         {
  198.         prevxel = bgxel;
  199.         for ( row = 0; row < rows; ++row )
  200.         {
  201.         new = row + intnew0;
  202.         if ( new >= 0 && new < newrows )
  203.             {
  204.             nxP = &(temp2xels[new][col]);
  205.             x = temp1xels[row][col];
  206.             switch ( PNM_FORMAT_TYPE(format) )
  207.             {
  208.             case PPM_TYPE:
  209.             PPM_ASSIGN( *nxP,
  210.                 ( fracnew0 * PPM_GETR(prevxel) + omfracnew0 * PPM_GETR(x) + HALFSCALE ) / SCALE,
  211.                 ( fracnew0 * PPM_GETG(prevxel) + omfracnew0 * PPM_GETG(x) + HALFSCALE ) / SCALE,
  212.                 ( fracnew0 * PPM_GETB(prevxel) + omfracnew0 * PPM_GETB(x) + HALFSCALE ) / SCALE );
  213.             break;
  214.  
  215.             default:
  216.             PNM_ASSIGN1( *nxP,
  217.                 ( fracnew0 * PNM_GET1(prevxel) + omfracnew0 * PNM_GET1(x) + HALFSCALE ) / SCALE );
  218.             break;
  219.             }
  220.             prevxel = x;
  221.             }
  222.         }
  223.         if ( fracnew0 > 0 && intnew0 + rows < newrows )
  224.         {
  225.         nxP = &(temp2xels[intnew0 + rows][col]);
  226.                 switch ( PNM_FORMAT_TYPE(format) )
  227.                     {
  228.                     case PPM_TYPE:
  229.             PPM_ASSIGN( *nxP,
  230.             ( fracnew0 * PPM_GETR(prevxel) + omfracnew0 * PPM_GETR(bgxel) + HALFSCALE ) / SCALE,
  231.             ( fracnew0 * PPM_GETG(prevxel) + omfracnew0 * PPM_GETG(bgxel) + HALFSCALE ) / SCALE,
  232.             ( fracnew0 * PPM_GETB(prevxel) + omfracnew0 * PPM_GETB(bgxel) + HALFSCALE ) / SCALE );
  233.                     break;
  234.  
  235.                     default:
  236.             PNM_ASSIGN1( *nxP,
  237.             ( fracnew0 * PNM_GET1(prevxel) + omfracnew0 * PNM_GET1(bgxel) + HALFSCALE ) / SCALE );
  238.                     break;
  239.                     }
  240.         }
  241.         }
  242.     else
  243.         {
  244.         for ( row = 0; row < rows; ++row )
  245.         {
  246.         new = row + intnew0;
  247.         if ( new >= 0 && new < newrows )
  248.             temp2xels[new][col] = temp1xels[row][col];
  249.         }
  250.         }
  251.     }
  252.     pnm_freearray( temp1xels, rows );
  253.  
  254.     /* Finally, shear X from temp2 into newxelrow. */
  255.     pnm_writepnminit( stdout, newcols, newrows, maxval, newformat, 0 );
  256.     newxelrow = pnm_allocrow( newcols );
  257.     for ( row = 0; row < newrows; ++row )
  258.     {
  259.     if ( fangle > 0 )
  260.         new0 = row * xshearfac;
  261.     else
  262.         new0 = ( newrows - row ) * xshearfac;
  263.     intnew0 = (int) new0;
  264.     fracnew0 = ( new0 - intnew0 ) * SCALE;
  265.     omfracnew0 = SCALE - fracnew0;
  266.     intnew0 -= x2shearjunk;
  267.  
  268.     for ( col = 0, nxP = newxelrow; col < newcols; ++col, ++nxP )
  269.         *nxP = bgxel;
  270.  
  271.     if ( antialias )
  272.         {
  273.         prevxel = bgxel;
  274.         for ( col = 0, xP = temp2xels[row]; col < tempcols; ++col, ++xP )
  275.         {
  276.         new = intnew0 + col;
  277.         if ( new >= 0 && new < newcols )
  278.             {
  279.             nxP = &(newxelrow[new]);
  280.             switch ( PNM_FORMAT_TYPE(format) )
  281.             {
  282.             case PPM_TYPE:
  283.             PPM_ASSIGN( *nxP,
  284.                 ( fracnew0 * PPM_GETR(prevxel) + omfracnew0 * PPM_GETR(*xP) + HALFSCALE ) / SCALE,
  285.                 ( fracnew0 * PPM_GETG(prevxel) + omfracnew0 * PPM_GETG(*xP) + HALFSCALE ) / SCALE,
  286.                 ( fracnew0 * PPM_GETB(prevxel) + omfracnew0 * PPM_GETB(*xP) + HALFSCALE ) / SCALE );
  287.             break;
  288.  
  289.             default:
  290.             PNM_ASSIGN1( *nxP,
  291.                 ( fracnew0 * PNM_GET1(prevxel) + omfracnew0 * PNM_GET1(*xP) + HALFSCALE ) / SCALE );
  292.             break;
  293.             }
  294.             prevxel = *xP;
  295.             }
  296.         }
  297.         if ( fracnew0 > 0 && intnew0 + tempcols < newcols )
  298.         {
  299.         nxP = &(newxelrow[intnew0 + tempcols]);
  300.                 switch ( PNM_FORMAT_TYPE(format) )
  301.                     {
  302.                     case PPM_TYPE:
  303.             PPM_ASSIGN( *nxP,
  304.             ( fracnew0 * PPM_GETR(prevxel) + omfracnew0 * PPM_GETR(bgxel) + HALFSCALE ) / SCALE,
  305.             ( fracnew0 * PPM_GETG(prevxel) + omfracnew0 * PPM_GETG(bgxel) + HALFSCALE ) / SCALE,
  306.             ( fracnew0 * PPM_GETB(prevxel) + omfracnew0 * PPM_GETB(bgxel) + HALFSCALE ) / SCALE );
  307.                     break;
  308.  
  309.                     default:
  310.             PNM_ASSIGN1( *nxP,
  311.             ( fracnew0 * PNM_GET1(prevxel) + omfracnew0 * PNM_GET1(bgxel) + HALFSCALE ) / SCALE );
  312.                     break;
  313.                     }
  314.         }
  315.         }
  316.     else
  317.         {
  318.         for ( col = 0, xP = temp2xels[row]; col < tempcols; ++col, ++xP )
  319.         {
  320.         new = intnew0 + col;
  321.         if ( new >= 0 && new < newcols )
  322.             newxelrow[new] = *xP;
  323.         }
  324.         }
  325.  
  326.     pnm_writepnmrow( stdout, newxelrow, newcols, maxval, newformat, 0 );
  327.     }
  328.  
  329.     pm_close( stdout );
  330.  
  331.     exit( 0 );
  332.     }
  333.