home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Resource Library: Graphics
/
graphics-16000.iso
/
general
/
convrtrs
/
pbmplus
/
ntpbmsrc.lha
/
netpbm
/
pnm
/
pnmscale.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-11-29
|
12KB
|
465 lines
/* 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 );
}