~ubuntu-branches/ubuntu/precise/gnome-control-center/precise-updates

« back to all changes in this revision

Viewing changes to font-viewer/font-thumbnailer.c

Tags: upstream-3.0.1.1
ImportĀ upstreamĀ versionĀ 3.0.1.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
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>
4
 
 *
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.
9
 
 *
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.
14
 
 *
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
18
 
 */
19
 
 
20
 
#ifdef HAVE_CONFIG_H
21
 
#  include <config.h>
22
 
#endif
23
 
 
24
 
#include <stdio.h>
25
 
#include <locale.h>
26
 
 
27
 
#include <ft2build.h>
28
 
#include FT_FREETYPE_H
29
 
 
30
 
#include <gdk-pixbuf/gdk-pixbuf.h>
31
 
 
32
 
#include <gio/gio.h>
33
 
#include <glib/gi18n.h>
34
 
 
35
 
#include "totem-resources.h"
36
 
 
37
 
static const gchar *
38
 
get_ft_error(FT_Error error)
39
 
{
40
 
#undef __FTERRORS_H__
41
 
#define FT_ERRORDEF(e,v,s) case e: return s;
42
 
#define FT_ERROR_START_LIST
43
 
#define FT_ERROR_END_LIST
44
 
    switch (error) {
45
 
#include FT_ERRORS_H
46
 
    default:
47
 
        return "unknown";
48
 
    }
49
 
}
50
 
 
51
 
#define FONT_SIZE 64
52
 
#define PAD_PIXELS 4
53
 
 
54
 
FT_Error FT_New_Face_From_URI(FT_Library library,
55
 
                              const gchar *uri,
56
 
                              FT_Long face_index,
57
 
                              FT_Face *aface);
58
 
 
59
 
static void
60
 
draw_bitmap(GdkPixbuf *pixbuf, FT_Bitmap *bitmap, gint off_x, gint off_y)
61
 
{
62
 
    guchar *buffer;
63
 
    gint p_width, p_height, p_rowstride;
64
 
    gint i, j;
65
 
 
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);
70
 
 
71
 
    for (j = 0; j < bitmap->rows; j++) {
72
 
        if (j + off_y < 0 || j + off_y >= p_height)
73
 
            continue;
74
 
        for (i = 0; i < bitmap->width; i++) {
75
 
            guchar pixel;
76
 
            gint pos;
77
 
 
78
 
            if (i + off_x < 0 || i + off_x >= p_width)
79
 
                continue;
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;
84
 
                break;
85
 
            case ft_pixel_mode_grays:
86
 
                pixel = 255 - bitmap->buffer[j*bitmap->pitch + i];
87
 
                break;
88
 
            default:
89
 
                pixel = 255;
90
 
            }
91
 
            pos = (j + off_y) * p_rowstride + 3 * (i + off_x);
92
 
            buffer[pos]   = pixel;
93
 
            buffer[pos+1] = pixel;
94
 
            buffer[pos+2] = pixel;
95
 
        }
96
 
    }
97
 
}
98
 
 
99
 
static void
100
 
draw_char(GdkPixbuf *pixbuf, FT_Face face, FT_UInt glyph_index,
101
 
          gint *pen_x, gint *pen_y)
102
 
{
103
 
    FT_Error error;
104
 
    FT_GlyphSlot slot;
105
 
 
106
 
    slot = face->glyph;
107
 
 
108
 
    error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
109
 
    if (error) {
110
 
        g_printerr("could not load glyph index '%ud': %s\n", glyph_index,
111
 
                   get_ft_error(error));
112
 
        return;
113
 
    }
114
 
 
115
 
    error = FT_Render_Glyph(slot, ft_render_mode_normal);
116
 
    if (error) {
117
 
        g_printerr("could not render glyph index '%ud': %s\n", glyph_index,
118
 
                   get_ft_error(error));
119
 
        return;
120
 
    }
121
 
 
122
 
    draw_bitmap(pixbuf, &slot->bitmap,
123
 
                *pen_x + slot->bitmap_left,
124
 
                *pen_y - slot->bitmap_top);
125
 
 
126
 
    *pen_x += slot->advance.x >> 6;
127
 
}
128
 
 
129
 
static void
130
 
save_pixbuf(GdkPixbuf *pixbuf, gchar *filename)
131
 
{
132
 
    guchar *buffer;
133
 
    gint p_width, p_height, p_rowstride;
134
 
    gint i, j;
135
 
    gint trim_left, trim_right, trim_top, trim_bottom;
136
 
    GdkPixbuf *subpixbuf;
137
 
 
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);
142
 
 
143
 
    for (i = 0; i < p_width; i++) {
144
 
        gboolean seen_pixel = FALSE;
145
 
 
146
 
        for (j = 0; j < p_height; j++) {
147
 
            gint offset = j * p_rowstride + 3*i;
148
 
 
149
 
            seen_pixel = (buffer[offset]   != 0xff ||
150
 
                          buffer[offset+1] != 0xff ||
151
 
                          buffer[offset+2] != 0xff);
152
 
            if (seen_pixel)
153
 
                break;
154
 
        }
155
 
        if (seen_pixel)
156
 
            break;
157
 
    }
158
 
    trim_left = MIN(p_width, i);
159
 
    trim_left = MAX(trim_left - PAD_PIXELS, 0);
160
 
 
161
 
    for (i = p_width-1; i >= trim_left; i--) {
162
 
        gboolean seen_pixel = FALSE;
163
 
 
164
 
        for (j = 0; j < p_height; j++) {
165
 
            gint offset = j * p_rowstride + 3*i;
166
 
 
167
 
            seen_pixel = (buffer[offset]   != 0xff ||
168
 
                          buffer[offset+1] != 0xff ||
169
 
                          buffer[offset+2] != 0xff);
170
 
            if (seen_pixel)
171
 
                break;
172
 
        }
173
 
        if (seen_pixel)
174
 
            break;
175
 
    }
176
 
    trim_right = MAX(trim_left, i);
177
 
    trim_right = MIN(trim_right + PAD_PIXELS, p_width-1);
178
 
 
179
 
    for (j = 0; j < p_height; j++) {
180
 
        gboolean seen_pixel = FALSE;
181
 
 
182
 
        for (i = 0; i < p_width; i++) {
183
 
            gint offset = j * p_rowstride + 3*i;
184
 
 
185
 
            seen_pixel = (buffer[offset]   != 0xff ||
186
 
                          buffer[offset+1] != 0xff ||
187
 
                          buffer[offset+2] != 0xff);
188
 
            if (seen_pixel)
189
 
                break;
190
 
        }
191
 
        if (seen_pixel)
192
 
            break;
193
 
    }
194
 
    trim_top = MIN(p_height, j);
195
 
    trim_top = MAX(trim_top - PAD_PIXELS, 0);
196
 
 
197
 
    for (j = p_height-1; j >= trim_top; j--) {
198
 
        gboolean seen_pixel = FALSE;
199
 
 
200
 
        for (i = 0; i < p_width; i++) {
201
 
            gint offset = j * p_rowstride + 3*i;
202
 
 
203
 
            seen_pixel = (buffer[offset]   != 0xff ||
204
 
                          buffer[offset+1] != 0xff ||
205
 
                          buffer[offset+2] != 0xff);
206
 
            if (seen_pixel)
207
 
                break;
208
 
        }
209
 
        if (seen_pixel)
210
 
            break;
211
 
    }
212
 
    trim_bottom = MAX(trim_top, j);
213
 
    trim_bottom = MIN(trim_bottom + PAD_PIXELS, p_height-1);
214
 
 
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);
220
 
}
221
 
 
222
 
int
223
 
main(int argc, char **argv)
224
 
{
225
 
    FT_Error error;
226
 
    FT_Library library;
227
 
    FT_Face face;
228
 
    FT_UInt glyph_index1, glyph_index2;
229
 
    GFile *file;
230
 
    gchar *uri;
231
 
    GdkPixbuf *pixbuf;
232
 
    guchar *buffer;
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;
242
 
    gint rv = 1;
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") },
250
 
            { NULL }
251
 
    };
252
 
 
253
 
    bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
254
 
    bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
255
 
    textdomain (GETTEXT_PACKAGE);
256
 
 
257
 
    setlocale (LC_ALL, "");
258
 
 
259
 
    g_type_init ();
260
 
    g_thread_init (NULL);
261
 
 
262
 
    context = g_option_context_new (NULL);
263
 
    g_option_context_add_main_entries (context, options, GETTEXT_PACKAGE);
264
 
 
265
 
    retval = g_option_context_parse (context, &argc, &argv, &gerror);
266
 
    g_option_context_free (context);
267
 
    if (!retval) {
268
 
        g_printerr (_("Error parsing arguments: %s\n"), gerror->message);
269
 
        g_error_free (gerror);
270
 
        return 1;
271
 
    }
272
 
 
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]);
276
 
        goto out;
277
 
    }
278
 
 
279
 
    if (thumbstr_utf8 != NULL) {
280
 
        /* build ucs4 version of string to thumbnail */
281
 
        gerror = NULL;
282
 
        thumbstr = g_utf8_to_ucs4 (thumbstr_utf8, strlen (thumbstr_utf8),
283
 
                                   NULL, &thumbstr_len, &gerror);
284
 
        default_thumbstr = FALSE;
285
 
 
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);
290
 
                goto out;
291
 
        }
292
 
    }
293
 
 
294
 
    error = FT_Init_FreeType(&library);
295
 
    if (error) {
296
 
        g_printerr("could not initialise freetype: %s\n", get_ft_error(error));
297
 
        goto out;
298
 
    }
299
 
 
300
 
    totem_resources_monitor_start (arguments[0], 30 * G_USEC_PER_SEC);
301
 
 
302
 
    file = g_file_new_for_commandline_arg (arguments[0]);
303
 
    uri = g_file_get_uri (file);
304
 
    g_object_unref (file);
305
 
 
306
 
    error = FT_New_Face_From_URI(library, uri, 0, &face);
307
 
    if (error) {
308
 
        g_printerr("could not load face '%s': %s\n", uri,
309
 
                   get_ft_error(error));
310
 
        g_free (uri);
311
 
        goto out;
312
 
    }
313
 
 
314
 
    g_free (uri);
315
 
 
316
 
    error = FT_Set_Pixel_Sizes(face, 0, font_size);
317
 
    if (error) {
318
 
        g_printerr("could not set pixel size: %s\n", get_ft_error(error));
319
 
        /* goto out; */
320
 
    }
321
 
 
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]);
327
 
            if (error) {
328
 
                g_printerr("could not set charmap: %s\n", get_ft_error(error));
329
 
                /* goto out; */
330
 
            }
331
 
            break;
332
 
        }
333
 
    }
334
 
 
335
 
    pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
336
 
                            font_size*3*thumbstr_len/2, font_size*1.5);
337
 
    if (!pixbuf) {
338
 
        g_printerr("could not create pixbuf\n");
339
 
        goto out;
340
 
    }
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++)
344
 
        buffer[i] = 255;
345
 
 
346
 
    pen_x = font_size/2;
347
 
    pen_y = font_size;
348
 
 
349
 
    if (default_thumbstr) {
350
 
        glyph_index1 = FT_Get_Char_Index (face, 'A');
351
 
        glyph_index2 = FT_Get_Char_Index (face, 'a');
352
 
 
353
 
        /* if the glyphs for those letters don't exist, pick some other
354
 
        * glyphs. */
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);
357
 
 
358
 
        draw_char(pixbuf, face, glyph_index1, &pen_x, &pen_y);
359
 
        draw_char(pixbuf, face, glyph_index2, &pen_x, &pen_y);
360
 
    }
361
 
    else {
362
 
        gunichar *p = thumbstr;
363
 
        FT_Select_Charmap (face, FT_ENCODING_UNICODE);
364
 
        i = 0;
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);
368
 
            i++;
369
 
            p++;
370
 
        }
371
 
    }
372
 
    save_pixbuf(pixbuf, arguments[1]);
373
 
    g_object_unref(pixbuf);
374
 
 
375
 
    totem_resources_monitor_stop ();
376
 
 
377
 
    /* freeing the face causes a crash I haven't tracked down yet */
378
 
    error = FT_Done_Face(face);
379
 
    if (error) {
380
 
        g_printerr("could not unload face: %s\n", get_ft_error(error));
381
 
        goto out;
382
 
    }
383
 
    error = FT_Done_FreeType(library);
384
 
    if (error) {
385
 
        g_printerr("could not finalise freetype library: %s\n",
386
 
                   get_ft_error(error));
387
 
        goto out;
388
 
    }
389
 
 
390
 
    rv = 0; /* success */
391
 
 
392
 
  out:
393
 
 
394
 
    g_strfreev (arguments);
395
 
    g_free (thumbstr);
396
 
    g_free (thumbstr_utf8);
397
 
 
398
 
    return rv;
399
 
}