--- /dev/null
+<html>
+<head>
+<title>Dynamic Web 2.0 Button using jQuery</title>
+
+<script type="text/javascript" src="jquery.js"></script>
+<script type="text/javascript" src="jquery.corner.js"></script>
+
+<script type="text/javascript">
+
+var fontInfo = {};
+
+var fontName = "Verdana";
+var fontSize = 12;
+
+function getFontImageUrl() {
+ return '/cgi-bin/spritext.cgi?format=png'
+ + '&fontname=' + fontName
+ + '&fontsize=' + fontSize;
+}
+
+function getFontImage() {
+ var newImg = new Image();
+ newImg.src = getFontImageUrl();
+}
+
+function getFontInfoAndUpdate() {
+ $.getJSON("/cgi-bin/spritext.cgi", { fontname: fontName, fontsize: fontSize, format: "json" }, function(json) {
+ fontInfo = json;
+ updateButton($("#input").val());
+ });
+}
+
+$(function(){
+
+ $("#fontsize").change(function() {
+ fontSize = $("#fontsize").val();
+ getFontImage();
+ getFontInfoAndUpdate();
+ }).change();
+
+// $("#button").corner("15px");
+
+ $("#input").keyup(function() {
+ updateButton($(this).val());
+ });
+
+});
+
+var SPACE_WIDTH = 25;
+var LETTER_SPACING = 60;
+var widthMap = {A:31,B:32,C:33,D:35,E:32,F:30,G:34,H:35,I:18,J:15,K:32,L:30,M:39,N:35,O:36,P:30,Q:35,R:34,S:31,T:30,U:34,V:31,W:43,X:31,Y:29,Z:31};
+
+function getLetterWidth(letter, fontSize) {
+ return widthMap[letter.toUpperCase()] * 1.5;
+}
+
+function updateButton(text) {
+ var letters = $("#letters");
+ letters.empty();
+ var btnWidth = 0;
+ var letter = 'A';
+ var previous = 'A';
+ for (var i = 0; i < text.length; i++)
+ {
+ letter = text[i];
+ if (letter == ' ')
+ {
+ letters.append($(document.createElement('div'))
+ .css({float: 'left', width: fontSize * 0.5, height: fontSize})
+ );
+ }
+ else
+ {
+// var className = 'Verdana60';
+ var glyphInfo = fontInfo['u' + letter.charCodeAt(0)];
+// var xPos = -((letterUC.charCodeAt(0) - "A".charCodeAt(0)) * LETTER_SPACING);
+// var yPos = -2;
+// var lWidth = getLetterWidth(letter, 60);
+ var marginLeft = 0;
+ if (letter == 'O')
+ marginLeft = -10;
+ letters.append($(document.createElement('div'))
+ .css({float: 'left',
+ width: glyphInfo.w, height: fontSize,
+ 'background': (-glyphInfo.x) + 'px ' + (-glyphInfo.y) + 'px'
+ + ' url(' + getFontImageUrl() + ')'
+ + ' no-repeat',
+ 'margin-left': marginLeft
+ })
+ );
+ btnWidth += glyphInfo.w + 1;
+ }
+ previous = letter;
+ }
+
+// $("#button").width(btnWidth);
+}
+
+</script>
+
+<style type="text/css">
+
+#letters difev {
+ float: left;
+ height: 100px;
+ background: transparent no-repeat;
+}
+
+#letters .Verdanavds60 {
+ background: url(http://localhost/cgi-bin/spritext.cgi?fontname=Verdana&fontsize=60);
+}
+
+#letters {
+ width: 600px;
+}
+
+.space {
+ width: 25px;
+}
+
+</style>
+
+</head>
+<body>
+
+Font Size: <input type="text" id="fontsize" name="fontsize" value="12" />
+
+<div>
+Floor text: <input type="text" id="input" value="Sh"></input>
+</div>
+
+<br>
+
+<div id="letters"></div>
+
+</body>
+</html>
+
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libgen.h>
+#include <cairo.h>
+#include <cairo-ft.h>
+#include <cgic.h>
+#ifndef CAIRO_HAS_PNG_FUNCTIONS
+#error This program requires cairo with PNG support
+#endif
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))
+
+#define TRUE (1==1)
+#define FALSE (!TRUE)
+
+static cairo_status_t
+stdio_write (void *closure, const unsigned char *data, unsigned int length);
+
+double
+get_max_width (cairo_t *cr, char *characters);
+
+double
+get_max_height (cairo_t *cr, char *characters);
+
+void
+out_stroke (cairo_t *cr)
+{
+
+}
+
+int
+cgiMain ()
+{
+ char outputJson = FALSE;
+
+ char characters[] = {
+ '!', '"', '#', '$', '%', '&','\'', '(',
+ ')', '*', '+', ',', '-', '.', '/', '0',
+ '1', '2', '3', '4', '5', '6', '7', '8',
+ '9', ':', ';', '<', '=', '>', '?', '@',
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+ 'Y', 'Z', '[','\\', ']', '^', '_', '`',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
+ 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
+ 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
+ 'y', 'z', '{', '|', '}', '~'
+ };
+
+ int i;
+
+ /* QueryString */
+ char fontname[20];
+ int fontsize;
+ char format[5];
+ char fillcolor[20];
+ cgiFormStringNoNewlines("fontname", fontname, 20);
+ cgiFormInteger("fontsize", &fontsize, 50);
+ cgiFormStringNoNewlines("format", format, 5);
+ cgiFormStringNoNewlines("fillcolor", fillcolor, 20);
+
+ int fillcolor_red;
+ int fillcolor_green;
+ int fillcolor_blue;
+ sscanf (fillcolor, " rgb : %d , %d , %d ", &fillcolor_red, &fillcolor_green, &fillcolor_blue);
+
+ if ( format[0] == 'j' && format[1] == 's' && format[2] == 'o' && format[3] == 'n' )
+ outputJson = TRUE;
+
+ if (outputJson)
+ {
+ cgiHeaderContentType("application/json");
+ } else {
+ cgiHeaderContentType("image/png");
+ }
+
+ int error;
+ FT_Library library;
+ FT_Face ft_face;
+ FT_Bool use_kerning;
+ FT_UInt left_index, right_index;
+ FT_Vector kerning;
+
+ error = FT_Init_FreeType( &library );
+ if ( error )
+ printf("error");
+
+ error = FT_New_Face( library,"/srv/rdworth.org/cgi-bin/Verdana.ttf",
+ 0,
+ &ft_face );
+ if ( error == FT_Err_Unknown_File_Format )
+ printf("File opened. Font format unsupported.");
+ else if ( error )
+ printf("Could not be open or read or broken.");
+
+ use_kerning = FT_HAS_KERNING( ft_face );
+
+ /* Compute max-width and max-height */
+ cairo_surface_t *surface;
+ cairo_t *cr;
+ cairo_font_face_t *cr_face;
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ 1, 1);
+
+ cr = cairo_create (surface);
+
+/*
+ cairo_select_font_face (cr, fontname,
+ CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_NORMAL);
+*/
+ cr_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0);
+ cairo_set_font_face (cr, cr_face);
+
+ cairo_set_font_size (cr, fontsize);
+
+ cairo_set_line_width (cr, 1.0);
+
+ double max_width = get_max_width(cr, characters);
+ double max_height = get_max_height(cr, characters);
+
+ cairo_font_face_destroy (cr_face);
+
+ cairo_destroy (cr);
+
+ cairo_surface_destroy(surface);
+
+ /* Draw */
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ (max_width + 8) * 10,
+ (max_height + 8) * 10);
+
+ cr = cairo_create (surface);
+
+/*
+ cairo_select_font_face (cr, fontname,
+ CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_NORMAL);
+*/
+ cr_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0);
+ cairo_set_font_face (cr, cr_face);
+
+ cairo_set_font_size (cr, fontsize);
+
+ cairo_text_extents_t extents;
+ double x = 0.0;
+ double y = 0.0;
+
+ if (outputJson)
+ printf("{");
+
+ cairo_translate (cr, 0, -(max_height / 2.50));
+
+// cairo_translate (cr, 0, -5.0);
+
+ char string[2];
+ string[1] = '\0';
+ for (i = 0; i < ARRAY_SIZE(characters); i++)
+ {
+ if (i % 10 == 0)
+ {
+ x = 0.;
+ y += max_height + 8;
+ }
+ string[0] = characters[i];
+
+ cairo_text_extents (cr, string, &extents);
+
+ if (outputJson)
+ {
+ if (i > 0)
+ printf (",\n");
+ printf ("u%i:{", characters[i]);
+ printf ("x:%.1f,y:%.1f,w:%.1f,h:%.1f",
+ x,
+ y - (max_height * 1.15),
+ extents.width + extents.x_bearing,
+ extents.height);
+ int j;
+ for ( j = 0; j < ARRAY_SIZE(characters); j++ )
+ {
+ right_index = FT_Get_Char_Index( ft_face, characters[i] );
+ left_index = FT_Get_Char_Index( ft_face, characters[j] );
+
+ FT_Get_Kerning( ft_face, left_index, right_index,
+ FT_KERNING_UNSCALED, &kerning );
+
+ if ( kerning.x )
+ printf(",k%d:%d", characters[j], kerning.x);
+ }
+
+ printf ("}");
+ }
+
+ x -= extents.x_bearing;
+
+ cairo_move_to (cr, x, y);
+ cairo_set_source_rgb (cr, 0., 0., 0.); // black
+ if ( 0 <= fillcolor_red && fillcolor_red <= 255.0
+ && 0 <= fillcolor_green && fillcolor_green <= 255.0
+ && 0 <= fillcolor_blue && fillcolor_blue <= 255.0 )
+ cairo_set_source_rgb (cr, fillcolor_red / 255.0, fillcolor_green / 255.0, fillcolor_blue / 255.0);
+ cairo_text_path (cr, string);
+ cairo_fill (cr);
+
+ x += extents.x_bearing;
+ x += max_width + 8;
+ }
+
+/*
+ int thick_width = 4;
+ int thin_width = 0;
+
+ for (c = 'A'; c <= 'I'; c++)
+ {
+ string[0] = c;
+ int spacing = ((c - 'A') * letterspacing) + 1;
+
+
+ cairo_save(cr);
+
+ cairo_move_to (cr, spacing, 0);
+ cairo_text_path (cr, string);
+// cairo_set_source_rgb (cr, 0.1, 0.2, 0.2); // gray
+ cairo_set_source_rgb (cr, 0.8, 0.8, 0.85); // silver
+ cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
+
+ cairo_push_group (cr);
+ cairo_set_line_width (cr, thick_width);
+ cairo_stroke_preserve (cr);
+ cairo_set_line_width (cr, thin_width);
+ cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+ cairo_stroke_preserve (cr);
+ cairo_fill (cr);
+ cairo_pop_group_to_source (cr);
+
+ cairo_paint (cr);
+
+ cairo_restore(cr);
+
+ cairo_move_to (cr, spacing, 0);
+ cairo_text_path (cr, string);
+ cairo_set_source_rgb (cr, 0.4, 0.45, 0.7); // blue
+
+ cairo_fill (cr);
+ }
+*/
+
+ cairo_scale (cr, 1, -1);
+ cairo_push_group (cr);
+/*
+
+ cairo_pattern_t *gradient;
+
+ for (i = 0; i < 9; i++)
+ {
+ char c[2];
+ strncpy(c, STRING + i, 1);
+ c[1] = '\0';
+ int spacing = (i * letterspacing) + 1;
+ cairo_move_to (cr, spacing, -3);
+ cairo_show_text (cr, c);
+
+ }
+ cairo_pop_group_to_source (cr);
+
+ gradient = cairo_pattern_create_linear (0, 0, 0, -fontsize);
+ cairo_pattern_add_color_stop_rgba (gradient, 0.0, 1, 1, 1, 0.5);
+ cairo_pattern_add_color_stop_rgba (gradient, 0.7, 1, 1, 1, 0.0);
+
+ cairo_mask (cr, gradient);
+
+ cairo_pattern_destroy (gradient);
+*/
+ if (outputJson)
+ {
+ printf("}");
+ } else {
+ cairo_surface_write_to_png_stream (surface, stdio_write, cgiOut);
+ }
+
+ cairo_destroy (cr);
+
+ cairo_surface_destroy (surface);
+
+ return 0;
+}
+
+static cairo_status_t
+stdio_write (void *closure, const unsigned char *data, unsigned int length)
+{
+ FILE *file = closure;
+ if (fwrite (data, 1, length, file) == length)
+ return CAIRO_STATUS_SUCCESS;
+ else
+ return CAIRO_STATUS_WRITE_ERROR;
+}
+
+double
+get_max_width(cairo_t *cr, char *characters)
+{
+ int i;
+ double max_width = 0.;
+ char string[2];
+ string[1] = '\0';
+ for (i = 0; i < ARRAY_SIZE(characters); i++) {
+ cairo_text_extents_t extents;
+ string[0] = characters[i];
+ cairo_text_extents (cr, string, &extents);
+ if ((extents.width + (extents.x_bearing * 2)) > max_width)
+ max_width = extents.width + (extents.x_bearing * 2);
+ }
+ return max_width;
+}
+
+double
+get_max_height(cairo_t *cr, char *characters)
+{
+ int i;
+ double max_height = 0.;
+ char string[2];
+ string[1] = '\0';
+ for (i = 0; i < ARRAY_SIZE(characters); i++) {
+ cairo_text_extents_t extents;
+ string[0] = characters[i];
+ cairo_text_extents (cr, string, &extents);
+// if ((extents.height - extents.y_bearing) > max_height)
+// max_height = extents.height - extents.y_bearing;
+ if ((extents.height) > max_height)
+ max_height = extents.height;
+ }
+ return max_height;
+}
+
--- /dev/null
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+
+<head>
+<title>spritext</title>
+
+<style type="text/css">
+
+label {
+ margin-right: 10px;
+}
+
+#color {
+ float: left;
+}
+
+.swatch-container {
+ float: left;
+ margin: 4px;
+ padding: 4px;
+}
+
+.swatch-container:hover {
+ margin: 3px;
+ border: 1px dotted #aabbee;
+ background-color: #f3f4f5;
+}
+
+.swatch {
+ cursor: pointer;
+ border: 1px solid gray;
+ width: 25px;
+ height: 25px;
+}
+
+.swatch-container.current {
+ margin: 3px;
+ border: 1px dotted #99aadd;
+ background-color: #e2e3e4;
+}
+
+</style>
+
+<script type="text/javascript" src="jquery.js"></script>
+<script type="text/javascript">
+
+var fontsizes = [10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70];
+
+var fontnames = ["Arial", "Arial Black",
+"Bitstream Charter",
+"Chandas", "Comic Sans MS", "Courier New",
+"Gentium", "Georgia",
+"Impact",
+"Jamrul",
+"Kochi Gothic",
+"MgOpen Canonica", "MgOpen Cosmetica", "MgOpen Modata",
+"Nimbus Roman No9 L",
+"Rekha",
+"Samanata", "Sans", "Serif",
+"Times New Roman", "TlwgTypewriter", "Trebuchet MS", "TSCu_Comic", "TSCu_Paranar",
+"URW Bookman L", "URW Chancery L", "URW Gothic L", "URW Palladio L",
+"Verdana"];
+
+var colors = ["#EEEEEE", "#FFFFFF", "#F9F7ED", "#FFFF88", "#CDEB8B", "#C3D9FF", "#36393D",
+"#FF1A00", "#CC0000", "#FF7400", "#008C00", "#006E2E", "#4096EE", "#FF0084",
+"#D15600", "#C79810", "#73880A", "#6BBA70", "#3F4C6B", "#356AA0", "#D01F3C"
+];
+
+var cgiUrl = "http://localhost/cgi-bin/spritext.cgi";
+
+var fontInfo = {};
+
+var fontName = "Verdana";
+
+var fontSize = 12;
+
+var options = {fontname:null, fontsize:30};
+
+var fontImageUrl = "http://localhost/cgi-bin/spritext.cgi";
+
+$(function(){
+
+ $("#previewInput").keyup(function() {
+ getFontInfoAndUpdate();
+ }).keyup();
+
+ $(fontsizes).each(function(i) {
+ var option = $(document.createElement('option'));
+ option.val(fontsizes[i]);
+ option.text(fontsizes[i].toString());
+ $("#fontSize").append(option);
+ });
+
+ $(fontnames).each(function(i) {
+ var option = $(document.createElement('option'));
+ option.val(fontnames[i]);
+ option.text(fontnames[i]);
+ $("#fontName").append(option);
+ });
+
+ $(colors).each(function(i) {
+ var swatchContainer = $(document.createElement('div'))
+ .addClass('swatch-container');
+ if (!(i % 7))
+ swatchContainer.css('clear', 'left');
+ var swatch = $(document.createElement('div'))
+ .addClass('swatch')
+ .css({'background-color':colors[i]});
+ swatch.click(function() {
+ $('.current').removeClass('current');
+ var swatch = $(this);
+ swatch.parent().addClass('current');
+ setOption('fillcolor', swatch.css('background-color').replace(/\s/g, ''));
+ });
+ swatchContainer.append(swatch);
+ $("#color").append(swatchContainer);
+ });
+
+ $("#fontSize").change(function() {
+ fontSize = $("#fontSize").val();
+ setOption('fontsize', $("#fontSize").val());
+ });
+
+ $("#fontName").change(function() {
+ setOption('fontname', $("#fontName").val());
+ });
+
+});
+
+function setOption(name, value)
+{
+ options[name] = value;
+ var src = cgiUrl + '?t=t';
+ for ( var property in options )
+ {
+ if (options[property])
+ src += '&' + property + '=' + options[property];
+ }
+ fontImageUrl = src;
+ $("#imgCgi").attr('src', fontImageUrl);
+ getFontInfoAndUpdate();
+}
+
+function getFontInfoAndUpdate() {
+ alert(fontName);
+ alert(fontSize);
+ $.getJSON("/cgi-bin/spritext.cgi", { fontname: fontName, fontsize: fontSize, format: "json" }, function(json) {
+ alert(json.toString());
+ fontInfo = json;
+ updatePreview();
+ });
+}
+
+function updatePreview() {
+ var text = $("#previewInput").val()
+ var letters = $("#letters");
+ letters.empty();
+ var btnWidth = 0;
+ var letter = 'A';
+ var previous = 'A';
+ for (var i = 0; i < text.length; i++)
+ {
+ letter = text[i];
+ if (letter == ' ')
+ {
+ letters.append($(document.createElement('div'))
+ .css({float: 'left', width: fontSize * 0.5, height: fontSize})
+ );
+ }
+ else
+ {
+ var glyphInfo = fontInfo['u' + letter.charCodeAt(0)];
+ if (glyphInfo) {
+ var marginLeft = 0;
+ if (letter == 'O')
+ marginLeft = -10;
+ letters.append($(document.createElement('div'))
+ .css({float: 'left',
+ width: glyphInfo.w, height: fontSize,
+ 'background': (-glyphInfo.x) + 'px ' + (-glyphInfo.y) + 'px'
+ + ' url(' + fontImageUrl + ')'
+ + ' no-repeat',
+ 'margin-left': marginLeft, border:'1px solid green'
+ })
+ );
+ btnWidth += glyphInfo.w + 1;
+ }
+ }
+ previous = letter;
+ }
+}
+
+</script>
+
+</head>
+
+<body>
+
+<fieldset style="float:left;width:350px;">
+<legend>Create Font</legend>
+
+<div>
+<label for="fontSize">Font Size:</label><select id="fontSize"></select>
+</div>
+
+<div>
+<label for="fontName">Font Face:</label><select id="fontName"></select>
+</div>
+
+<div>
+<label>Color:</label>
+<div id="color"></div>
+</div>
+
+</fieldset>
+
+<fieldset style="float:left; width:300px;">
+<legend>Use Font</legend>
+<div>
+Enter text: <input type="text" id="previewInput" value="Spritext"></input>
+</div>
+
+<br>
+
+<div id="preview">
+<div id="letters"></div>
+</div>
+
+</fieldset>
+
+<fieldset style="clear:left;">
+<legend>Preview Font</legend>
+
+<div style="clear:left;">
+<img id="imgCgi" src="http://localhost/cgi-bin/spritext.cgi&fontsize=30" style="padding:1px;border:1px solid black;" />
+</div>
+
+</fieldset>
+
+</body>
+
+</html>
+