Strictly enforce size limits. Automatically handle panoramas.

This commit is contained in:
Stuart Longland 2008-01-29 10:12:15 +10:00
parent 25d503d164
commit 4bd7d81e80
5 changed files with 124 additions and 50 deletions

View File

@ -4,6 +4,7 @@
#include <varray.h>
#include <photo.h>
#include <ClearSilver.h>
#include <settings.h>
/* CGI Environment. The following HDF structure will be initialised by the
* ClearSilver CGI kit to contain the GET and POST variables sent from the
@ -20,16 +21,6 @@ CGI* cgi;
CSPARSE* cstemp;
char* cstemp_dir;
/* Default Photo settings */
#define DEFAULT_WIDTH 720
#define DEFAULT_HEIGHT 0
#define DEFAULT_QUALITY 60
#define DEFAULT_ROTATION "0.0"
/* Max size */
#define MAX_WIDTH 2048
#define MAX_HEIGHT 2048
/* Entry point into entire webapp */
int main( int argc, char** argv );

View File

@ -31,6 +31,7 @@ struct photo_meta {
char* filename;
char* filepath;
struct dimensions size;
double aspect_ratio;
unsigned char is_video;
};
@ -56,6 +57,10 @@ struct photo_info {
char* thumbnail;
struct dimensions thumbdims;
char* annotation;
/* Default settings for photo */
struct dimensions default_dims;
unsigned char default_quality;
double default_rotation;
/* This may be extended at a later date */
};

17
include/settings.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef _SETTINGS_H
#define _SETTINGS_H
/* Default Photo settings */
#define DEFAULT_WIDTH 720
#define DEFAULT_HEIGHT 0
#define DEFAULT_QUALITY 60
#define DEFAULT_ROTATION 0.0
/* Panorama photo settings */
#define PANORAMA_DEFAULT_WIDTH 0
#define PANORAMA_DEFAULT_HEIGHT 540
#define PANORAMA_ASPECT_RATIO 3
/* Max size */
#define MAX_WIDTH 2048
#define MAX_HEIGHT 2048
#endif

View File

@ -350,13 +350,30 @@ void photo_handler( struct gallery_info* gallery,
/* Start up ImageMagick */
MagickWandGenesis();
/* Fetch the gallery information */
struct gallery_contents* gc = read_gallery_contents( gallery, NULL );
dprintf("photo_handler: loaded gallery contents in %p\n", gc);
/* Fetch the photo information */
struct photo_info* photo = read_photo_info( gc, photo_name, NULL );
dprintf("photo_handler: loaded photo info in %p\n", photo);
/* Are we asked to show the original image? */
int original = hdf_get_int_value( cgi->hdf, "Query.original", 0 );
/* Default sizes depend on if we're looking at a panorama or not. */
int default_width = DEFAULT_WIDTH;
int default_height = DEFAULT_HEIGHT;
if ( photo->meta.aspect_ratio >= PANORAMA_ASPECT_RATIO ) {
dputs("photo_handler: detected panorama photo\n");
default_width = PANORAMA_DEFAULT_WIDTH;
default_height= PANORAMA_DEFAULT_HEIGHT;
}
/* Pull the size/quality information out of the GET variables. */
int width = hdf_get_int_value( cgi->hdf, "Query.width", DEFAULT_WIDTH );
int height = hdf_get_int_value( cgi->hdf, "Query.height", DEFAULT_HEIGHT );
int width = hdf_get_int_value( cgi->hdf, "Query.width", default_width );
int height = hdf_get_int_value( cgi->hdf, "Query.height", default_height );
int quality = hdf_get_int_value( cgi->hdf, "Query.quality", DEFAULT_QUALITY );
/* MAX SIZE: Allow images no bigger than a 2048 pixel square */
@ -372,22 +389,17 @@ void photo_handler( struct gallery_info* gallery,
/* Since ClearSilver doesn't provide a 'get float', we have to get
* string then call atof on it.
*/
char* rotation_str = hdf_get_value( cgi->hdf, "Query.rotation", DEFAULT_ROTATION );
double rotation = atof( rotation_str );
if ( ( rotation < -360.0 ) || ( rotation > 360.0 ) ) rotation = 0.0;
char* rotation_str = hdf_get_value( cgi->hdf, "Query.rotation", "" );
double rotation = DEFAULT_ROTATION;
if ( strlen( rotation_str ) )
rotation = atof( rotation_str );
if ( ( rotation < -360.0 ) || ( rotation > 360.0 ) )
rotation = DEFAULT_ROTATION;
dprintf("photo_handler: asked for %dx%d image "
"at %fdeg rotation and %d quality\n",
width, height, rotation, quality);
/* Fetch the gallery information */
struct gallery_contents* gc = read_gallery_contents( gallery, NULL );
dprintf("photo_handler: loaded gallery contents in %p\n", gc);
/* Fetch the photo information */
struct photo_info* photo = read_photo_info( gc, photo_name, NULL );
dprintf("photo_handler: loaded photo info in %p\n", photo);
/* Request image of the specified size */
struct dimensions dims;
char* resized;

View File

@ -9,6 +9,7 @@
#include <sys/stat.h>
#include <unistd.h>
#include <jpeg.h>
#include <settings.h>
/* Read photo information in. It takes a gallery and photo filename as
* arguments, and can optionally take a pre-allocated photo_info struct.
@ -58,6 +59,17 @@ struct photo_info* read_photo_info( struct gallery_contents* gallery,
dest->next = NULL;
dest->annotation = NULL;
/* Default settings should be set according to system defaults */
dest->default_rotation = DEFAULT_ROTATION;
dest->default_quality = DEFAULT_QUALITY;
if ( meta->aspect_ratio >= PANORAMA_ASPECT_RATIO ) {
dest->default_dims.width = PANORAMA_DEFAULT_WIDTH;
dest->default_dims.height = PANORAMA_DEFAULT_HEIGHT;
} else {
dest->default_dims.width = DEFAULT_WIDTH;
dest->default_dims.height = DEFAULT_HEIGHT;
}
/* Attempt to locate the photo and its neighbours */
size_t i;
for( i = 0; i < gallery->photos->length; i++ ) {
@ -148,6 +160,28 @@ struct photo_info* read_photo_info( struct gallery_contents* gallery,
dest->annotation =
get_txtinfo_chain_val( annotations,
".annotation" );
/* This method can also specify default width,
* height, quality and dimension info
*/
char* str;
str = get_txtinfo_chain_val(
annotations, ".width" );
if ( str != NULL )
dest->default_dims.width = atoi(str);
str = get_txtinfo_chain_val(
annotations, ".height" );
if ( str != NULL )
dest->default_dims.height = atoi(str);
str = get_txtinfo_chain_val(
annotations, ".quality" );
if ( str != NULL )
dest->default_quality = (char)atoi(str);
str = get_txtinfo_chain_val(
annotations, ".rotation" );
if ( str != NULL )
dest->default_rotation = atof(str);
destroy_txtinfo_chain( annotations );
}
}
@ -284,6 +318,8 @@ struct photo_meta* read_photo_meta( const char* filename,
dest->size.height = MagickGetImageHeight( wand );
DestroyMagickWand( wand );
}
dest->aspect_ratio = (double)dest->size.width /
(double)dest->size.height;
}
dprintf( "read_photo_meta: video: %d, width: %d, height: %d\n",
dest->is_video, dest->size.width, dest->size.height );
@ -327,6 +363,40 @@ void destroy_photo_meta( struct photo_meta* meta, int fields_only ) {
if ( !fields_only ) free( meta );
}
/* Helper function... calculate size of resized photo */
inline void calculate_dims( struct photo_meta* meta,
unsigned int width, unsigned int height,
struct dimensions* dims ) {
if ( (width == 0) && (height == 0) ) {
width = meta->size.width;
height = meta->size.height;
} else if ( width == 0 ) {
width = (unsigned int)((double)height * meta->aspect_ratio);
} else if ( height == 0 ) {
height = (unsigned int)((double)width / meta->aspect_ratio);
} else {
/* We're given both. Scale the photo to fit within this area */
unsigned int s_width = (unsigned int)
((double)height * meta->aspect_ratio);
if ( s_width > width )
height = (unsigned int)
((double)width / meta->aspect_ratio);
else
width = s_width;
}
dims->width = width;
dims->height = height;
/* Check limits...
* These will overwrite the above values if out-of-bounds */
if ( width > MAX_WIDTH )
calculate_dims( meta, MAX_WIDTH, height, dims );
else if ( height > MAX_HEIGHT )
calculate_dims( meta, width, MAX_HEIGHT, dims );
else if ( ( width > MAX_WIDTH ) && ( height > MAX_HEIGHT ) )
calculate_dims( meta, MAX_WIDTH, MAX_HEIGHT, dims );
}
/* Resize a photo. This sizes and scales a photo to the specified dimensions
* and settings. The image is written to disk cache, the filename being
* returned for display in the browser (when generating HTML or JSON).
@ -346,35 +416,14 @@ char* resize_photo( struct photo_meta* dest,
dprintf( "resize_photo: fitting %s (from %s) in %dx%d area\n",
dest->filename, dest->gallery_name,
width, height );
double aspect_ratio = (double)dest->size.width /
(double)dest->size.height;
dprintf( "resize_photo: calculated aspect ratio %f (%dx%d)\n",
aspect_ratio, dest->size.width, dest->size.height );
if ( (width == 0) && (height == 0) ) {
width = dest->size.width;
height = dest->size.height;
} else if ( width == 0 ) {
width = (unsigned int)((double)height * aspect_ratio);
} else if ( height == 0 ) {
height = (unsigned int)((double)width / aspect_ratio);
} else {
/* We're given both. Scale the photo to fit within this area */
unsigned int s_width = (unsigned int)
((double)height * aspect_ratio);
if ( s_width > width )
height = (unsigned int)
((double)width / aspect_ratio);
else
width = s_width;
}
struct dimensions my_dims;
calculate_dims( dest, width, height, &my_dims );
width = my_dims.width;
height= my_dims.height;
dprintf( "resize_photo: dimensions %dx%d\n", width, height );
if ( resized_dims != NULL ) {
resized_dims->width = width;
resized_dims->height = height;
}
if ( resized_dims != NULL )
memcpy( resized_dims, &my_dims, sizeof(my_dims) );
/* Determine the name of the cache item */
char* cache_file = construct_path( "s/scscicicicfs", CACHEDIR,