Strictly enforce size limits. Automatically handle panoramas.
This commit is contained in:
parent
25d503d164
commit
4bd7d81e80
@ -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 );
|
||||
|
||||
|
@ -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
17
include/settings.h
Normal 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
|
38
src/main.c
38
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;
|
||||
|
103
src/photo.c
103
src/photo.c
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user