cvs: gd /gd-pango README gd_pango.c gd_pango.h /gd-pango/examples rotated.c
[email protected] ("Pierre-Alain Joye")
| Newsgroups | php.gd.cvs |
|---|---|
| Message-ID | <cvspajoye1167403958@cvsserver> |
pajoye Fri Dec 29 14:52:38 2006 UTC
Added files:
/gd/gd-pango/examples rotated.c
Modified files:
/gd/gd-pango gd_pango.c gd_pango.h README
Log:
- add basic rotation support
. experimental codes
. only support rotation transformation for now
- add rotated.c example usage
pajoye-20061229145238.txt
(text/plain, 17.8 KB)
http://cvs.php.net/viewvc.cgi/gd/gd-pango/gd_pango.c?r1=1.1&r2=1.2&diff_format=u Index: gd/gd-pango/gd_pango.c diff -u gd/gd-pango/gd_pango.c:1.1 gd/gd-pango/gd_pango.c:1.2 --- gd/gd-pango/gd_pango.c:1.1 Fri Dec 22 23:50:39 2006 +++ gd/gd-pango/gd_pango.c Fri Dec 29 14:52:37 2006 @@ -15,7 +15,7 @@ | Authors: Pierre-A. Joye <[email protected]> | +----------------------------------------------------------------------+ */ -/* $Id: gd_pango.c,v 1.1 2006/12/22 23:50:39 pajoye Exp $ */ +/* $Id: gd_pango.c,v 1.2 2006/12/29 14:52:37 pajoye Exp $ */ /** * @file * @brief Pango support for GD @@ -24,7 +24,7 @@ * * @author Pierre-Alain Joye * @date 2006/12/19 - * $Id: gd_pango.c,v 1.1 2006/12/22 23:50:39 pajoye Exp $ + * $Id: gd_pango.c,v 1.2 2006/12/29 14:52:37 pajoye Exp $ */ /** * \mainpage @@ -97,10 +97,56 @@ #include <pango/pangoft2.h> #include <gd.h> #include "gd_pango.h" +#include <math.h> //! non-zero if initialized static int GD_PANGO_IS_INITIALIZED = 0; +/* Gets the bounds of a layout in pango units. Mostly copied from gtklabel.c */ +static void +get_rotated_layout_bounds (PangoLayout *layout, int *width, int *height) +{ + PangoContext *context = pango_layout_get_context (layout); + const PangoMatrix *matrix = pango_context_get_matrix(context); + gdouble x_min = 0, x_max = 0, y_min = 0, y_max = 0; /* quiet gcc */ + PangoRectangle logical_rect; + gint i, j; + + pango_layout_get_extents (layout, NULL, &logical_rect); + + for (i = 0; i < 2; i++) + { + gdouble x = (i == 0) ? logical_rect.x : logical_rect.x + logical_rect.width; + for (j = 0; j < 2; j++) + { + gdouble y = (j == 0) ? logical_rect.y : logical_rect.y + logical_rect.height; + + gdouble xt = (x * matrix->xx + y * matrix->xy) + matrix->x0 * PANGO_SCALE; + gdouble yt = (x * matrix->yx + y * matrix->yy) + matrix->y0 * PANGO_SCALE; + + if (i == 0 && j == 0) + { + x_min = x_max = xt; + y_min = y_max = yt; + } + else + { + if (xt < x_min) + x_min = xt; + if (yt < y_min) + y_min = yt; + if (xt > x_max) + x_max = xt; + if (yt > y_max) + y_max = yt; + } + } + } + + *width = ceil (x_max) - floor (x_min); + *height = ceil (y_max) - floor (y_min); +} + static void gdPangoGetItemProperties ( PangoItem *item, PangoUnderline *uline, @@ -195,7 +241,7 @@ } } -static FT_Bitmap * gdPangocreateFTBitmap(int width, int height) +static FT_Bitmap * gdPangoCreateFTBitmap(int width, int height) { FT_Bitmap *bitmap; guchar *buf; @@ -258,6 +304,7 @@ return; } } + alpha_blending_back = surface->alphaBlendingFlag; gdImageAlphaBlending(surface, 1); p_ft = (unsigned char *)bitmap->buffer + (bitmap->pitch * y); @@ -266,7 +313,7 @@ for(i = 0; i < height; i++) { int k; for(k = 0; k < width; k++) { - int level, fg; + int level; if (p_ft[x + k]==0) { continue; } @@ -288,10 +335,8 @@ gdRect *rect, int baseline) { - pango_ft2_render(context->ft2bmp, font, glyphs, - rect->x, rect->y + baseline); - gdPangoCopyFTBitmapToSurface(context->ft2bmp, surface, - colors, rect); + pango_ft2_render(context->ft2bmp, font, glyphs, rect->x, rect->y + baseline); + gdPangoCopyFTBitmapToSurface(context->ft2bmp, surface, colors, rect); gdPangoCleanFTBitmap(context->ft2bmp); } @@ -353,9 +398,9 @@ tmp_list = tmp_list->next; gdPangoGetItemProperties(run->item, - &uline, &strike, &rise, - &fg_color, &fg_set, &bg_color, &bg_set, - &shape_set, &ink_rect, &logical_rect); + &uline, &strike, &rise, + &fg_color, &fg_set, &bg_color, &bg_set, + &shape_set, &ink_rect, &logical_rect); risen_y = y + baseline - PANGO_PIXELS (rise); @@ -373,22 +418,22 @@ if(!shape_set) { if (uline == PANGO_UNDERLINE_NONE) { - pango_glyph_string_extents (run->glyphs, run->item->analysis.font, - NULL, &logical_rect); + pango_glyph_string_extents(run->glyphs, run->item->analysis.font, + &ink_rect, &logical_rect); } else { - pango_glyph_string_extents (run->glyphs, run->item->analysis.font, + pango_glyph_string_extents(run->glyphs, run->item->analysis.font, &ink_rect, &logical_rect); } d_rect.w = (int)PANGO_PIXELS(logical_rect.width); - d_rect.h = (int)height; + d_rect.h = (int)PANGO_PIXELS(logical_rect.height); d_rect.x = (int)(x + PANGO_PIXELS (x_off)); d_rect.y = (int)(risen_y - baseline); if((!context->ft2bmp) || d_rect.w + d_rect.x > context->ft2bmp->width || d_rect.h + d_rect.y > context->ft2bmp->rows) { gdPangofreeFTBitmap(context->ft2bmp); - context->ft2bmp = gdPangocreateFTBitmap(d_rect.w + d_rect.x, d_rect.h + d_rect.y); + context->ft2bmp = gdPangoCreateFTBitmap(d_rect.w + d_rect.x, d_rect.h + d_rect.y); } gdPangoRenderGlyphString(context, surface, &colors, @@ -454,6 +499,8 @@ x_off += logical_rect.width; } } + + /* Public API */ /** @@ -490,7 +537,7 @@ gdPangoContext *context = g_malloc(sizeof(gdPangoContext)); G_CONST_RETURN char *charset; - context->font_map = pango_ft2_font_map_new (); + context->font_map = pango_ft2_font_map_new(); pango_ft2_font_map_set_resolution (PANGO_FT2_FONT_MAP (context->font_map), GD_PANGO_DEFAULT_DPI, GD_PANGO_DEFAULT_DPI); context->context = pango_ft2_font_map_create_context (PANGO_FT2_FONT_MAP (context->font_map)); @@ -523,7 +570,7 @@ /** * Free a context. * - * @param *context [i/o] Context to be free + * @param *context Context to be free */ void gdPangoFreeContext(gdPangoContext *context) { @@ -544,22 +591,12 @@ */ gdImagePtr gdPangoCreateSurfaceDraw(gdPangoContext *context) { - PangoRectangle logical_rect; - gdImagePtr surface; - int width, height; + gdImagePtr surface = NULL; - pango_layout_get_extents (context->layout, NULL, &logical_rect); - width = PANGO_PIXELS (logical_rect.width); - height = PANGO_PIXELS (logical_rect.height); - if(width < context->min_width) { - width = context->min_width; + surface = gdPangoRenderTo(context, surface, 0, 0); + if (!surface) { + printf("surface not set\n"); } - if(height < context->min_height) { - height = context->min_height; - } - - surface = gdImageCreateTrueColor(width, height); - gdPangoRenderTo(context, surface, 0, 0); return surface; } @@ -567,67 +604,118 @@ * Render the text to the given image * * Render the text to the given image. The (x,y) coordinate set the top - * left corner of the text area. + * left corner of the text rectangle. * - * @param *context [in] Context - * @param *surface [i/o] Surface to draw on it - * @param x [in] X of left-top of drawing area - * @param y [in] Y of left-top of drawing area + * @param *context Context + * @param *surface Surface to draw on it + * @param x X of left-top of drawing area + * @param y Y of left-top of drawing area */ -void gdPangoRenderTo(gdPangoContext *context, gdImagePtr surface, int x, int y) +gdImagePtr gdPangoRenderTo(gdPangoContext *context, gdImage* surface, int x, int y) { - PangoLayoutIter *iter; - PangoRectangle logical_rect; - int width, height; + PangoRectangle logical_rect, ink_rect; + int layout_width, layout_height; + int rotated; + double angle; + int new_w, new_h; - if(! surface) { - printf("surface is NULL"); - return; - } + pango_layout_get_pixel_extents(context->layout, &ink_rect, &logical_rect); - iter = pango_layout_get_iter (context->layout); + layout_width = MAX(ink_rect.width, logical_rect.width); + layout_height = MAX(ink_rect.height, logical_rect.height); - pango_layout_get_extents (context->layout, NULL, &logical_rect); - width = PANGO_PIXELS (logical_rect.width); - height = PANGO_PIXELS (logical_rect.height); + rotated = (pango_context_get_matrix(context->context) != NULL); - int ab = surface->alphaBlendingFlag; - gdImageAlphaBlending(surface, 0); - gdImageFilledRectangle(surface, 0,0, surface->sx, surface->sy, 0x0); - gdImageAlphaBlending(surface, ab); - gdImageColorTransparent(surface, 0xFF000011); + /* check if a matrix has been used + * NB: other transformations are not supported yet. GD2 Renderer class + * is required. + */ + if (rotated) { + angle = context->angle * G_PI/180; + int w2,h2; + + /* sin(angle) * layout_height + cos(angle) * layout_width + */ + get_rotated_layout_bounds(context->layout, &w2, &h2); + new_w = PANGO_PIXELS(w2); + new_h = PANGO_PIXELS(h2); + + /* Right aligned rotated layout has different widths than the same contents + * but left aligned + */ + if (pango_layout_get_alignment(context->layout) != PANGO_ALIGN_LEFT) { + new_w = cos(angle) * layout_height + cos(angle) * layout_width; + } + } else { + new_w = layout_width; + new_h = layout_height; + } - if((! context->ft2bmp) || context->ft2bmp->width < width - || context->ft2bmp->rows < height) { + if((! context->ft2bmp) || context->ft2bmp->width < new_w + || context->ft2bmp->rows < new_h) { gdPangofreeFTBitmap(context->ft2bmp); - context->ft2bmp = gdPangocreateFTBitmap(width, height); + context->ft2bmp = gdPangoCreateFTBitmap(new_w, new_h); } - do { - PangoLayoutLine *line; - int baseline; + if (!surface) { + surface = gdImageCreateTrueColor(new_w, new_h); + if (!surface) { + return NULL; + } + } - line = pango_layout_iter_get_line (iter); + if (!rotated) { + PangoLayoutIter *iter = pango_layout_get_iter (context->layout); - pango_layout_iter_get_line_extents (iter, NULL, &logical_rect); - baseline = pango_layout_iter_get_baseline (iter); + do { + PangoLayoutLine *line; + int baseline; + + line = pango_layout_iter_get_line (iter); + + pango_layout_iter_get_line_extents (iter, NULL, &logical_rect); + baseline = pango_layout_iter_get_baseline (iter); + + gdPangoRenderLine(context, surface, line, + x + PANGO_PIXELS (logical_rect.x), + y + PANGO_PIXELS (logical_rect.y), + PANGO_PIXELS (logical_rect.height), + PANGO_PIXELS (baseline - logical_rect.y)); + } while (pango_layout_iter_next_line (iter)); - gdPangoRenderLine(context, surface, line, - x + PANGO_PIXELS (logical_rect.x), - y + PANGO_PIXELS (logical_rect.y), - PANGO_PIXELS (logical_rect.height), - PANGO_PIXELS (baseline - logical_rect.y)); - } while (pango_layout_iter_next_line (iter)); + pango_layout_iter_free (iter); + } else { + int layout_x, layout_y; + int layout_dir_x, layout_dir_y; + int x2p, y2p; + gdRect rect; + + x2p = (int) (sin(angle) * layout_height); + y2p = -(int) (cos(angle) * layout_height); + + layout_dir_x = cos(angle) * x2p; + layout_dir_y = sin(angle) * x2p; + + layout_x = -layout_dir_x; + layout_y = -layout_dir_y; + + rect.x = 0; + rect.y = 0; + rect.w = new_w; + rect.h = new_h; - pango_layout_iter_free (iter); + pango_ft2_render_layout(context->ft2bmp, context->layout, layout_x, layout_y); + gdPangoCopyFTBitmapToSurface(context->ft2bmp, surface, &context->default_colors, &rect); + } + return surface; } /** * Specify minimum size of drawing rect. * - * @param *context [i/o] Context - * @param width [in] Width. -1 means no wrapping mode. - * @param height [in] Height. zero/minus value means non-specified. + * @param *context Context + * @param width Width. -1 means no wrapping mode. + * @param height Height. zero/minus value means non-specified. */ void gdPangoSetMinimumSize(gdPangoContext *context, int width, int height) { @@ -675,7 +763,7 @@ /** * Get layout height. * - * @param *context [in] Context + * @param *context Context * @return Height */ int gdPangoGetLayoutHeight(gdPangoContext *context) @@ -707,9 +795,9 @@ * Set plain text to context. * Text must be utf-8. * - * @param *context [i/o] Context - * @param *text [in] Plain text - * @param length [in] Text length. -1 means NULL-terminated text. + * @param *context Context + * @param *text Plain text + * @param length Text length. -1 means NULL-terminated text. */ void gdPangoSetText(gdPangoContext *context, const char *text, int length) @@ -724,9 +812,9 @@ /** * Set DPI to context. * - * @param *context [i/o] Context - * @param dpi_x [in] X dpi - * @param dpi_y [in] Y dpi + * @param *context Context + * @param dpi_x Horizontal dpi + * @param dpi_y Vertical dpi */ void gdPangoSetDpi(gdPangoContext *context, double dpi_x, double dpi_y) http://cvs.php.net/viewvc.cgi/gd/gd-pango/gd_pango.h?r1=1.1&r2=1.2&diff_format=u Index: gd/gd-pango/gd_pango.h diff -u gd/gd-pango/gd_pango.h:1.1 gd/gd-pango/gd_pango.h:1.2 --- gd/gd-pango/gd_pango.h:1.1 Fri Dec 22 23:50:39 2006 +++ gd/gd-pango/gd_pango.h Fri Dec 29 14:52:37 2006 @@ -15,14 +15,14 @@ | Authors: Pierre-A. Joye <[email protected]> | +----------------------------------------------------------------------+ */ -/* $Id: gd_pango.h,v 1.1 2006/12/22 23:50:39 pajoye Exp $ */ +/* $Id: gd_pango.h,v 1.2 2006/12/29 14:52:37 pajoye Exp $ */ /** * @file * @brief Header file of gd-pango * * @author Pierre-Alain Joye * @date 2006/12/19 - * $Id: gd_pango.h,v 1.1 2006/12/22 23:50:39 pajoye Exp $ + * $Id: gd_pango.h,v 1.2 2006/12/29 14:52:37 pajoye Exp $ */ #ifndef GD_PANGO_H @@ -36,7 +36,7 @@ #define GD_FAILURE -1 #define GD_PANGO_DEFAULT_FONT_FAMILY "Vera" -#define GD_PANGO_DEFAULT_FONT_SIZE 14 +#define GD_PANGO_DEFAULT_FONT_SIZE 20 /* TODO: Use GD DPI instead */ #define GD_PANGO_DEFAULT_DPI 96 @@ -80,11 +80,13 @@ PangoContext *context; PangoFontMap *font_map; PangoFontDescription *font_desc; + PangoMatrix *matrix; PangoLayout *layout; FT_Bitmap *ft2bmp; gdPangoColors default_colors; int min_width; int min_height; + double angle; } gdPangoContext; extern int gdPangoInit(); @@ -95,7 +97,7 @@ extern gdImagePtr gdPangoCreateSurfaceDraw( gdPangoContext *context); -extern void gdPangoRenderTo( +extern gdImagePtr gdPangoRenderTo( gdPangoContext *context, gdImagePtr surface, int x, int y); http://cvs.php.net/viewvc.cgi/gd/gd-pango/README?r1=1.2&r2=1.3&diff_format=u Index: gd/gd-pango/README diff -u gd/gd-pango/README:1.2 gd/gd-pango/README:1.3 --- gd/gd-pango/README:1.2 Sat Dec 23 11:41:35 2006 +++ gd/gd-pango/README Fri Dec 29 14:52:37 2006 @@ -6,5 +6,15 @@ The documentation (doxygen generated) is available here: http://www.libgd.org/pango/ +Basic rotation support has been added. See examples/rotated.c. +There is no gdPangoSetAngle as I like to fully support all +transformations transparently, without having to call GD specific +functions. + +More advanced usages or improved text position can only be added +with a special GD renderer class or using the cairo backend. + +The GD Renderer will be the next big addition in gd-pango. + More to come in the next weeks. (2006-12-22) http://cvs.php.net/viewvc.cgi/gd/gd-pango/examples/rotated.c?view=markup&rev=1.1 Index: gd/gd-pango/examples/rotated.c +++ gd/gd-pango/examples/rotated.c /* +----------------------------------------------------------------------+ | GD-Pango | +----------------------------------------------------------------------+ | Copyright (c) 2006-2007 Pierre-Alain Joye | +----------------------------------------------------------------------+ | This source file is subject to the New BSD license, That is bundled | | with this package in the file LICENSE.NEWBSD, and is available | | through the world-wide-web at | | http://www.opensource.org/licenses/bsd-license.php | | If you did not receive a copy of the new BSDlicense and are unable | | to obtain it through the world-wide-web, please send a note to | | [email protected] so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Pierre-A. Joye <[email protected]> | +----------------------------------------------------------------------+ */ /* $Id: rotated.c,v 1.1 2006/12/29 14:52:38 pajoye Exp $ */ #include <pango/pango.h> #include <pango/pangoft2.h> #include <gd.h> #include <gd_pango.h> char *readFile(const char *filename) { long file_size; char *text; FILE *file = fopen(filename, "rb"); if(!file) { printf("Cannot open file <%s>\n", filename); exit(1); } fseek(file, 0, SEEK_END); file_size = ftell(file); fseek(file, 0, SEEK_SET); text = (char *)malloc(file_size + 1); fread(text, file_size, 1, file); text[file_size] = '\0'; return text; } int main() { gdImagePtr im; char *text; FILE *fp; int w,h; int margin_x, margin_y; gdPangoContext *context; gdPangoColors default_colors; PangoContext *pangocontext; PangoMatrix rotated_matrix = PANGO_MATRIX_INIT; PangoLayout *layout; default_colors.fg = gdTrueColorAlpha(0, 255, 255, 0); default_colors.bg = gdTrueColorAlpha(255, 255, 255, 0); default_colors.alpha = 0; /* text = readFile("russian.txt"); text = readFile("arabic.txt"); text = readFile("hebrew.txt"); text = readFile("german.txt"); text = readFile("english.txt"); */ text = readFile("english.txt"); context = gdPangoCreateContext(); gdPangoSetDpi(context, 96, 96); gdPangoSetMinimumSize(context, 800, 200); gdPangoSetDefaultColor(context, &default_colors); gdPangoSetMarkup(context, text, -1); pangocontext = gdPangoGetPangoContext(context); layout = gdPangoGetPangoLayout(context); pango_context_set_base_dir(pangocontext, PANGO_DIRECTION_LTR); w = gdPangoGetLayoutWidth(context); h = gdPangoGetLayoutHeight(context); margin_x = 0; margin_y = 0; im = gdImageCreateTrueColor(800, 800); gdPangoRenderTo(context, im, margin_x, margin_y); fp = fopen("c.png", "wb"); gdImagePng(im, fp); fclose(fp); gdImageDestroy(im); context->angle = -30; if (context->angle != 0.0) { pango_matrix_rotate (&rotated_matrix, context->angle); pango_context_set_matrix(pangocontext, &rotated_matrix); pango_layout_set_alignment(layout, PANGO_ALIGN_RIGHT); pango_layout_context_changed (layout); context->matrix = &rotated_matrix; } /* Render to a new image, sized for a rotated text */ im = gdPangoCreateSurfaceDraw(context); fp = fopen("d.png", "wb"); gdImagePng(im, fp); fclose(fp); gdPangoFreeContext(context); gdImageDestroy(im); return 0; }