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;
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.