From 11a458806bf0775b663c164dfc1403f1f3947784 Mon Sep 17 00:00:00 2001 From: raveit Date: Sat, 8 Aug 2015 20:59:06 +0200 Subject: font-viewer: Use cairo for font rendering Taken from gnome-font-viewer based on initial patch by Rodrigo Moya and updated by Cosimo Cecchi commit: 51110f87d6f134f8481031f13fdc3bc3759991bb --- font-viewer/font-thumbnailer.c | 259 +++++++++++++++++++++++------------------ 1 file changed, 148 insertions(+), 111 deletions(-) (limited to 'font-viewer/font-thumbnailer.c') diff --git a/font-viewer/font-thumbnailer.c b/font-viewer/font-thumbnailer.c index 921d2679..5992b3a7 100644 --- a/font-viewer/font-thumbnailer.c +++ b/font-viewer/font-thumbnailer.c @@ -1,5 +1,8 @@ -/* -*- mode: C; c-basic-offset: 4 -*- - * fontilus - a collection of font utilities for MATE +/* -*- mode: C; c-basic-offset: 4 -*- */ + +/* + * font-thumbnailer: a thumbnailer for font files, using FreeType + * * Copyright (C) 2002-2003 James Henstridge * * This program is free software; you can redistribute it and/or modify @@ -23,19 +26,18 @@ #include #include - #include #include FT_FREETYPE_H #include - #include #include +#include "ftstream-vfs.h" #include "totem-resources.h" static const gchar * -get_ft_error(FT_Error error) +get_ft_error (FT_Error error) { #undef __FTERRORS_H__ #define FT_ERRORDEF(e,v,s) case e: return s; @@ -51,83 +53,87 @@ get_ft_error(FT_Error error) #define FONT_SIZE 64 #define PAD_PIXELS 4 -FT_Error FT_New_Face_From_URI(FT_Library library, - const gchar *uri, - FT_Long face_index, - FT_Face *aface); - static void -draw_bitmap(GdkPixbuf *pixbuf, FT_Bitmap *bitmap, gint off_x, gint off_y) +draw_bitmap (GdkPixbuf *pixbuf, + FT_Bitmap *bitmap, + gint off_x, + gint off_y) { guchar *buffer; gint p_width, p_height, p_rowstride; gint i, j; - buffer = gdk_pixbuf_get_pixels(pixbuf); - p_width = gdk_pixbuf_get_width(pixbuf); - p_height = gdk_pixbuf_get_height(pixbuf); - p_rowstride = gdk_pixbuf_get_rowstride(pixbuf); + buffer = gdk_pixbuf_get_pixels (pixbuf); + p_width = gdk_pixbuf_get_width (pixbuf); + p_height = gdk_pixbuf_get_height (pixbuf); + p_rowstride = gdk_pixbuf_get_rowstride (pixbuf); for (j = 0; j < bitmap->rows; j++) { if (j + off_y < 0 || j + off_y >= p_height) continue; + for (i = 0; i < bitmap->width; i++) { guchar pixel; gint pos; if (i + off_x < 0 || i + off_x >= p_width) continue; + switch (bitmap->pixel_mode) { case ft_pixel_mode_mono: - pixel = bitmap->buffer[j * bitmap->pitch + i/8]; + pixel = bitmap->buffer[j * bitmap->pitch + i / 8]; pixel = 255 - ((pixel >> (7 - i % 8)) & 0x1) * 255; break; case ft_pixel_mode_grays: - pixel = 255 - bitmap->buffer[j*bitmap->pitch + i]; + pixel = 255 - bitmap->buffer[j * bitmap->pitch + i]; break; default: pixel = 255; } pos = (j + off_y) * p_rowstride + 3 * (i + off_x); - buffer[pos] = pixel; - buffer[pos+1] = pixel; - buffer[pos+2] = pixel; + buffer[pos] = pixel; + buffer[pos + 1] = pixel; + buffer[pos + 2] = pixel; } } } static void -draw_char(GdkPixbuf *pixbuf, FT_Face face, FT_UInt glyph_index, - gint *pen_x, gint *pen_y) +draw_char (GdkPixbuf *pixbuf, + FT_Face face, + FT_UInt glyph_index, + gint *pen_x, + gint *pen_y) { FT_Error error; FT_GlyphSlot slot; slot = face->glyph; - error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); + error = FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT); if (error) { - g_printerr("could not load glyph index '%ud': %s\n", glyph_index, - get_ft_error(error)); + g_printerr ("Could not load glyph index '%ud': %s\n", glyph_index, + get_ft_error (error)); return; } - error = FT_Render_Glyph(slot, ft_render_mode_normal); + error = FT_Render_Glyph (slot, ft_render_mode_normal); if (error) { - g_printerr("could not render glyph index '%ud': %s\n", glyph_index, - get_ft_error(error)); + g_printerr("Could not render glyph index '%ud': %s\n", glyph_index, + get_ft_error (error)); return; } - draw_bitmap(pixbuf, &slot->bitmap, - *pen_x + slot->bitmap_left, - *pen_y - slot->bitmap_top); + draw_bitmap (pixbuf, &slot->bitmap, + *pen_x + slot->bitmap_left, + *pen_y - slot->bitmap_top); *pen_x += slot->advance.x >> 6; } static void -save_pixbuf(GdkPixbuf *pixbuf, gchar *filename) +save_pixbuf (GdkPixbuf *pixbuf, + const gchar *filename) { guchar *buffer; gint p_width, p_height, p_rowstride; @@ -135,111 +141,127 @@ save_pixbuf(GdkPixbuf *pixbuf, gchar *filename) gint trim_left, trim_right, trim_top, trim_bottom; GdkPixbuf *subpixbuf; - buffer = gdk_pixbuf_get_pixels(pixbuf); - p_width = gdk_pixbuf_get_width(pixbuf); - p_height = gdk_pixbuf_get_height(pixbuf); - p_rowstride = gdk_pixbuf_get_rowstride(pixbuf); + buffer = gdk_pixbuf_get_pixels (pixbuf); + p_width = gdk_pixbuf_get_width (pixbuf); + p_height = gdk_pixbuf_get_height (pixbuf); + p_rowstride = gdk_pixbuf_get_rowstride (pixbuf); for (i = 0; i < p_width; i++) { gboolean seen_pixel = FALSE; for (j = 0; j < p_height; j++) { - gint offset = j * p_rowstride + 3*i; + gint offset = j * p_rowstride + 3 * i; + + seen_pixel = (buffer[offset] != 0xff || + buffer[offset + 1] != 0xff || + buffer[offset + 2] != 0xff); - seen_pixel = (buffer[offset] != 0xff || - buffer[offset+1] != 0xff || - buffer[offset+2] != 0xff); if (seen_pixel) break; } + if (seen_pixel) break; } - trim_left = MIN(p_width, i); - trim_left = MAX(trim_left - PAD_PIXELS, 0); - for (i = p_width-1; i >= trim_left; i--) { + trim_left = MIN (p_width, i); + trim_left = MAX (trim_left - PAD_PIXELS, 0); + + for (i = p_width - 1; i >= trim_left; i--) { gboolean seen_pixel = FALSE; for (j = 0; j < p_height; j++) { - gint offset = j * p_rowstride + 3*i; + gint offset = j * p_rowstride + 3 * i; + + seen_pixel = (buffer[offset] != 0xff || + buffer[offset + 1] != 0xff || + buffer[offset + 2] != 0xff); - seen_pixel = (buffer[offset] != 0xff || - buffer[offset+1] != 0xff || - buffer[offset+2] != 0xff); if (seen_pixel) break; } + if (seen_pixel) break; } - trim_right = MAX(trim_left, i); - trim_right = MIN(trim_right + PAD_PIXELS, p_width-1); + + trim_right = MAX (trim_left, i); + trim_right = MIN (trim_right + PAD_PIXELS, p_width - 1); for (j = 0; j < p_height; j++) { gboolean seen_pixel = FALSE; for (i = 0; i < p_width; i++) { - gint offset = j * p_rowstride + 3*i; + gint offset = j * p_rowstride + 3 * i; + + seen_pixel = (buffer[offset] != 0xff || + buffer[offset + 1] != 0xff || + buffer[offset + 2] != 0xff); - seen_pixel = (buffer[offset] != 0xff || - buffer[offset+1] != 0xff || - buffer[offset+2] != 0xff); if (seen_pixel) break; } + if (seen_pixel) break; } - trim_top = MIN(p_height, j); - trim_top = MAX(trim_top - PAD_PIXELS, 0); - for (j = p_height-1; j >= trim_top; j--) { + trim_top = MIN (p_height, j); + trim_top = MAX (trim_top - PAD_PIXELS, 0); + + for (j = p_height - 1; j >= trim_top; j--) { gboolean seen_pixel = FALSE; for (i = 0; i < p_width; i++) { - gint offset = j * p_rowstride + 3*i; + gint offset = j * p_rowstride + 3 * i; + + seen_pixel = (buffer[offset] != 0xff || + buffer[offset + 1] != 0xff || + buffer[offset + 2] != 0xff); - seen_pixel = (buffer[offset] != 0xff || - buffer[offset+1] != 0xff || - buffer[offset+2] != 0xff); if (seen_pixel) break; } + if (seen_pixel) break; } - trim_bottom = MAX(trim_top, j); - trim_bottom = MIN(trim_bottom + PAD_PIXELS, p_height-1); - - subpixbuf = gdk_pixbuf_new_subpixbuf(pixbuf, trim_left, trim_top, - trim_right - trim_left, - trim_bottom - trim_top); - gdk_pixbuf_save(subpixbuf, filename, "png", NULL, NULL); - g_object_unref(subpixbuf); + + trim_bottom = MAX (trim_top, j); + trim_bottom = MIN (trim_bottom + PAD_PIXELS, p_height - 1); + + subpixbuf = gdk_pixbuf_new_subpixbuf (pixbuf, + trim_left, trim_top, + trim_right - trim_left, + trim_bottom - trim_top); + + gdk_pixbuf_save (subpixbuf, filename, + "png", NULL, NULL); + g_object_unref (subpixbuf); } int -main(int argc, char **argv) +main (int argc, + char **argv) { FT_Error error; FT_Library library; FT_Face face; FT_UInt glyph_index1, glyph_index2; GFile *file; - gchar *uri; GdkPixbuf *pixbuf; guchar *buffer; gint i, len, pen_x, pen_y; gunichar *thumbstr = NULL; glong thumbstr_len = 2; gint font_size = FONT_SIZE; - gchar *thumbstr_utf8 = NULL; + gchar *thumbstr_utf8 = NULL, *help, *uri; gchar **arguments = NULL; GOptionContext *context; GError *gerror = NULL; gboolean retval, default_thumbstr = TRUE; gint rv = 1; + const GOptionEntry options[] = { { "text", 't', 0, G_OPTION_ARG_STRING, &thumbstr_utf8, N_("Text to thumbnail (default: Aa)"), N_("TEXT") }, @@ -260,19 +282,24 @@ main(int argc, char **argv) g_option_context_add_main_entries (context, options, GETTEXT_PACKAGE); retval = g_option_context_parse (context, &argc, &argv, &gerror); - g_option_context_free (context); if (!retval) { - g_printerr (_("Error parsing arguments: %s\n"), gerror->message); + g_printerr ("Error parsing arguments: %s\n", gerror->message); + + g_option_context_free (context); g_error_free (gerror); return 1; } if (!arguments || g_strv_length (arguments) != 2) { - /* FIXME: once glib bug 336089 is fixed, use print_help here instead! */ - g_printerr("usage: %s [--text TEXT] [--size SIZE] FONT-FILE OUTPUT-FILE\n", argv[0]); + help = g_option_context_get_help (context, TRUE, NULL); + g_printerr ("%s", help); + + g_option_context_free (context); goto out; } + g_option_context_free (context); + if (thumbstr_utf8 != NULL) { /* build ucs4 version of string to thumbnail */ gerror = NULL; @@ -280,17 +307,16 @@ main(int argc, char **argv) NULL, &thumbstr_len, &gerror); default_thumbstr = FALSE; - /* Not sure this can really happen... */ if (gerror != NULL) { - g_printerr("Failed to convert: %s\n", gerror->message); - g_error_free (gerror); - goto out; + g_printerr ("Failed to convert: %s\n", gerror->message); + g_error_free (gerror); + goto out; } } - error = FT_Init_FreeType(&library); + error = FT_Init_FreeType (&library); if (error) { - g_printerr("could not initialise freetype: %s\n", get_ft_error(error)); + g_printerr("Could not initialise freetype: %s\n", get_ft_error (error)); goto out; } @@ -300,47 +326,53 @@ main(int argc, char **argv) uri = g_file_get_uri (file); g_object_unref (file); - error = FT_New_Face_From_URI(library, uri, 0, &face); + error = FT_New_Face_From_URI (library, uri, 0, &face); if (error) { - g_printerr("could not load face '%s': %s\n", uri, - get_ft_error(error)); + g_printerr ("Could not load face '%s': %s\n", uri, + get_ft_error (error)); g_free (uri); goto out; } g_free (uri); - error = FT_Set_Pixel_Sizes(face, 0, font_size); + error = FT_Set_Pixel_Sizes (face, 0, font_size); if (error) { - g_printerr("could not set pixel size: %s\n", get_ft_error(error)); - /* goto out; */ + g_printerr ("Could not set pixel size: %s\n", get_ft_error (error)); + goto out; } for (i = 0; i < face->num_charmaps; i++) { if (face->charmaps[i]->encoding == ft_encoding_latin_1 || face->charmaps[i]->encoding == ft_encoding_unicode || face->charmaps[i]->encoding == ft_encoding_apple_roman) { - error = FT_Set_Charmap(face, face->charmaps[i]); + error = FT_Set_Charmap (face, face->charmaps[i]); if (error) { - g_printerr("could not set charmap: %s\n", get_ft_error(error)); - /* goto out; */ + g_printerr("Could not set charmap: %s\n", get_ft_error(error)); + goto out; } break; } } - pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, - font_size*3*thumbstr_len/2, font_size*1.5); + pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, + FALSE, /* has-alpha */ + 8, /* bits-per-sample */ + font_size * 3 * thumbstr_len / 2, /* width */ + font_size * 1.5); /* height */ if (!pixbuf) { - g_printerr("could not create pixbuf\n"); + g_printerr ("Could not create pixbuf\n"); goto out; } - buffer = gdk_pixbuf_get_pixels(pixbuf); - len = gdk_pixbuf_get_rowstride(pixbuf) * gdk_pixbuf_get_height(pixbuf); + + buffer = gdk_pixbuf_get_pixels (pixbuf); + len = gdk_pixbuf_get_rowstride (pixbuf) * gdk_pixbuf_get_height (pixbuf); + + /* fill the pixbuf buffer to make it white */ for (i = 0; i < len; i++) buffer[i] = 255; - pen_x = font_size/2; + pen_x = font_size / 2; pen_y = font_size; if (default_thumbstr) { @@ -349,38 +381,43 @@ main(int argc, char **argv) /* if the glyphs for those letters don't exist, pick some other * glyphs. */ - if (glyph_index1 == 0) glyph_index1 = MIN (65, face->num_glyphs-1); - if (glyph_index2 == 0) glyph_index2 = MIN (97, face->num_glyphs-1); + if (glyph_index1 == 0) + glyph_index1 = MIN (65, face->num_glyphs - 1); - draw_char(pixbuf, face, glyph_index1, &pen_x, &pen_y); - draw_char(pixbuf, face, glyph_index2, &pen_x, &pen_y); - } - else { - gunichar *p = thumbstr; + if (glyph_index2 == 0) + glyph_index2 = MIN (97, face->num_glyphs - 1); + + draw_char (pixbuf, face, glyph_index1, &pen_x, &pen_y); + draw_char (pixbuf, face, glyph_index2, &pen_x, &pen_y); + } else { + const gunichar *p = thumbstr; FT_Select_Charmap (face, FT_ENCODING_UNICODE); i = 0; + while (i < thumbstr_len) { glyph_index1 = FT_Get_Char_Index (face, *p); - draw_char(pixbuf, face, glyph_index1, &pen_x, &pen_y); + draw_char (pixbuf, face, glyph_index1, &pen_x, &pen_y); i++; p++; } } - save_pixbuf(pixbuf, arguments[1]); - g_object_unref(pixbuf); + + save_pixbuf (pixbuf, arguments[1]); + g_object_unref (pixbuf); totem_resources_monitor_stop (); /* freeing the face causes a crash I haven't tracked down yet */ - error = FT_Done_Face(face); + error = FT_Done_Face (face); if (error) { - g_printerr("could not unload face: %s\n", get_ft_error(error)); + g_printerr("Could not unload face: %s\n", get_ft_error (error)); goto out; } - error = FT_Done_FreeType(library); + + error = FT_Done_FreeType (library); if (error) { - g_printerr("could not finalise freetype library: %s\n", - get_ft_error(error)); + g_printerr ("Could not finalize freetype library: %s\n", + get_ft_error (error)); goto out; } -- cgit v1.2.1