Improved the JavaScript frontend
This commit is contained in:
parent
caf6e071c4
commit
b0dddc1a34
@ -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 );
|
||||
|
||||
|
107
src/main.c
107
src/main.c
@ -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,
|
||||
|
10
src/photo.c
10
src/photo.c
@ -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 )
|
||||
|
116
templates/lib.js
116
templates/lib.js
@ -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;
|
||||
|
@ -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 ?>
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user