1
/* -*- mode: C; c-basic-offset: 4 -*-
2
* fontilus - a collection of font utilities for GNOME
3
* Copyright (C) 2002-2003 James Henstridge <james@daa.com.au>
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28
#include FT_FREETYPE_H
30
#include <gdk-pixbuf/gdk-pixbuf.h>
33
#include <glib/gi18n.h>
35
#include "totem-resources.h"
38
get_ft_error(FT_Error error)
41
#define FT_ERRORDEF(e,v,s) case e: return s;
42
#define FT_ERROR_START_LIST
43
#define FT_ERROR_END_LIST
54
FT_Error FT_New_Face_From_URI(FT_Library library,
60
draw_bitmap(GdkPixbuf *pixbuf, FT_Bitmap *bitmap, gint off_x, gint off_y)
63
gint p_width, p_height, p_rowstride;
66
buffer = gdk_pixbuf_get_pixels(pixbuf);
67
p_width = gdk_pixbuf_get_width(pixbuf);
68
p_height = gdk_pixbuf_get_height(pixbuf);
69
p_rowstride = gdk_pixbuf_get_rowstride(pixbuf);
71
for (j = 0; j < bitmap->rows; j++) {
72
if (j + off_y < 0 || j + off_y >= p_height)
74
for (i = 0; i < bitmap->width; i++) {
78
if (i + off_x < 0 || i + off_x >= p_width)
80
switch (bitmap->pixel_mode) {
81
case ft_pixel_mode_mono:
82
pixel = bitmap->buffer[j * bitmap->pitch + i/8];
83
pixel = 255 - ((pixel >> (7 - i % 8)) & 0x1) * 255;
85
case ft_pixel_mode_grays:
86
pixel = 255 - bitmap->buffer[j*bitmap->pitch + i];
91
pos = (j + off_y) * p_rowstride + 3 * (i + off_x);
93
buffer[pos+1] = pixel;
94
buffer[pos+2] = pixel;
100
draw_char(GdkPixbuf *pixbuf, FT_Face face, FT_UInt glyph_index,
101
gint *pen_x, gint *pen_y)
108
error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
110
g_printerr("could not load glyph index '%ud': %s\n", glyph_index,
111
get_ft_error(error));
115
error = FT_Render_Glyph(slot, ft_render_mode_normal);
117
g_printerr("could not render glyph index '%ud': %s\n", glyph_index,
118
get_ft_error(error));
122
draw_bitmap(pixbuf, &slot->bitmap,
123
*pen_x + slot->bitmap_left,
124
*pen_y - slot->bitmap_top);
126
*pen_x += slot->advance.x >> 6;
130
save_pixbuf(GdkPixbuf *pixbuf, gchar *filename)
133
gint p_width, p_height, p_rowstride;
135
gint trim_left, trim_right, trim_top, trim_bottom;
136
GdkPixbuf *subpixbuf;
138
buffer = gdk_pixbuf_get_pixels(pixbuf);
139
p_width = gdk_pixbuf_get_width(pixbuf);
140
p_height = gdk_pixbuf_get_height(pixbuf);
141
p_rowstride = gdk_pixbuf_get_rowstride(pixbuf);
143
for (i = 0; i < p_width; i++) {
144
gboolean seen_pixel = FALSE;
146
for (j = 0; j < p_height; j++) {
147
gint offset = j * p_rowstride + 3*i;
149
seen_pixel = (buffer[offset] != 0xff ||
150
buffer[offset+1] != 0xff ||
151
buffer[offset+2] != 0xff);
158
trim_left = MIN(p_width, i);
159
trim_left = MAX(trim_left - PAD_PIXELS, 0);
161
for (i = p_width-1; i >= trim_left; i--) {
162
gboolean seen_pixel = FALSE;
164
for (j = 0; j < p_height; j++) {
165
gint offset = j * p_rowstride + 3*i;
167
seen_pixel = (buffer[offset] != 0xff ||
168
buffer[offset+1] != 0xff ||
169
buffer[offset+2] != 0xff);
176
trim_right = MAX(trim_left, i);
177
trim_right = MIN(trim_right + PAD_PIXELS, p_width-1);
179
for (j = 0; j < p_height; j++) {
180
gboolean seen_pixel = FALSE;
182
for (i = 0; i < p_width; i++) {
183
gint offset = j * p_rowstride + 3*i;
185
seen_pixel = (buffer[offset] != 0xff ||
186
buffer[offset+1] != 0xff ||
187
buffer[offset+2] != 0xff);
194
trim_top = MIN(p_height, j);
195
trim_top = MAX(trim_top - PAD_PIXELS, 0);
197
for (j = p_height-1; j >= trim_top; j--) {
198
gboolean seen_pixel = FALSE;
200
for (i = 0; i < p_width; i++) {
201
gint offset = j * p_rowstride + 3*i;
203
seen_pixel = (buffer[offset] != 0xff ||
204
buffer[offset+1] != 0xff ||
205
buffer[offset+2] != 0xff);
212
trim_bottom = MAX(trim_top, j);
213
trim_bottom = MIN(trim_bottom + PAD_PIXELS, p_height-1);
215
subpixbuf = gdk_pixbuf_new_subpixbuf(pixbuf, trim_left, trim_top,
216
trim_right - trim_left,
217
trim_bottom - trim_top);
218
gdk_pixbuf_save(subpixbuf, filename, "png", NULL, NULL);
219
g_object_unref(subpixbuf);
223
main(int argc, char **argv)
228
FT_UInt glyph_index1, glyph_index2;
233
gint i, len, pen_x, pen_y;
234
gunichar *thumbstr = NULL;
235
glong thumbstr_len = 2;
236
gint font_size = FONT_SIZE;
237
gchar *thumbstr_utf8 = NULL;
238
gchar **arguments = NULL;
239
GOptionContext *context;
240
GError *gerror = NULL;
241
gboolean retval, default_thumbstr = TRUE;
243
const GOptionEntry options[] = {
244
{ "text", 't', 0, G_OPTION_ARG_STRING, &thumbstr_utf8,
245
N_("Text to thumbnail (default: Aa)"), N_("TEXT") },
246
{ "size", 's', 0, G_OPTION_ARG_INT, &font_size,
247
N_("Font size (default: 64)"), N_("SIZE") },
248
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &arguments,
249
NULL, N_("FONT-FILE OUTPUT-FILE") },
253
bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
254
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
255
textdomain (GETTEXT_PACKAGE);
257
setlocale (LC_ALL, "");
260
g_thread_init (NULL);
262
context = g_option_context_new (NULL);
263
g_option_context_add_main_entries (context, options, GETTEXT_PACKAGE);
265
retval = g_option_context_parse (context, &argc, &argv, &gerror);
266
g_option_context_free (context);
268
g_printerr (_("Error parsing arguments: %s\n"), gerror->message);
269
g_error_free (gerror);
273
if (!arguments || g_strv_length (arguments) != 2) {
274
/* FIXME: once glib bug 336089 is fixed, use print_help here instead! */
275
g_printerr("usage: %s [--text TEXT] [--size SIZE] FONT-FILE OUTPUT-FILE\n", argv[0]);
279
if (thumbstr_utf8 != NULL) {
280
/* build ucs4 version of string to thumbnail */
282
thumbstr = g_utf8_to_ucs4 (thumbstr_utf8, strlen (thumbstr_utf8),
283
NULL, &thumbstr_len, &gerror);
284
default_thumbstr = FALSE;
286
/* Not sure this can really happen... */
287
if (gerror != NULL) {
288
g_printerr("Failed to convert: %s\n", gerror->message);
289
g_error_free (gerror);
294
error = FT_Init_FreeType(&library);
296
g_printerr("could not initialise freetype: %s\n", get_ft_error(error));
300
totem_resources_monitor_start (arguments[0], 30 * G_USEC_PER_SEC);
302
file = g_file_new_for_commandline_arg (arguments[0]);
303
uri = g_file_get_uri (file);
304
g_object_unref (file);
306
error = FT_New_Face_From_URI(library, uri, 0, &face);
308
g_printerr("could not load face '%s': %s\n", uri,
309
get_ft_error(error));
316
error = FT_Set_Pixel_Sizes(face, 0, font_size);
318
g_printerr("could not set pixel size: %s\n", get_ft_error(error));
322
for (i = 0; i < face->num_charmaps; i++) {
323
if (face->charmaps[i]->encoding == ft_encoding_latin_1 ||
324
face->charmaps[i]->encoding == ft_encoding_unicode ||
325
face->charmaps[i]->encoding == ft_encoding_apple_roman) {
326
error = FT_Set_Charmap(face, face->charmaps[i]);
328
g_printerr("could not set charmap: %s\n", get_ft_error(error));
335
pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
336
font_size*3*thumbstr_len/2, font_size*1.5);
338
g_printerr("could not create pixbuf\n");
341
buffer = gdk_pixbuf_get_pixels(pixbuf);
342
len = gdk_pixbuf_get_rowstride(pixbuf) * gdk_pixbuf_get_height(pixbuf);
343
for (i = 0; i < len; i++)
349
if (default_thumbstr) {
350
glyph_index1 = FT_Get_Char_Index (face, 'A');
351
glyph_index2 = FT_Get_Char_Index (face, 'a');
353
/* if the glyphs for those letters don't exist, pick some other
355
if (glyph_index1 == 0) glyph_index1 = MIN (65, face->num_glyphs-1);
356
if (glyph_index2 == 0) glyph_index2 = MIN (97, face->num_glyphs-1);
358
draw_char(pixbuf, face, glyph_index1, &pen_x, &pen_y);
359
draw_char(pixbuf, face, glyph_index2, &pen_x, &pen_y);
362
gunichar *p = thumbstr;
363
FT_Select_Charmap (face, FT_ENCODING_UNICODE);
365
while (i < thumbstr_len) {
366
glyph_index1 = FT_Get_Char_Index (face, *p);
367
draw_char(pixbuf, face, glyph_index1, &pen_x, &pen_y);
372
save_pixbuf(pixbuf, arguments[1]);
373
g_object_unref(pixbuf);
375
totem_resources_monitor_stop ();
377
/* freeing the face causes a crash I haven't tracked down yet */
378
error = FT_Done_Face(face);
380
g_printerr("could not unload face: %s\n", get_ft_error(error));
383
error = FT_Done_FreeType(library);
385
g_printerr("could not finalise freetype library: %s\n",
386
get_ft_error(error));
390
rv = 0; /* success */
394
g_strfreev (arguments);
396
g_free (thumbstr_utf8);