Strictly enforce size limits. Automatically handle panoramas.
This commit is contained in:
parent
25d503d164
commit
4bd7d81e80
@ -4,6 +4,7 @@
|
|||||||
#include <varray.h>
|
#include <varray.h>
|
||||||
#include <photo.h>
|
#include <photo.h>
|
||||||
#include <ClearSilver.h>
|
#include <ClearSilver.h>
|
||||||
|
#include <settings.h>
|
||||||
|
|
||||||
/* CGI Environment. The following HDF structure will be initialised by the
|
/* CGI Environment. The following HDF structure will be initialised by the
|
||||||
* ClearSilver CGI kit to contain the GET and POST variables sent from the
|
* ClearSilver CGI kit to contain the GET and POST variables sent from the
|
||||||
@ -20,16 +21,6 @@ CGI* cgi;
|
|||||||
CSPARSE* cstemp;
|
CSPARSE* cstemp;
|
||||||
char* cstemp_dir;
|
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 */
|
/* Entry point into entire webapp */
|
||||||
int main( int argc, char** argv );
|
int main( int argc, char** argv );
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ struct photo_meta {
|
|||||||
char* filename;
|
char* filename;
|
||||||
char* filepath;
|
char* filepath;
|
||||||
struct dimensions size;
|
struct dimensions size;
|
||||||
|
double aspect_ratio;
|
||||||
unsigned char is_video;
|
unsigned char is_video;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -56,6 +57,10 @@ struct photo_info {
|
|||||||
char* thumbnail;
|
char* thumbnail;
|
||||||
struct dimensions thumbdims;
|
struct dimensions thumbdims;
|
||||||
char* annotation;
|
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 */
|
/* 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 */
|
/* Start up ImageMagick */
|
||||||
MagickWandGenesis();
|
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? */
|
/* Are we asked to show the original image? */
|
||||||
int original = hdf_get_int_value( cgi->hdf, "Query.original", 0 );
|
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. */
|
/* Pull the size/quality information out of the GET variables. */
|
||||||
int width = hdf_get_int_value( cgi->hdf, "Query.width", DEFAULT_WIDTH );
|
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 height = hdf_get_int_value( cgi->hdf, "Query.height", default_height );
|
||||||
int quality = hdf_get_int_value( cgi->hdf, "Query.quality", DEFAULT_QUALITY );
|
int quality = hdf_get_int_value( cgi->hdf, "Query.quality", DEFAULT_QUALITY );
|
||||||
|
|
||||||
/* MAX SIZE: Allow images no bigger than a 2048 pixel square */
|
/* 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
|
/* Since ClearSilver doesn't provide a 'get float', we have to get
|
||||||
* string then call atof on it.
|
* string then call atof on it.
|
||||||
*/
|
*/
|
||||||
char* rotation_str = hdf_get_value( cgi->hdf, "Query.rotation", DEFAULT_ROTATION );
|
char* rotation_str = hdf_get_value( cgi->hdf, "Query.rotation", "" );
|
||||||
double rotation = atof( rotation_str );
|
double rotation = DEFAULT_ROTATION;
|
||||||
if ( ( rotation < -360.0 ) || ( rotation > 360.0 ) ) rotation = 0.0;
|
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 "
|
dprintf("photo_handler: asked for %dx%d image "
|
||||||
"at %fdeg rotation and %d quality\n",
|
"at %fdeg rotation and %d quality\n",
|
||||||
width, height, rotation, quality);
|
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 */
|
/* Request image of the specified size */
|
||||||
struct dimensions dims;
|
struct dimensions dims;
|
||||||
char* resized;
|
char* resized;
|
||||||
|
103
src/photo.c
103
src/photo.c
@ -9,6 +9,7 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <jpeg.h>
|
#include <jpeg.h>
|
||||||
|
#include <settings.h>
|
||||||
|
|
||||||
/* Read photo information in. It takes a gallery and photo filename as
|
/* Read photo information in. It takes a gallery and photo filename as
|
||||||
* arguments, and can optionally take a pre-allocated photo_info struct.
|
* 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->next = NULL;
|
||||||
dest->annotation = 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 */
|
/* Attempt to locate the photo and its neighbours */
|
||||||
size_t i;
|
size_t i;
|
||||||
for( i = 0; i < gallery->photos->length; 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 =
|
dest->annotation =
|
||||||
get_txtinfo_chain_val( annotations,
|
get_txtinfo_chain_val( annotations,
|
||||||
".annotation" );
|
".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 );
|
destroy_txtinfo_chain( annotations );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -284,6 +318,8 @@ struct photo_meta* read_photo_meta( const char* filename,
|
|||||||
dest->size.height = MagickGetImageHeight( wand );
|
dest->size.height = MagickGetImageHeight( wand );
|
||||||
DestroyMagickWand( 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",
|
dprintf( "read_photo_meta: video: %d, width: %d, height: %d\n",
|
||||||
dest->is_video, dest->size.width, dest->size.height );
|
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 );
|
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
|
/* 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
|
* and settings. The image is written to disk cache, the filename being
|
||||||
* returned for display in the browser (when generating HTML or JSON).
|
* 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",
|
dprintf( "resize_photo: fitting %s (from %s) in %dx%d area\n",
|
||||||
dest->filename, dest->gallery_name,
|
dest->filename, dest->gallery_name,
|
||||||
width, height );
|
width, height );
|
||||||
double aspect_ratio = (double)dest->size.width /
|
struct dimensions my_dims;
|
||||||
(double)dest->size.height;
|
calculate_dims( dest, width, height, &my_dims );
|
||||||
dprintf( "resize_photo: calculated aspect ratio %f (%dx%d)\n",
|
width = my_dims.width;
|
||||||
aspect_ratio, dest->size.width, dest->size.height );
|
height= my_dims.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
dprintf( "resize_photo: dimensions %dx%d\n", width, height );
|
dprintf( "resize_photo: dimensions %dx%d\n", width, height );
|
||||||
|
|
||||||
if ( resized_dims != NULL ) {
|
if ( resized_dims != NULL )
|
||||||
resized_dims->width = width;
|
memcpy( resized_dims, &my_dims, sizeof(my_dims) );
|
||||||
resized_dims->height = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Determine the name of the cache item */
|
/* Determine the name of the cache item */
|
||||||
char* cache_file = construct_path( "s/scscicicicfs", CACHEDIR,
|
char* cache_file = construct_path( "s/scscicicicfs", CACHEDIR,
|
||||||
|
Loading…
Reference in New Issue
Block a user