Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

FontPreview

by qbxk (Friar)
on Dec 28, 2005 at 21:29 UTC ( #519645=sourcecode: print w/replies, xml ) Need Help??
Category: Miscellaneous
Author/Contact Info Brian Bittman brian@bxbd.net
Description: A first program using the experimental ServerApp module. Point this at a directory containing ttf files and it will use PerlMagick (Image Magick) to render provided text in a particular font. Useful when you have hundreds of fonts to "preview" for a particular word or phrase that needs just the right font - there is certainly much to be wanted feature-wise, this is an experiment and demonstration (you probably should use Firefox with this...)
#!/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 &lt;&lt;" onclick="prev
+Font();">
            <input type=button value="Next &gt;&gt;" onclick="nextFont
+();">            
            &nbsp;&nbsp;&nbsp;
            <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;">

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: sourcecode [id://519645]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (5)
As of 2022-01-25 08:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    In 2022, my preferred method to securely store passwords is:












    Results (65 votes). Check out past polls.

    Notices?