This is pnmscale.c in view mode; [Download] [Up]
/* pnmscale.c - read a portable anymap and scale it ** ** Copyright (C) 1989, 1991 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 <math.h> #include "pnm.h" #define SCALE 4096 #define HALFSCALE 2048 int main( argc, argv ) int argc; char* argv[]; { FILE* ifp; xel* xelrow; xel* tempxelrow; xel* newxelrow; register xel* xP; register xel* nxP; int argn, specxscale, specyscale, specxsize, specysize, specxysize; int rows, cols, format, newformat, rowsread, newrows, newcols, newpixels; register int row, col, needtoreadrow; xelval maxval; float xscale, yscale; long sxscale, syscale; register long fracrowtofill, fracrowleft; long* rs; long* gs; long* bs; char* usage = "<s> [pnmfile]\n \ -xsize|width|-ysize|-height <s> [pnmfile]\n \ -xscale|-yscale <s> [pnmfile]\n \ -xscale|-xsize|-width <s> -yscale|-ysize|-height <s> [pnmfile]\n \ -xysize <x> <y> [pnmfile]\n \ -pixels <n> [pnmfile]"; pnm_init( &argc, argv ); argn = 1; specxscale = specyscale = specxsize = specysize = specxysize = newpixels = 0; while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) { if ( pm_keymatch( argv[argn], "-xscale", 4 ) ) { if ( specxscale ) pm_error( "already specified an x scale" ); if ( specxsize ) pm_error( "only one of -xsize/-width and -xscale may be specified" ); ++argn; if ( argn == argc || sscanf( argv[argn], "%f", &xscale ) != 1 ) pm_usage( usage ); if ( xscale <= 0.0 ) pm_error( "x scale must be greater than 0" ); specxscale = 1; } else if ( pm_keymatch( argv[argn], "-yscale", 4 ) ) { if ( specyscale ) pm_error( "already specified a y scale" ); if ( specysize ) pm_error( "only one of -ysize/-height and -yscale may be specified" ); ++argn; if ( argn == argc || sscanf( argv[argn], "%f", &yscale ) != 1 ) pm_usage( usage ); if ( yscale <= 0.0 ) pm_error( "y scale must be greater than 0" ); specyscale = 1; } else if ( pm_keymatch( argv[argn], "-xsize", 4 ) || pm_keymatch( argv[argn], "-width", 2 ) ) { if ( specxsize ) pm_error( "already specified a width" ); if ( specxscale ) pm_error( "only one of -xscale and -xsize/-width may be specified" ); ++argn; if ( argn == argc || sscanf( argv[argn], "%d", &newcols ) != 1 ) pm_usage( usage ); if ( newcols <= 0 ) pm_error( "new width must be greater than 0" ); specxsize = 1; } else if ( pm_keymatch( argv[argn], "-ysize", 4 ) || pm_keymatch( argv[argn], "-height", 2 ) ) { if ( specysize ) pm_error( "already specified a height" ); if ( specyscale ) pm_error( "only one of -yscale and -ysize/-height may be specified" ); ++argn; if ( argn == argc || sscanf( argv[argn], "%d", &newrows ) != 1 ) pm_usage( usage ); if ( newrows <= 0 ) pm_error( "new height must be greater than 0" ); specysize = 1; } else if ( pm_keymatch( argv[argn], "-xysize", 3 ) ) { if ( specxsize || specysize || specxscale || specyscale || newpixels ) pm_error( "can't use -xysize with any other specifiers" ); ++argn; if ( argn == argc || sscanf( argv[argn], "%d", &newcols ) != 1 ) pm_usage( usage ); ++argn; if ( argn == argc || sscanf( argv[argn], "%d", &newrows ) != 1 ) pm_usage( usage ); if ( newcols <= 0 || newrows <= 0 ) pm_error( "new width and height must be greater than 0" ); specxsize = 1; specysize = 1; specxysize = 1; } else if ( pm_keymatch( argv[argn], "-pixels", 2 ) ) { if ( specxsize || specysize || specxscale || specyscale ) pm_error( "can't use -pixels with any other specifiers" ); ++argn; if ( argn == argc || sscanf( argv[argn], "%d", &newpixels ) != 1 ) pm_usage( usage ); if ( newpixels <= 0 ) pm_error( "number of pixels must be greater than 0" ); } else pm_usage( usage ); ++argn; } if ( ! ( specxscale || specyscale || specxsize || specysize || newpixels ) ) { /* No flags specified, so a single scale factor is required. */ if ( argn == argc ) pm_usage( usage ); if ( sscanf( argv[argn], "%f", &xscale ) != 1 ) pm_usage( usage ); if ( xscale <= 0.0 ) pm_error( "scale must be greater than 0" ); ++argn; yscale = xscale; specxscale = specyscale = 1; } /* 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 */ pnm_readpnminit( 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; /* Compute all sizes and scales. */ if ( newpixels ) if ( rows * cols <= newpixels ) { newrows = rows; newcols = cols; xscale = yscale = 1.0; } else { xscale = yscale = sqrt( (float) newpixels / (float) cols / (float) rows ); specxscale = specyscale = 1; } if ( specxysize ) if ( (float) newcols / (float) newrows > (float) cols / (float) rows ) specxsize = 0; else specysize = 0; if ( specxsize ) xscale = (float) newcols / (float) cols; else if ( specxscale ) newcols = cols * xscale + 0.999; if ( specysize ) yscale = (float) newrows / (float) rows; else if ( specyscale ) newrows = rows * yscale + 0.999; else if ( specxsize ) { yscale = xscale; newrows = rows * yscale + 0.999; } else { yscale = 1.0; newrows = rows; } if ( ! ( specxsize || specxscale ) ) if ( specysize ) { xscale = yscale; newcols = cols * xscale + 0.999; } else { xscale = 1.0; newcols = cols; } sxscale = xscale * SCALE; syscale = yscale * SCALE; xelrow = pnm_allocrow( cols ); if ( newrows == rows ) /* shortcut Y scaling if possible */ tempxelrow = xelrow; else tempxelrow = pnm_allocrow( cols ); rs = (long*) pm_allocrow( cols, sizeof(long) ); gs = (long*) pm_allocrow( cols, sizeof(long) ); bs = (long*) pm_allocrow( cols, sizeof(long) ); rowsread = 0; fracrowleft = syscale; needtoreadrow = 1; for ( col = 0; col < cols; ++col ) rs[col] = gs[col] = bs[col] = HALFSCALE; fracrowtofill = SCALE; pnm_writepnminit( stdout, newcols, newrows, maxval, newformat, 0 ); newxelrow = pnm_allocrow( newcols ); for ( row = 0; row < newrows; ++row ) { /* First scale Y from xelrow into tempxelrow. */ if ( newrows == rows ) /* shortcut Y scaling if possible */ { pnm_readpnmrow( ifp, xelrow, cols, maxval, format ); } else { while ( fracrowleft < fracrowtofill ) { if ( needtoreadrow ) if ( rowsread < rows ) { pnm_readpnmrow( ifp, xelrow, cols, maxval, format ); ++rowsread; /* needtoreadrow = 0; */ } switch ( PNM_FORMAT_TYPE(format) ) { case PPM_TYPE: for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) { rs[col] += fracrowleft * PPM_GETR( *xP ); gs[col] += fracrowleft * PPM_GETG( *xP ); bs[col] += fracrowleft * PPM_GETB( *xP ); } break; default: for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) gs[col] += fracrowleft * PNM_GET1( *xP ); break; } fracrowtofill -= fracrowleft; fracrowleft = syscale; needtoreadrow = 1; } /* Now fracrowleft is >= fracrowtofill, so we can produce a row. */ if ( needtoreadrow ) if ( rowsread < rows ) { pnm_readpnmrow( ifp, xelrow, cols, maxval, format ); ++rowsread; needtoreadrow = 0; } switch ( PNM_FORMAT_TYPE(format) ) { case PPM_TYPE: for ( col = 0, xP = xelrow, nxP = tempxelrow; col < cols; ++col, ++xP, ++nxP ) { register long r, g, b; r = rs[col] + fracrowtofill * PPM_GETR( *xP ); g = gs[col] + fracrowtofill * PPM_GETG( *xP ); b = bs[col] + fracrowtofill * PPM_GETB( *xP ); r /= SCALE; if ( r > maxval ) r = maxval; g /= SCALE; if ( g > maxval ) g = maxval; b /= SCALE; if ( b > maxval ) b = maxval; PPM_ASSIGN( *nxP, r, g, b ); rs[col] = gs[col] = bs[col] = HALFSCALE; } break; default: for ( col = 0, xP = xelrow, nxP = tempxelrow; col < cols; ++col, ++xP, ++nxP ) { register long g; g = gs[col] + fracrowtofill * PNM_GET1( *xP ); g /= SCALE; if ( g > maxval ) g = maxval; PNM_ASSIGN1( *nxP, g ); gs[col] = HALFSCALE; } break; } fracrowleft -= fracrowtofill; if ( fracrowleft == 0 ) { fracrowleft = syscale; needtoreadrow = 1; } fracrowtofill = SCALE; } /* Now scale X from tempxelrow into newxelrow and write it out. */ if ( newcols == cols ) /* shortcut X scaling if possible */ pnm_writepnmrow( stdout, tempxelrow, newcols, maxval, newformat, 0 ); else { register long r, g, b; register long fraccoltofill, fraccolleft; register int needcol; nxP = newxelrow; fraccoltofill = SCALE; r = g = b = HALFSCALE; needcol = 0; for ( col = 0, xP = tempxelrow; col < cols; ++col, ++xP ) { fraccolleft = sxscale; while ( fraccolleft >= fraccoltofill ) { if ( needcol ) { ++nxP; r = g = b = HALFSCALE; } switch ( PNM_FORMAT_TYPE(format) ) { case PPM_TYPE: r += fraccoltofill * PPM_GETR( *xP ); g += fraccoltofill * PPM_GETG( *xP ); b += fraccoltofill * PPM_GETB( *xP ); r /= SCALE; if ( r > maxval ) r = maxval; g /= SCALE; if ( g > maxval ) g = maxval; b /= SCALE; if ( b > maxval ) b = maxval; PPM_ASSIGN( *nxP, r, g, b ); break; default: g += fraccoltofill * PNM_GET1( *xP ); g /= SCALE; if ( g > maxval ) g = maxval; PNM_ASSIGN1( *nxP, g ); break; } fraccolleft -= fraccoltofill; fraccoltofill = SCALE; needcol = 1; } if ( fraccolleft > 0 ) { if ( needcol ) { ++nxP; r = g = b = HALFSCALE; needcol = 0; } switch ( PNM_FORMAT_TYPE(format) ) { case PPM_TYPE: r += fraccolleft * PPM_GETR( *xP ); g += fraccolleft * PPM_GETG( *xP ); b += fraccolleft * PPM_GETB( *xP ); break; default: g += fraccolleft * PNM_GET1( *xP ); break; } fraccoltofill -= fraccolleft; } } if ( fraccoltofill > 0 ) { --xP; switch ( PNM_FORMAT_TYPE(format) ) { case PPM_TYPE: r += fraccoltofill * PPM_GETR( *xP ); g += fraccoltofill * PPM_GETG( *xP ); b += fraccoltofill * PPM_GETB( *xP ); break; default: g += fraccoltofill * PNM_GET1( *xP ); break; } } if ( ! needcol ) { switch ( PNM_FORMAT_TYPE(format) ) { case PPM_TYPE: r /= SCALE; if ( r > maxval ) r = maxval; g /= SCALE; if ( g > maxval ) g = maxval; b /= SCALE; if ( b > maxval ) b = maxval; PPM_ASSIGN( *nxP, r, g, b ); break; default: g /= SCALE; if ( g > maxval ) g = maxval; PNM_ASSIGN1( *nxP, g ); break; } } pnm_writepnmrow( stdout, newxelrow, newcols, maxval, newformat, 0 ); } } pm_close( ifp ); pm_close( stdout ); exit( 0 ); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.