/* pnmquadrilateral.c - quadrilateral transformation of a portable anymap ** ** Copyright (C) 1989, 2009 by Jef Poskanzer. ** ** Permission to use, copy, modify, and distribute this software and its ** documentation for any purpose and without fee is hereby granted, provided ** that the above copyright notice appear in all copies and that both that ** copyright notice and this permission notice appear in supporting ** documentation. This software is provided "as is" without express or ** implied warranty. */ #include "pnm.h" int main( int argc, char** argv ) { FILE* ifp; int argn, supersamplesize, x1, y1, x2, y2, x3, y3, x4, y4; int rows, cols, format, newformat; xelval maxval; xel** xels; xel** newsubxels; xel** newxels; xel black_xel, x; int row, col, subrow, subcol, newrow, newcol, supersamples; double rowfrac, colfrac; double xl, yl, xr, yr; int r, g, b; char* usage = "[-supersamplesize ] x1 y1 x2 y2 x3 y3 x4 y4 [pnmfile]"; pnm_init( &argc, argv ); argn = 1; supersamplesize = 3; while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] >= 'a' && argv[argn][1] <= 'z' ) { if ( pm_keymatch( argv[argn], "-supersamplesize", 2 ) ) { ++argn; if ( argn == argc || sscanf( argv[argn], "%d", &supersamplesize ) != 1 ) pm_usage( usage ); if ( supersamplesize <= 0 ) pm_error( "supersamplesize must be greater than 0" ); } else pm_usage( usage ); ++argn; } if ( argn + 8 > argc ) pm_usage( usage ); if ( sscanf( argv[argn], "%d", &x1 ) != 1 ) pm_usage( usage ); if ( sscanf( argv[argn+1], "%d", &y1 ) != 1 ) pm_usage( usage ); if ( sscanf( argv[argn+2], "%d", &x2 ) != 1 ) pm_usage( usage ); if ( sscanf( argv[argn+3], "%d", &y2 ) != 1 ) pm_usage( usage ); if ( sscanf( argv[argn+4], "%d", &x3 ) != 1 ) pm_usage( usage ); if ( sscanf( argv[argn+5], "%d", &y3 ) != 1 ) pm_usage( usage ); if ( sscanf( argv[argn+6], "%d", &x4 ) != 1 ) pm_usage( usage ); if ( sscanf( argv[argn+7], "%d", &y4 ) != 1 ) pm_usage( usage ); argn += 8; /* Now get input file. */ if ( argn != argc ) { ifp = pm_openr( argv[argn] ); ++argn; } else ifp = stdin; if ( argn != argc ) pm_usage( usage ); pnm_pbmmaxval = PNM_MAXMAXVAL; /* use larger value for better results */ xels = pnm_readpnm( ifp, &cols, &rows, &maxval, &format ); /* Promote PBM files to PGM. */ if ( PNM_FORMAT_TYPE(format) == PBM_TYPE ) { newformat = PGM_TYPE; pm_message( "promoting from PBM to PGM" ); } else newformat = format; newsubxels = pnm_allocarray( cols * supersamplesize, rows * supersamplesize ); /* Set the background to black. */ if ( PNM_FORMAT_TYPE(newformat) == PPM_TYPE ) PPM_ASSIGN( black_xel, 0, 0, 0 ); else PNM_ASSIGN1( black_xel, 0 ); for ( newrow = 0; newrow < rows * supersamplesize; ++newrow ) for ( newcol = 0; newcol < cols * supersamplesize; ++newcol ) newsubxels[newrow][newcol] = black_xel; /* Transform the image, with supersampling. */ for ( row = 0; row < rows; ++row ) for ( subrow = 0; subrow < supersamplesize; ++subrow ) { rowfrac = (double) ( row * supersamplesize + subrow ) / ( rows * supersamplesize ); xl = ( x1 + rowfrac * ( x3 - x1 ) ) * supersamplesize; yl = ( y1 + rowfrac * ( y3 - y1 ) ) * supersamplesize; xr = ( x2 + rowfrac * ( x4 - x2 ) ) * supersamplesize; yr = ( y2 + rowfrac * ( y4 - y2 ) ) * supersamplesize; for ( col = 0; col < cols; ++col ) for ( subcol = 0; subcol < supersamplesize; ++subcol ) { colfrac = (double) ( col * supersamplesize + subcol ) / ( cols * supersamplesize ); newcol = ( xl + colfrac * ( xr - xl ) ) + 0.5; newrow = ( yl + colfrac * ( yr - yl ) ) + 0.5; if ( newcol >= 0 && newcol < cols * supersamplesize && newrow >= 0 && newrow < rows * supersamplesize ) newsubxels[newrow][newcol] = xels[row][col]; } } /* Average the supersampled image down to output size. */ supersamples = supersamplesize * supersamplesize; newxels = pnm_allocarray( cols, rows ); for ( row = 0; row < rows; ++row ) for ( col = 0; col < cols; ++col ) { r = g = b = 0; for ( subrow = 0; subrow < supersamplesize; ++subrow ) for ( subcol = 0; subcol < supersamplesize; ++subcol ) { x = newsubxels[row * supersamplesize + subrow][col * supersamplesize + subcol]; switch ( PNM_FORMAT_TYPE(format) ) { case PPM_TYPE: r += PPM_GETR( x ); g += PPM_GETG( x ); b += PPM_GETB( x ); break; default: g += PNM_GET1( x ); break; } } switch ( PNM_FORMAT_TYPE(format) ) { case PPM_TYPE: r = r / supersamples; g = g / supersamples; b = b / supersamples; PPM_ASSIGN( newxels[row][col], r, g, b ); break; default: g = g / supersamples; PNM_ASSIGN1( newxels[row][col], g ); break; } } pnm_writepnm( stdout, newxels, cols, rows, maxval, newformat, 0 ); pm_closer( ifp ); pm_closew( stdout ); exit( 0 ); }