#!/usr/bin/perl
use strict;
$|++;
use Image::Magick;
use lib './lib';
use ServerApp; #NOT IN CPAN, see perlmonks.org
my $app = new ServerApp({
Port => 2690,
});
my $ret = $app->run_with(
[ '/', sub { return indexPage(); } ],
[ 'font-list', sub {
my ($req, $info) = @_;
use CGI;
my $cgi = new CGI($req->content); #POST - this is no good...Se
+rverApp must provide a better facility
my %vars = %{ $cgi->Vars };
if( exists $vars{'fontDir'} ) {
#print "dir: $vars{'fontDir'}\n";
if( -e $vars{'fontDir'} ) {
my $ret = [];
opendir DIR, $vars{'fontDir'};
foreach( readdir DIR ) {
next if /^\.{1,2}/ || !/\.ttf$/i;
push @$ret, $_;
}
closedir DIR;
@$ret = sort { lc $a cmp lc $b } @$ret;
return { js => $ret };
}
}
} ],
[ 'render', sub {
my ($req, $info) = @_;
use CGI;
my $cgi = new CGI($req->url->query); #POST - this is no good..
+.ServerApp must provide a better facility
my %vars = %{ $cgi->Vars };
if( exists $vars{'f'} ) {
if( -e $vars{'f'} ) {
my $text = $vars{'t'} || 'AaBbCcDd';
my $font = $vars{'f'};
my $size = $vars{'p'} || '30';
my $antiAlias = $vars{'a'};
my $color = $vars{'c'} || 'black';
my $baseColor = $vars{'bg'} || 'white';
my $newline_ct = $text =~ tr/\n/\n/;
my $im = new Image::Magick(
'size'=>'1000x1000',
magick => 'gif',
#~ debug=>'All',
);
my $params = {
'font'=>$font,
'pointsize'=>$size,
'fill'=> $color,
'gravity'=>'NorthWest',
'text'=>$text,
'antialias'=>$antiAlias,
};
my $r;
$r = $im->Read( 'xc:'.$baseColor );
warn "$r" if "$r";
my @values = $im->QueryFontMetrics( %$params );
use Data::Dumper;print Dumper($params);
my ($charWidth, $charHeight, $ascender, $descender, $w
+idth, $height, $max_advance) = @values;
$height = ($height + 1) * ($newline_ct + 1);
print $width.'x'.$height . "\n";
$r = $im->Resize( width=>$width+30, height=> $height+5
+);
warn "$r" if "$r";
$r = $im->Annotate( %$params );
warn "$r" if "$r";
my @blobs = $im->ImageToBlob( );
return $blobs[0];
}
}
}, ],
['quit', undef, 1],
);
print "Exited with $ret\n";
sub indexPage {
return join '', <DATA>;
}
__END__
<script>
/* REMOTE request object ********************************************
+**********
Release 1.0
Copyright (C) 2005 bxbd.
REMOTE request object is licensed under the GNU General Public License
*****************************************************/
function Remote() {};
Remote.pending = [];
Remote.Request = function (url, postdata, events) {
var request; //the generic XMLHttpRequest object this library abst
+racts
var isIE;
if (window.XMLHttpRequest) {
request = new XMLHttpRequest();
}
else if (window.ActiveXObject) {
// branch for IE/Windows ActiveX version
isIE = true;
request = new ActiveXObject("Microsoft.XMLHTTP"); //always go
+t to be different..!
}
if(request) {//no XMLHttpRequest object?, we have a problem
var reqid = Remote.pending.length;
request.id = "a" + reqid;
//this is preparing our request object for what to do later on
request.onreadystatechange = function() {
if (Remote.pending[reqid].readyState == 4) {//complete
+...
if (Remote.pending[reqid].status == 200) { //serve
+r returned code 200: OK
var response = Remote.pending[reqid];
//add methods to our response object to parse
+the return value (if applicable)
response.responseObj = function() {
if(typeof(response["_responseObj"]) == 'un
+defined') {
var x;
try {
eval("x = " + response.responseTex
+t);
}
catch(e) {
throw "remote.js ____ Could not pa
+rse server return value:\n" + response.responseText;
}
response["_responseObj"] = x;
}
return response["_responseObj"];
}
//coming soon: response.responseXML
Remote._execute(events.onCompleted, response);
}
else {
Remote._execute(events.onError, Remote.pending
+[reqid]);
}
Remote.pending[reqid] = null; //see, it's being re
+moved.
}
else {
Remote._execute(events.onUpdate, Remote.pending[re
+qid]);
}
}
Remote.pending[reqid] = request; //add to the running hash, th
+e finished case will remove it.
if(postdata) {
request.open("POST", url, true);
request.setRequestHeader('Content-Type', 'application/x-ww
+w-form-urlencoded');
request.send(postdata);
}
else {
alert("Remote.Request, GET: " + url)
request.open("GET", url, true);
request.send(null);
}
return reqid;
}
else {
alert("Could not allocate an XMLHttpRequest object (isIE = " +
+ (isIE ? 'yes' : 'no') + ")");
}
};
Remote._execute = function(excode, Response) {
//the return statements only exist so this method is testable, no
+other reason (right now).
if(typeof(excode) == 'function') {
return excode(Response); ///booooo only 1 argument supported r
+ight now!!
}
else {
return eval(excode);
}
};
Remote.BuildQuery = function() {
//Helper function, takes a list of arguments
// for each argument, if it's a string it seeks out that element (by i
+d) in the DOM tree,
//If an id turns out to be a FORM element, buildQuery will add all the
+ *named* form elements of that form
//otherwise, if it's a hash or object, it'll just copy those right int
+o the finished hash
//returns a GET/POST compatible string from the values of those elemen
+ts
var post = [];
for(var i=0; i<arguments.length; i++) {
if(typeof(arguments[i]) == 'string') {
var elt = document.getElementById(arguments[i]);
if(elt) {
if(elt.tagName.toLowerCase() == 'form') {
+
for(var e=0; e<elt.elements.length; e++) {
if(!elt.elements[e].name) { continue; }
var value = Remote.getValue(elt.elements[e]);
+
post[elt.elements[e].name] = Remote.escapeURI(
+value);
}
}
else {
var value = Remote.getValue(elt);
if(value) {
post[arguments[i]] = Remote.escapeURI(value);
}
}
}
else {
post[arguments[i]] = '';
}
}
else if(typeof(arguments[i]) == 'object') {
for(var x in arguments[i]) {
post[x] = arguments[i][x];
}
}
}
var post_terms = [];
for(var p in post) {
post_terms[post_terms.length] = p + '=' + post[p];
}
return post_terms.join("&");
};
Remote.escapeURI = function(str) {
if(encodeURIComponent) {
return encodeURIComponent(str);
}
else {
return escape(str);
}
};
Remote.getValue = function(elt) {
if(elt.tagName.toLowerCase().match('^(input|select|textarea)$')) {
var value = "";
if(elt.type.toLowerCase() == 'checkbox') {
if(elt.checked) {
return 1;
}
else {
return;
}
}
else {
return elt.value;
}
}
return;
};
</script>
<script>
var fontDir;
monitor( function(){ checkInput("fontDir") }, 500);
function monitor( fcn, time ) {
setTimeout(fcn, time);
setTimeout( function(){ monitor(fcn, time) }, time );
}
function checkInput(id) {
var elt;
if( elt = document.getElementById(id) ) {
if( elt.value != fontDir ) {
loadFonts( elt.value );
}
}
}
function loadFonts(dir) {
fontDir = dir;
var reqid = Remote.Request(
"font-list",
Remote.BuildQuery('fontDir'),
{
onCompleted: function(Response) {
var list = Response.responseObj();
var div = document.getElementById('fontList');
var html = '';
for( var l=0; l<list.length; l++ ) {
//html += "<a style='text-decoration:none;' hr
+ef=\"javascript:render('" + list[l] + "')\">" + list[l] + "</a><br>";
html += "<option value='" + list[l] + "'>" + l
+ist[l] + "</option>";
}
div.innerHTML = html;
},
onError: function(Response) { //what to do when the se
+rver returns anything but a code 200 to this request
+
alert("The server returned an ERROR: " + Response.
+responseText);
}
}
);
}
function nextFont() {
var sel = document.getElementById('fontList');
if( sel.selectedIndex > sel.options.length ) {
sel.selectedIndex = 0;
}
else {
sel.selectedIndex += 1;
}
render();
}
function prevFont() {
var sel = document.getElementById('fontList');
if( sel.selectedIndex <= 0) {
sel.selectedIndex = sel.options.length - 1;
}
else {
sel.selectedIndex -= 1;
}
render();
}
function render() {
var ttf = document.getElementById('fontList').value;
var img = document.getElementById('fontDisplay');
var src = "/render?f=" +
escape(document.getElementById('fontDir').value + "\\" + t
+tf);
var v;
if( v = document.getElementById('fontSize').value ) {
src += "&p=" + v;
}
src += "&a=" + (document.getElementById('fontAlias').checked ?
+ '1':'0') ;
if( v = document.getElementById('fontText').value ) {
src += "&t=" + escape(v);
}
img.src = "";
setTimeout( function() { img.src = src; }, 50 );
}
</script>
<table border=0 cellpadding=0 cellspacing=0>
<tr>
<td colspan=2 style="padding-bottom: 10px;">
Pick a directory to browse:
<br>
<input type=text size=75
id="fontDir"
value="C:\Windows\fonts"
>
</td>
</tr>
<tr>
<td>
<select multiple id="fontList" style="height: 300px; width
+: 250px;border: 2px solid navy; padding: 10px; font: 8pt verdana; tex
+t-decoration: none; overflow: scroll;">
</select>
<br>
<input type=button value="Previous <<" onclick="prev
+Font();">
<input type=button value="Next >>" onclick="nextFont
+();">
<input type=button value="Render." onclick="render()">
</td>
<td valign="top" style="padding: 20px;" align="left">
<table border=0 cellpadding=0 cellspacing=2>
<tr>
<td nowrap>
Point size:
</td>
<td>
<input type=text id="fontSize" size=1>
</td>
</tr>
<tr>
<td>
Antialias?
</td>
<td>
<input type=checkbox id="fontAlias" checked>
</td>
</tr>
<tr valign="top">
<td>
Text:
</td>
<td>
<textarea wrap=hard rows=6 cols=25 id="fontTex
+t"></textarea>
</td>
</tr>
<tr>
<td colspan=2 align="right">
<input type=button value="Render." onclick="re
+nder()">
</td>
</tr>
</table>
</td>
</tr>
</table>
<br>
<img id="fontDisplay" border=0 style="padding: 20px;">
In reply to FontPreview
by qbxk
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.