Improved the JavaScript frontend

This commit is contained in:
Stuart Longland 2008-01-12 14:23:23 +10:00
parent caf6e071c4
commit b0dddc1a34
6 changed files with 243 additions and 25 deletions

View File

@ -52,6 +52,10 @@ void photo_handler(
void action_handler( char* action_name, /* Name of action to perform */
struct vararray* path_info );
/* Rotation Preview: Rotates the thumbnail of an image
* by the specified amount (in CGI parameters) and returns it. */
void action_rotation_preview( struct vararray* path_info );
/* Write a template out */
void write_template( const char* template_name );

View File

@ -9,6 +9,7 @@
#include <wand/MagickWand.h>
#include <string.h>
#include <photo.h>
#include <gallery.h>
#include <ClearSilver/ClearSilver.h>
#include <json/json.h>
#include <hdf-json.h>
@ -118,15 +119,15 @@ int main( int argc, char** argv ) {
free( gallery_path );
/* If the pointer is not null, then we can pass onto the
* gallery handler. Otherwise, */
* gallery handler. Otherwise, display an error page. */
if ( gallery != NULL ) {
gallery_handler( gallery, path_info );
free( gallery );
} else {
/* TODO */
printf("Content-Type: text/plain\n\n");
printf("Gallery %s not found.\n", gallery_name );
printf("TODO: error page: %s\n", strerror(errno) );
hdf_set_value( cgi->hdf, "error", "gallery_not_found" );
hdf_set_value( cgi->hdf, "what", gallery_name );
hdf_set_value( cgi->hdf, "os_error", strerror(errno) );
write_template( "error.cs" );
}
free( gallery_name );
@ -247,10 +248,98 @@ void gallery_handler( struct gallery_info* gallery,
/* Action pages handler */
void action_handler( char* action_name, /* Name of action to perform */
struct vararray* path_info ) {
printf("Content-Type: text/plain\n\nTODO: action handler for action %s\n", action_name);
char* hdf_string;
hdf_write_string( cgi->hdf, &hdf_string );
puts( hdf_string );
if ( strcmp( action_name, "rotate_preview" ) == 0 ) {
/* Display an image showing the previewed image */
action_rotation_preview( path_info );
} else {
hdf_set_value( cgi->hdf, "error", "action_not_found" );
hdf_set_value( cgi->hdf, "what", action_name );
write_template( "error.cs" );
}
}
/* Action handler for generating previews of rotated images. */
void action_rotation_preview( struct vararray* path_info ) {
/* Parameters, these define what image to rotate, and by how much */
char* gallery_name = hdf_get_value( cgi->hdf,
"Query.gallery", "" );
char* photo_name = hdf_get_value( cgi->hdf,
"Query.photo", "" );
char* rotation_str = hdf_get_value( cgi->hdf,
"Query.rotation", "0.0" );
if ( (strlen(gallery_name) < 1) || (strlen(photo_name) < 1) )
return; /* Nothing to do */
double rotation = atof( rotation_str );
if ( ( rotation < -360.0 ) || ( rotation > 360.0 ) ) rotation = 0.0;
/* Load the gallery metadata */
char* my_dir = get_cgidir();
char* gallery_dir = construct_path( "s/s", my_dir,
gallery_name );
struct gallery_info* gallery = read_gallery( gallery_dir, NULL );
struct gallery_contents* gc = read_gallery_contents( gallery, NULL );
if ( gc == NULL ) return;
/* Fetch the photo info */
struct photo_info* photo = read_photo_info( gc, photo_name, NULL );
if ( photo == NULL ) return;
if ( photo->thumbnail == NULL ) return;
/* Kickstart the ImageMagick library */
MagickWandGenesis();
/* Load the thumbnail up */
char* thumbnail_path = construct_path( "s/s",
my_dir, photo->thumbnail );
MagickWand* wand = NewMagickWand();
if (MagickReadImage( wand, thumbnail_path ) == MagickFalse) {
ExceptionType severity;
char* description=MagickGetException(wand,&severity);
dprintf("%s %s %ld %s\n",GetMagickModule(),description);
return;
}
/* Background colour */
PixelWand* background = NewPixelWand();
PixelSetColor( background, "#ffffff" );
MagickRotateImage( wand, background, rotation );
/* Resize & pad the image to 100x100 pixels */
double aspect_ratio = (double)MagickGetImageWidth( wand ) /
(double)MagickGetImageHeight( wand );
unsigned int x = (unsigned int)( 100.0 / aspect_ratio );
unsigned int offset = 50 - (x/2);
if ( x <= 100 ) {
MagickResizeImage( wand, 100, x, LanczosFilter, 1.0 );
MagickExtentImage( wand, 100, 100, 0, -offset );
} else {
x = (unsigned int)( 100.0 * aspect_ratio );
MagickResizeImage( wand, x, 100, LanczosFilter, 1.0 );
MagickExtentImage( wand, 100, 100, offset, 0 );
}
/* Set quality to 50% */
MagickSetImageCompressionQuality( wand, 50 );
/* Output a header */
printf("Content-Type: image/jpeg\n\n");
fflush(stdout);
/* Output the image */
MagickWriteImageFile( wand, stdout );
/* Clean up */
free( thumbnail_path );
destroy_photo_info( photo, 0 );
destroy_gallery_contents( gc, 0 );
destroy_gallery_info( gallery, 0 );
free( gallery_dir );
free( my_dir );
DestroyMagickWand( wand );
}
void photo_handler( struct gallery_info* gallery,

View File

@ -415,8 +415,16 @@ char* resize_photo( struct photo_meta* dest,
PixelWand* background = NewPixelWand();
PixelSetColor( background, "#ffffff" );
MagickRotateImage( wand, background, rotation );
MagickResizeImage( wand, width, height, LanczosFilter, 1.0 );
MagickRotateImage( wand, background, rotation );
/* Since rotating the image changes the aspect ratio, we'll
* update the resized image dimensions here.
*/
if ( ( rotation != 0.0) && ( resized_dims != NULL ) ) {
resized_dims->width = MagickGetImageWidth( wand );
resized_dims->height = MagickGetImageHeight( wand );
}
/* Image quality */
if ( quality < 100 )

View File

@ -15,7 +15,7 @@ function fetchImage( width, height, rotation ) {
xhr.onreadystatechange = function() {
if ( xhr.readyState == 4) {
document.zoom_en = true;
document.scroll_en = true;
if ( xhr.status == 200 ) {
eval( 'data=' + xhr.responseText );
photo_obj.src =
@ -23,6 +23,10 @@ function fetchImage( width, height, rotation ) {
document.data = data;
}
}
showPopupFor(3000, '<p class="popuptitle">Image Loaded</h4>'
+'<p class="popupbody">'
+'The image has been successfully retrieved.</p>');
document.scroll_en = true;
};
/* Cancel any existing timers */
@ -40,10 +44,15 @@ function fetchImage( width, height, rotation ) {
+ '&json=1';
document.zoom_timer = window.setTimeout( function() {
document.zoom_en = false;
document.scroll_en = false;
document.zoom_timer = false;
document.scroll_en = false;
showPopup('<p class="popuptitle">Loading Image</h4>'
+'<p class="popupbody">'
+'The requested image is being generated...'
+'Please Wait.</p>');
xhr.open('GET', url );
xhr.send(null);
document.zoom_timer = false;
}, 3000 );
}
@ -72,35 +81,118 @@ function setZoom( zoom ) {
fetchImage( width, height, data.settings.rotation );
}
}
zoomlabel = document.getElementById( 'zoomlabel' );
if ( zoomlabel ) {
zoomlabel.innerHTML = zoom;
}
showPopupFor(3000,'<p class="popuptitle">Zoom Image</h4>'
+'<p class="popupbody">Zoom photo to '+zoom
+'x magnification.<br />'
+'Adjust using your mouse\'s scroll wheel then '
+'wait a moment to see the result.</p>');
}
function resetZoom() {
data = getData();
if ( document.zoom_en )
setZoom( data.photo.zoom );
if ( document.scroll_en )
setZoom( document.defaultZoom );
}
function adjustZoom( amount ) {
data = getData();
if ( document.zoom == null )
document.zoom = data.photo.zoom;
if ( document.zoom_en )
if ( document.scroll_en )
setZoom( document.zoom + amount );
}
function showPopup(body) {
if ( document.popupDiv )
div = document.popupDiv;
else {
div = document.popupDiv
= document.createElement('div');
div.style.position='absolute';
div.style.right='0px';
div.style.top='0px';
div.style.width='30em';
div.style.height='100px';
div.style.backgroundColor='#ccc';
div.style.color='black';
div.style.borderStyle='dotted';
div.style.borderColor='black';
div.style.borderWidth='2px';
div.style.visibility='hidden';
document.body.appendChild( div );
}
div.innerHTML = body;
div.style.visibility='visible';
}
function showPopupFor(duration, body) {
showPopup( body );
if ( document.popup_timer )
window.clearTimeout( document.popup_timer );
document.popup_timer = window.setTimeout( function() {
hidePopup();
}, duration);
}
function hidePopup() {
document.popupDiv.style.visibility='hidden';
}
function setRotation( angle ) {
data = getData();
/* Display a preview */
preview = document.location.protocol + "//"
+ document.location.hostname
+ data.CGI.ScriptName
+ '/.rotate_preview'
+ '?gallery=' + data.gallery.name
+ '&photo=' + data.photo.name
+ '&rotation=' + angle;
if ( preview == document.rotationPreview )
return;
showPopup('<img alt="preview" src="'+preview
+'" width="100" height="100" align="right" />'
+'<p class="popuptitle">Rotate Photo</p>'
+'<p class="popupbody">Rotate photo by '+angle
+' degrees.<br />'
+'Adjust using your mouse\'s scroll wheel then '
+'wait a moment to see the result.</p>');
/* Schedule actual image fetch */
fetchImage( data.photo.width, data.photo.height, angle );
rotatefield = document.getElementById( 'rotate' );
if ( rotatefield ) {
rotatefield.value = angle;
}
document.rotationPreview = preview;
document.rotation = angle;
}
function adjustRotation(amount) {
data = getData();
setRotation( parseFloat(document.rotation) + amount );
}
function wheelHandler( delta ) {
pan=Math.round(document.getElementById('wheelPan').value);
zoom=Math.round(document.getElementById('wheelZoom').value)/100;
angle=parseFloat(document.getElementById('wheelRotate').value);
if ( document.getElementById('wheelActionZoom').checked )
if ( document.zoom_en )
if ( document.scroll_en )
adjustZoom( delta * zoom );
if ( document.getElementById('wheelActionHPan').checked )
window.scrollBy( -delta*pan, 0 );
if ( document.getElementById('wheelActionVPan').checked )
window.scrollBy( 0, -delta*pan );
if ( document.getElementById('wheelActionRotate').checked )
if ( document.scroll_en )
adjustRotation( -delta*angle );
}
document.zoom_en = true;
document.scroll_en = true;

View File

@ -8,6 +8,9 @@ body {
<script lang="tyoe/javascript">
function getData() {
var data = {
CGI: {
ScriptName: '<?cs var:js_escape(CGI.ScriptName) ?>'
},
gallery: {
name: '<?cs var:js_escape(gallery.name) ?>',
title: '<?cs var:js_escape(gallery.title) ?>',
@ -41,6 +44,10 @@ body {
document.data = data;
return( data );
}
document.defaultZoom =
Math.round( 100*(<?cs var:photo.width ?>) /
<?cs var:photo.origwidth ?>)/100;
document.rotation = <?cs var:settings.rotation ?>;
</script>
<script lang="text/javascript" src="<?cs var:uri
?>/templates/lib.js"></script>
@ -110,7 +117,7 @@ body {
<input type="text" name="height" id="height"
value="<?cs var:photo.height ?>" size="3" />
Rotation:
<input type="text" name="rotation"
<input type="text" name="rotation" id="rotate"
value="0.000" size="3" />
Quality: <input type="text" name="quality"
value="60" size="3" />
@ -118,7 +125,7 @@ body {
<input type="submit" value="Go" />
<br />
Zoom: <span id="zoomlabel"></span>
Zoom:
<a href="#" onclick="adjustZoom( -0.1 );">[-0.1]</a>
<a href="#" onclick="adjustZoom( -0.01 );">[-0.01]</a>
<a href="#" onclick="setZoom( 1.0 );">[1.0]</a>
@ -144,6 +151,14 @@ body {
<label for="wheelActionVPan">VPan</label>
by <input type="text" name="wheelPan" size="2"
value="50" id="wheelPan" /> pixels
or
<input type="radio" name="wheelAction"
value="rotate"
id="wheelActionRotate" />
<label for="wheelActionRotate">Rotate</label>
by <input type="text" name="wheelRotate" size="2"
value="1" id="wheelRotate" /> degrees
</p>
</form>
</td>
@ -155,5 +170,4 @@ body {
src="<?cs var:uri ?>/<?cs var:photo.resized ?>"
alt="<?cs var:html_strip(photo.annotation) ?>"
lowsrc="<?cs var:uri ?>/<?cs var:photo.thumbnail ?>" /></p>
<script type="text/javascript">resetZoom();</script>
<?cs /def ?>

View File

@ -77,3 +77,14 @@ li {
padding-top: 0.5em;
padding-bottom: 0.5em;
}
.popuptitle {
text-align: center;
font-size: large;
height: 20px;
}
.popupbody {
text-align: center;
height: 80px;
}