diff --git a/include/main.h b/include/main.h index e6a459f..e7e9fd6 100644 --- a/include/main.h +++ b/include/main.h @@ -4,6 +4,7 @@ #include #include #include +#include /* 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 ); diff --git a/include/photo.h b/include/photo.h index 14a0e5c..1727fd5 100644 --- a/include/photo.h +++ b/include/photo.h @@ -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 */ }; diff --git a/include/settings.h b/include/settings.h new file mode 100644 index 0000000..c662122 --- /dev/null +++ b/include/settings.h @@ -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 diff --git a/src/main.c b/src/main.c index 61114f4..e43a95c 100644 --- a/src/main.c +++ b/src/main.c @@ -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; diff --git a/src/photo.c b/src/photo.c index b994e37..c387842 100644 --- a/src/photo.c +++ b/src/photo.c @@ -9,6 +9,7 @@ #include #include #include +#include /* 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,