// $Id: x20c.c 12095 2011-12-03 08:56:15Z andrewross $
//
// plimage demo
//
//
#include "plcdemos.h"
#include "plevent.h"
#include <math.h>
#define XDIM 260
#define YDIM 220
void save_plot( char * );
void gray_cmap( PLINT );
int read_img( const char *, PLFLT ***, int *, int *, int * );
int get_clip( PLFLT *, PLFLT *, PLFLT *, PLFLT * );
int dbg = 0;
int nosombrero = 0;
int nointeractive = 0;
char *f_name = NULL;
struct stretch_data
{
PLFLT xmin, xmax, ymin, ymax;
PLFLT stretch;
};
static PLOptionTable options[] = {
{
"dbg", // extra debugging plot
NULL,
NULL,
&dbg,
PL_OPT_BOOL,
"-dbg",
"Extra debugging plot"
},
{
"nosombrero", // Turns on test of xor function
NULL,
NULL,
&nosombrero,
PL_OPT_BOOL,
"-nosombrero",
"No sombrero plot"
},
{
"nointeractive", // Turns on test of xor function
NULL,
NULL,
&nointeractive,
PL_OPT_BOOL,
"-nointeractive",
"No interactive selection"
},
{
"save", // For saving in postscript
NULL,
NULL,
&f_name,
PL_OPT_STRING,
"-save filename",
"Save sombrero plot in color postscript `filename'"
},
{
NULL, // option
NULL, // handler
NULL, // client data
NULL, // address of variable to set
0, // mode flag
NULL, // short syntax
NULL
} // long syntax
};
// Transformation function
static void
mypltr( PLFLT x, PLFLT y, PLFLT *tx, PLFLT *ty, PLPointer pltr_data )
{
struct stretch_data *s = (struct stretch_data *) pltr_data;
PLFLT x0, y0, dy;
x0 = ( s->xmin + s->xmax ) * 0.5;
y0 = ( s->ymin + s->ymax ) * 0.5;
dy = ( s->ymax - s->ymin ) * 0.5;
*tx = x0 + ( x0 - x ) * ( 1.0 - s->stretch * cos( ( y - y0 ) / dy * M_PI * 0.5 ) );
*ty = y;
}
int
main( int argc, const char *argv[] )
{
PLFLT x[XDIM], y[YDIM], **z, **r;
PLFLT xi, yi, xe, ye;
int i, j, width, height, num_col;
PLFLT **img_f;
PLFLT img_min;
PLFLT img_max;
struct stretch_data stretch;
PLcGrid2 cgrid2;
PLFLT xx, yy;
//
// Bugs in plimage():
// -at high magnifications, the left and right edge are ragged, try
// ./x20c -dev xwin -wplt 0.3,0.3,0.6,0.6 -ori 0.5
//
// Bugs in x20c.c:
// -if the window is resized after a selection is made on "lena", when
// making a new selection the old one will re-appear.
//
// Parse and process command line arguments
plMergeOpts( options, "x20c options", NULL );
plparseopts( &argc, argv, PL_PARSE_FULL );
// Initialize plplot
plinit();
plAlloc2dGrid( &z, XDIM, YDIM );
// view image border pixels
if ( dbg )
{
plenv( 1., (PLFLT) XDIM, 1., (PLFLT) YDIM, 1, 1 ); // no plot box
// build a one pixel square border, for diagnostics
for ( i = 0; i < XDIM; i++ )
z[i][YDIM - 1] = 1.; // right
for ( i = 0; i < XDIM; i++ )
z[i][0] = 1.; // left
for ( i = 0; i < YDIM; i++ )
z[0][i] = 1.; // top
for ( i = 0; i < YDIM; i++ )
z[XDIM - 1][i] = 1.; // botton
pllab( "...around a blue square.", " ", "A red border should appear..." );
plimage( (const PLFLT * const *) z, XDIM, YDIM,
1., (PLFLT) XDIM, 1., (PLFLT) YDIM, 0., 0.,
1., (PLFLT) XDIM, 1., (PLFLT) YDIM );
}
// sombrero-like demo
if ( !nosombrero )
{
plAlloc2dGrid( &r, XDIM, YDIM );
plcol0( 2 ); // draw a yellow plot box, useful for diagnostics! :(
plenv( 0., 2. * M_PI, 0, 3. * M_PI, 1, -1 );
for ( i = 0; i < XDIM; i++ )
x[i] = i * 2. * M_PI / (PLFLT) ( XDIM - 1 );
for ( i = 0; i < YDIM; i++ )
y[i] = i * 3. * M_PI / (PLFLT) ( YDIM - 1 );
for ( i = 0; i < XDIM; i++ )
for ( j = 0; j < YDIM; j++ )
{
r[i][j] = sqrt( x[i] * x[i] + y[j] * y[j] ) + 1e-3;
z[i][j] = sin( r[i][j] ) / ( r[i][j] );
}
pllab( "No, an amplitude clipped \"sombrero\"", "", "Saturn?" );
plptex( 2., 2., 3., 4., 0., "Transparent image" );
plimage( (const PLFLT * const *) z, XDIM, YDIM, 0., 2. * M_PI, 0., 3. * M_PI, 0.05, 1.,
0., 2. * M_PI, 0., 3. * M_PI );
plFree2dGrid( r, XDIM, YDIM );
// save the plot
if ( f_name )
save_plot( f_name );
}
plFree2dGrid( z, XDIM, YDIM );
// read Lena image
// Note we try two different locations to cover the case where this
// examples is being run from the test_c.sh script
if ( read_img( "lena.pgm", &img_f, &width, &height, &num_col ) )
{
if ( read_img( "../lena.pgm", &img_f, &width, &height, &num_col ) )
{
fprintf( stderr, "No such file" );
plend();
exit( 1 );
}
}
// set gray colormap
gray_cmap( num_col );
// display Lena
plenv( 1., width, 1., height, 1, -1 );
if ( !nointeractive )
pllab( "Set and drag Button 1 to (re)set selection, Button 2 to finish.", " ", "Lena..." );
else
pllab( "", " ", "Lena..." );
plimage( (const PLFLT * const *) img_f, width, height, 1., width, 1., height, 0., 0.,
1., width, 1., height );
// plend();exit(0);
// selection/expansion demo
if ( !nointeractive )
{
xi = 200.; xe = 330.;
yi = 280.; ye = 220.;
if ( get_clip( &xi, &xe, &yi, &ye ) ) // get selection rectangle
{
plend();
exit( 0 );
}
//
// I'm unable to continue, clearing the plot and advancing to the next
// one, without hiting the enter key, or pressing the button... help!
//
// Forcing the xwin driver to leave locate mode and destroying the
// xhairs (in GetCursorCmd()) solves some problems, but I still have
// to press the enter key or press Button-2 to go to next plot, even
// if a pladv() is not present! Using plbop() solves the problem, but
// it shouldn't be needed!
//
// plbop();
//
// plspause(0), pladv(0), plspause(1), also works,
// but the above question remains.
// With this approach, the previous pause state is lost,
// as there is no API call to get its current state.
//
plspause( 0 );
pladv( 0 );
// display selection only
plimage( (const PLFLT * const *) img_f, width, height, 1., width, 1., height, 0., 0., xi, xe, ye, yi );
plspause( 1 );
// zoom in selection
plenv( xi, xe, ye, yi, 1, -1 );
plimage( (const PLFLT * const *) img_f, width, height, 1., width, 1., height, 0., 0., xi, xe, ye, yi );
}
// Base the dynamic range on the image contents.
plMinMax2dGrid( (const PLFLT * const *) img_f, width, height, &img_max, &img_min );
// Draw a saturated version of the original image. Only use the middle 50%
// of the image's full dynamic range.
plcol0( 2 );
plenv( 0, width, 0, height, 1, -1 );
pllab( "", "", "Reduced dynamic range image example" );
plimagefr( (const PLFLT * const *) img_f, width, height, 0., width, 0., height, 0., 0., img_min + img_max * 0.25, img_max - img_max * 0.25, NULL, NULL );
// Draw a distorted version of the original image, showing its full dynamic range.
plenv( 0, width, 0, height, 1, -1 );
pllab( "", "", "Distorted image example" );
stretch.xmin = 0;
stretch.xmax = width;
stretch.ymin = 0;
stretch.ymax = height;
stretch.stretch = 0.5;
// In C / C++ the following would work, with plimagefr directly calling
// mypltr. For compatibilty with other language bindings the same effect
// can be achieved by generating the transformed grid first and then
// using pltr2.
// plimagefr((const PLFLT **) img_f, width, height, 0., width, 0., height, 0., 0., img_min, img_max, mypltr, (PLPointer) &stretch);
plAlloc2dGrid( &cgrid2.xg, width + 1, height + 1 );
plAlloc2dGrid( &cgrid2.yg, width + 1, height + 1 );
cgrid2.nx = width + 1;
cgrid2.ny = height + 1;
for ( i = 0; i <= width; i++ )
{
for ( j = 0; j <= height; j++ )
{
mypltr( i, j, &xx, &yy, ( PLPointer ) & stretch );
cgrid2.xg[i][j] = xx;
cgrid2.yg[i][j] = yy;
}
}
plimagefr( (const PLFLT * const *) img_f, width, height, 0., width, 0., height, 0., 0., img_min, img_max, pltr2, &cgrid2 );
plFree2dGrid( cgrid2.xg, width + 1, height + 1 );
plFree2dGrid( cgrid2.yg, width + 1, height + 1 );
plFree2dGrid( img_f, width, height );
plend();
exit( 0 );
}
// read image from file in binary ppm format
int read_img( const char *fname, PLFLT ***img_f, int *width, int *height, int *num_col )
{
FILE *fp;
unsigned char *img;
char ver[80];
int i, j, w, h;
PLFLT **imf;
// naive grayscale binary ppm reading. If you know how to, improve it
if ( ( fp = fopen( fname, "rb" ) ) == NULL )
return 1;
if ( fscanf( fp, "%s\n", ver ) != 1 ) // version
{
fclose( fp );
return 1;
}
// printf("version: %s\n", ver);
if ( strcmp( ver, "P5" ) ) // I only understand this!
{
fclose( fp );
return 1;
}
while ( ( i = fgetc( fp ) ) == '#' )
{
if ( fgets( ver, 80, fp ) == NULL ) // comments
{
fclose( fp );
return 1;
}
// printf("%s", ver);
}
ungetc( i, fp );
if ( fscanf( fp, "%d%d%d\n", &w, &h, num_col ) != 3 ) // width, height num colors
{
fclose( fp );
return 1;
}
// printf("width=%d height=%d num_col=%d\n", w, h, *num_col);
img = (unsigned char *) malloc( (size_t) ( w * h ) * sizeof ( char ) );
plAlloc2dGrid( &imf, w, h );
if ( (int) fread( img, sizeof ( char ), (size_t) ( w * h ), fp ) != w * h )
{
fclose( fp );
free( img );
plFree2dGrid( imf, w, h );
return 1;
}
fclose( fp );
for ( i = 0; i < w; i++ )
for ( j = 0; j < h; j++ )
imf[i][j] = img[( h - 1 - j ) * w + i];
// flip image up-down
free( img );
*width = w;
*height = h;
*img_f = imf;
return 0;
}
// save plot
void save_plot( char *fname )
{
PLINT cur_strm, new_strm;
plgstrm( &cur_strm ); // get current stream
plmkstrm( &new_strm ); // create a new one
plsdev( "psc" ); // new device type. Use a known existing driver
plsfnam( fname ); // file name
plcpstrm( cur_strm, 0 ); // copy old stream parameters to new stream
plreplot(); // do the save
plend1(); // close new device
plsstrm( cur_strm ); // and return to previous one
}
// get selection square interactively
int get_clip( PLFLT *xi, PLFLT *xe, PLFLT *yi, PLFLT *ye )
{
PLGraphicsIn gin;
PLFLT xxi = *xi, yyi = *yi, xxe = *xe, yye = *ye, t;
PLINT st, start = 0;
plxormod( 1, &st ); // enter xor mode to draw a selection rectangle
if ( st ) // driver has xormod capability, continue
{
while ( 1 )
{
PLFLT sx[5], sy[5];
plxormod( 0, &st );
plGetCursor( &gin );
plxormod( 1, &st );
if ( gin.button == 1 )
{
xxi = gin.wX; yyi = gin.wY;
if ( start )
plline( 5, sx, sy ); // clear previous rectangle
start = 0;
sx[0] = xxi; sy[0] = yyi;
sx[4] = xxi; sy[4] = yyi;
}
if ( gin.state & 0x100 )
{
xxe = gin.wX; yye = gin.wY;
if ( start )
plline( 5, sx, sy ); // clear previous rectangle
start = 1;
sx[2] = xxe; sy[2] = yye;
sx[1] = xxe; sy[1] = yyi;
sx[3] = xxi; sy[3] = yye;
plline( 5, sx, sy ); // draw new rectangle
}
if ( gin.button == 3 || gin.keysym == PLK_Return || gin.keysym == 'Q' )
{
if ( start )
plline( 5, sx, sy ); // clear previous rectangle
break;
}
}
plxormod( 0, &st ); // leave xor mod
if ( xxe < xxi )
{
t = xxi; xxi = xxe; xxe = t;
}
if ( yyi < yye )
{
t = yyi; yyi = yye; yye = t;
}
*xe = xxe; *xi = xxi;
*ye = yye; *yi = yyi;
return ( gin.keysym == 'Q' );
}
else // driver has no xormod capability, just do nothing
return 0;
}
// set gray colormap
void gray_cmap( PLINT num_col )
{
PLFLT r[2], g[2], b[2], pos[2];
r[0] = g[0] = b[0] = 0.0;
r[1] = g[1] = b[1] = 1.0;
pos[0] = 0.0;
pos[1] = 1.0;
plscmap1n( num_col );
plscmap1l( 1, 2, pos, r, g, b, NULL );
}