static void render_callback (PangoLayout *layout, int x, int y, gpointer context, gpointer state) { pango_ft2_render_layout ((FT_Bitmap *)context, layout, x, y); }
void Gosu::pango::drawText(Bitmap& bitmap, const std::wstring& text, int x, int y, Color c, const std::wstring& fontFace, unsigned fontHeight, unsigned fontFlags) { textWidth(text, fontFace, fontHeight, fontFlags); FT_Bitmap ft_bitmap; guchar* buf = new guchar[width * height]; std::fill(buf, buf + width * height, 0x00); ft_bitmap.rows = height; ft_bitmap.width = width; ft_bitmap.pitch = ft_bitmap.width; ft_bitmap.buffer = buf; ft_bitmap.num_grays = 256; ft_bitmap.pixel_mode = ft_pixel_mode_grays; int x_start = 0; pango_ft2_render_layout(&ft_bitmap, layout, x_start, 0); int min_height = height; if((unsigned)height > fontHeight) min_height = fontHeight; for(int y2 = 0; y2 < min_height; y2++) { if (y + y2 < 0 || y + y2 >= bitmap.height()) break; for(int x2 = 0; x2 < width; x2++) { if (x + x2 < 0 || x + x2 >= bitmap.width()) break; unsigned val = ft_bitmap.buffer[y2*width+x2]; Color color = c; color.setAlpha(val); bitmap.setPixel(x2 + x, y2 + y, color); } } delete[] buf; }
/** Draw a TextLine object. * @param object The renderer object to use for transform and output * @param text_line The TextLine to render, including font and height. * @param pos The position to render it at. * @param color The color to render it with. */ static void draw_text_line (DiaRenderer *object, TextLine *text_line, Point *pos, Alignment alignment, Color *color) { DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object); GdkColor gdkcolor; int x,y; Point start_pos; PangoLayout* layout = NULL; const gchar *text = text_line_get_string(text_line); int height_pixels; real font_height = text_line_get_height(text_line); real scale = dia_transform_length(renderer->transform, 1.0); if (text == NULL || *text == '\0') return; /* Don't render empty strings. */ point_copy(&start_pos,pos); renderer_color_convert(renderer, color, &gdkcolor); height_pixels = dia_transform_length(renderer->transform, font_height); if (height_pixels < 2) { /* "Greeking" instead of making tiny font */ int width_pixels = dia_transform_length(renderer->transform, text_line_get_width(text_line)); gdk_gc_set_foreground(renderer->gc, &gdkcolor); gdk_gc_set_dashes(renderer->gc, 0, (gint8*)"\1\2", 2); dia_transform_coords(renderer->transform, start_pos.x, start_pos.y, &x, &y); gdk_draw_line(renderer->pixmap, renderer->gc, x, y, x + width_pixels, y); return; } else { start_pos.y -= text_line_get_ascent(text_line); start_pos.x -= text_line_get_alignment_adjustment (text_line, alignment); dia_transform_coords(renderer->transform, start_pos.x, start_pos.y, &x, &y); layout = dia_font_build_layout(text, text_line->font, dia_transform_length(renderer->transform, text_line->height)/20.0); #if defined(PANGO_VERSION_ENCODE) # if (PANGO_VERSION >= PANGO_VERSION_ENCODE(1,16,0)) /* I'd say the former Pango API was broken, i.e. leaky */ # define HAVE_pango_layout_get_line_readonly # endif #endif text_line_adjust_layout_line (text_line, #if defined(HAVE_pango_layout_get_line_readonly) pango_layout_get_line_readonly(layout, 0), #else pango_layout_get_line(layout, 0), #endif scale/20.0); if (renderer->highlight_color != NULL) { draw_highlighted_string(renderer, layout, x, y, &gdkcolor); } else { #if defined HAVE_FREETYPE { FT_Bitmap ftbitmap; int width, height; GdkPixbuf *rgba = NULL; width = dia_transform_length(renderer->transform, text_line_get_width(text_line)); height = dia_transform_length(renderer->transform, text_line_get_height(text_line)); if (width > 0) { int stride; guchar* pixels; int i,j; guint8 *graybitmap; initialize_ft_bitmap(&ftbitmap, width, height); pango_ft2_render_layout(&ftbitmap, layout, 0, 0); graybitmap = ftbitmap.buffer; rgba = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height); stride = gdk_pixbuf_get_rowstride(rgba); pixels = gdk_pixbuf_get_pixels(rgba); for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixels[i*stride+j*4] = gdkcolor.red>>8; pixels[i*stride+j*4+1] = gdkcolor.green>>8; pixels[i*stride+j*4+2] = gdkcolor.blue>>8; pixels[i*stride+j*4+3] = graybitmap[i*ftbitmap.pitch+j]; } } g_free(graybitmap); gdk_draw_pixbuf(renderer->pixmap, renderer->gc, rgba, 0, 0, x, y, width, height, GDK_RGB_DITHER_NONE, 0, 0); g_object_unref(G_OBJECT(rgba)); } } #else gdk_gc_set_foreground(renderer->gc, &gdkcolor); gdk_draw_layout(renderer->pixmap, renderer->gc, x, y, layout); #endif } /* !higlight_color */ g_object_unref(G_OBJECT(layout)); } /* !greeking */
static Image *ReadCAPTIONImage(const ImageInfo *image_info, ExceptionInfo *exception) { char *caption, *property; const char *option; DrawInfo *draw_info; FT_Bitmap *canvas; Image *image; PangoAlignment align; PangoContext *context; PangoFontDescription *description; PangoFontMap *fontmap; PangoGravity gravity; PangoLayout *layout; PangoRectangle extent; PixelPacket fill_color; RectangleInfo page; register PixelPacket *q; register unsigned char *p; ssize_t y; /* Initialize Image structure. */ assert(image_info != (const ImageInfo *) NULL); assert(image_info->signature == MagickSignature); if (image_info->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", image_info->filename); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickSignature); image=AcquireImage(image_info); (void) ResetImagePage(image,"0x0+0+0"); /* Get context. */ fontmap=(PangoFontMap *) pango_ft2_font_map_new(); pango_ft2_font_map_set_resolution((PangoFT2FontMap *) fontmap, image->x_resolution,image->y_resolution); option=GetImageOption(image_info,"caption:hinting"); pango_ft2_font_map_set_default_substitute((PangoFT2FontMap *) fontmap, PangoSubstitute,(char *) option,NULL); context=pango_font_map_create_context(fontmap); option=GetImageOption(image_info,"caption:language"); if (option != (const char *) NULL) pango_context_set_language(context,pango_language_from_string(option)); draw_info=CloneDrawInfo(image_info,(DrawInfo *) NULL); pango_context_set_base_dir(context,draw_info->direction == RightToLeftDirection ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR); switch (draw_info->gravity) { case NorthGravity: gravity=PANGO_GRAVITY_NORTH; break; case WestGravity: gravity=PANGO_GRAVITY_WEST; break; case EastGravity: gravity=PANGO_GRAVITY_EAST; break; case SouthGravity: gravity=PANGO_GRAVITY_SOUTH; break; default: gravity=PANGO_GRAVITY_AUTO; break; } pango_context_set_base_gravity(context,gravity); option=GetImageOption(image_info,"caption:gravity-hint"); if (option != (const char *) NULL) { if (LocaleCompare(option,"line") == 0) pango_context_set_gravity_hint(context,PANGO_GRAVITY_HINT_LINE); if (LocaleCompare(option,"natural") == 0) pango_context_set_gravity_hint(context,PANGO_GRAVITY_HINT_NATURAL); if (LocaleCompare(option,"strong") == 0) pango_context_set_gravity_hint(context,PANGO_GRAVITY_HINT_STRONG); } /* Configure layout. */ layout=pango_layout_new(context); option=GetImageOption(image_info,"caption:auto-dir"); if (option != (const char *) NULL) pango_layout_set_auto_dir(layout,1); option=GetImageOption(image_info,"caption:ellipsize"); if (option != (const char *) NULL) { if (LocaleCompare(option,"end") == 0) pango_layout_set_ellipsize(layout,PANGO_ELLIPSIZE_END); if (LocaleCompare(option,"middle") == 0) pango_layout_set_ellipsize(layout,PANGO_ELLIPSIZE_MIDDLE); if (LocaleCompare(option,"none") == 0) pango_layout_set_ellipsize(layout,PANGO_ELLIPSIZE_NONE); if (LocaleCompare(option,"start") == 0) pango_layout_set_ellipsize(layout,PANGO_ELLIPSIZE_START); } option=GetImageOption(image_info,"caption:justify"); if ((option != (const char *) NULL) && (IsMagickTrue(option) != MagickFalse)) pango_layout_set_justify(layout,1); option=GetImageOption(image_info,"caption:single-paragraph"); if ((option != (const char *) NULL) && (IsMagickTrue(option) != MagickFalse)) pango_layout_set_single_paragraph_mode(layout,1); option=GetImageOption(image_info,"caption:wrap"); if (option != (const char *) NULL) { if (LocaleCompare(option,"char") == 0) pango_layout_set_wrap(layout,PANGO_WRAP_CHAR); if (LocaleCompare(option,"word") == 0) pango_layout_set_wrap(layout,PANGO_WRAP_WORD); if (LocaleCompare(option,"word-char") == 0) pango_layout_set_wrap(layout,PANGO_WRAP_WORD_CHAR); } option=GetImageOption(image_info,"caption:indent"); if (option != (const char *) NULL) pango_layout_set_indent(layout,(StringToLong(option)*image->x_resolution* PANGO_SCALE+36)/72); switch (draw_info->align) { case CenterAlign: align=PANGO_ALIGN_CENTER; break; case RightAlign: align=PANGO_ALIGN_RIGHT; break; case LeftAlign: default: align=PANGO_ALIGN_LEFT; break; } if ((align != PANGO_ALIGN_CENTER) && (draw_info->direction == RightToLeftDirection)) align=(PangoAlignment) (PANGO_ALIGN_LEFT+PANGO_ALIGN_RIGHT-align); pango_layout_set_alignment(layout,align); description=pango_font_description_from_string(draw_info->font == (char *) NULL ? "helvetica" : draw_info->font); pango_font_description_set_size(description,PANGO_SCALE*draw_info->pointsize); pango_layout_set_font_description(layout,description); pango_font_description_free(description); property=InterpretImageProperties(image_info,image,image_info->filename); (void) SetImageProperty(image,"caption",property); property=DestroyString(property); caption=ConstantString(GetImageProperty(image,"caption")); /* Render caption. */ option=GetImageOption(image_info,"caption:markup"); if ((option != (const char *) NULL) && (IsMagickTrue(option) != MagickFalse)) pango_layout_set_markup(layout,caption,-1); else pango_layout_set_text(layout,caption,-1); pango_layout_context_changed(layout); page.x=0; page.y=0; if (image_info->page != (char *) NULL) (void) ParseAbsoluteGeometry(image_info->page,&page); if (image->columns == 0) { pango_layout_get_pixel_extents(layout,NULL,&extent); image->columns=extent.x+extent.width; } else { image->columns-=2*page.x; pango_layout_set_width(layout,(PANGO_SCALE*image->columns* image->x_resolution+36.0)/72.0); } if (image->rows == 0) { pango_layout_get_pixel_extents(layout,NULL,&extent); image->rows=extent.y+extent.height; } else { image->rows-=2*page.y; pango_layout_set_height(layout,(PANGO_SCALE*image->rows* image->y_resolution+36.0)/72.0); } /* Create canvas. */ canvas=(FT_Bitmap *) AcquireMagickMemory(sizeof(*canvas)); if (canvas == (FT_Bitmap *) NULL) { draw_info=DestroyDrawInfo(draw_info); ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); } canvas->width=image->columns; canvas->pitch=(canvas->width+3) & ~3; canvas->rows=image->rows; canvas->buffer=(unsigned char *) AcquireQuantumMemory(canvas->pitch, canvas->rows*sizeof(*canvas->buffer)); if (canvas->buffer == (unsigned char *) NULL) { draw_info=DestroyDrawInfo(draw_info); canvas=(FT_Bitmap *) RelinquishMagickMemory(canvas); ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); } canvas->num_grays=256; canvas->pixel_mode=ft_pixel_mode_grays; ResetMagickMemory(canvas->buffer,0x00,canvas->pitch*canvas->rows); pango_ft2_render_layout(canvas,layout,0,0); /* Convert caption to image. */ image->columns+=2*page.x; image->rows+=2*page.y; if (SetImageBackgroundColor(image) == MagickFalse) { draw_info=DestroyDrawInfo(draw_info); canvas->buffer=(unsigned char *) RelinquishMagickMemory(canvas->buffer); canvas=(FT_Bitmap *) RelinquishMagickMemory(canvas); caption=DestroyString(caption); image=DestroyImageList(image); return((Image *) NULL); } p=canvas->buffer; for (y=page.y; y < (ssize_t) (image->rows-page.y); y++) { register ssize_t x; q=GetAuthenticPixels(image,0,y,image->columns,1,exception); if (q == (PixelPacket *) NULL) break; q+=page.x; for (x=page.x; x < (ssize_t) (image->columns-page.x); x++) { MagickRealType fill_opacity; (void) GetFillColor(draw_info,x,y,&fill_color); fill_opacity=QuantumRange-(*p)/canvas->num_grays*(QuantumRange- fill_color.opacity); if (draw_info->text_antialias == MagickFalse) fill_opacity=fill_opacity >= 0.5 ? 1.0 : 0.0; MagickCompositeOver(&fill_color,fill_opacity,q,q->opacity,q); p++; q++; } for ( ; x < (ssize_t) ((canvas->width+3) & ~3); x++) p++; } /* Relinquish resources. */ draw_info=DestroyDrawInfo(draw_info); canvas->buffer=(unsigned char *) RelinquishMagickMemory(canvas->buffer); canvas=(FT_Bitmap *) RelinquishMagickMemory(canvas); caption=DestroyString(caption); return(GetFirstImageInList(image)); }
static GLboolean glgdGraphNodeDrawLabel(glgdGraph *graph, glgdNode *node) { int i; GLint width; GLuint texture; GLfloat s0, s1, t0, t1; GLfloat a; guint32 alpha, rgb, *t; guint8 *row, *row_end; PangoContext *pangoContext; PangoFontDescription *fontDesc; PangoLayout *layout; PangoRectangle extents; FT_Bitmap bitmap; glgdVec2 center, pnt[2]; glgdStroke *stroke; glgdTexture *tex; if (graph && graph->pangoFT2Context) { stroke = &graph->stroke; tex = &graph->textTexture; if (tex->width <= 0 || tex->height <= 0) { glgdTrace(1, "Invalid texture dimension (%d,%d)\n", tex->width, tex->height); return GL_FALSE; } /* Pango font description */ width = 10 * _PANGO_SCALE; pangoContext = gtk_widget_get_pango_context(graph->gtkWindow); fontDesc = pango_context_get_font_description(pangoContext); pango_font_description_set_size(fontDesc, PANGO_SCALE * width); pango_font_description_set_weight(fontDesc, PANGO_WEIGHT_NORMAL); pango_context_set_font_description(graph->pangoFT2Context, fontDesc); /* Text layout */ width = (int)graph->dim[0] * _PANGO_SCALE; layout = graph->layout; pango_layout_set_width(layout, PANGO_SCALE * width); pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER); pango_layout_set_text(layout, node->label, -1); pango_layout_get_extents(layout, NULL, &extents); if (extents.width == 0 || extents.height == 0) { glgdTrace(1, "Invalid extents (%d,%d)\n", extents.width, extents.height); return GL_FALSE; } /* Bitmap creation */ bitmap.rows = PANGO_PIXELS(extents.height); bitmap.width = PANGO_PIXELS(extents.width); if (bitmap.width > tex->width || bitmap.rows > tex->height) { return GL_FALSE; } bitmap.pitch = bitmap.width; bitmap.buffer = GLGD_MALLOC(bitmap.rows * bitmap.width); bitmap.num_grays = 256; bitmap.pixel_mode = ft_pixel_mode_grays; memset(bitmap.buffer, 0, bitmap.rows * bitmap.width); pango_ft2_render_layout(&bitmap, layout, PANGO_PIXELS(-extents.x), 0); #if !defined(GL_VERSION_1_2) && G_BYTE_ORDER == G_LITTLE_ENDIAN rgb =((guint32)(stroke->col[0] * 255.0)) | (((guint32)(stroke->col[1] * 255.0)) << 8) | (((guint32)(stroke->col[2] * 255.0)) << 16); #else rgb =(((guint32)(stroke->col[0] * 255.0)) << 24) | (((guint32)(stroke->col[1] * 255.0)) << 16) | (((guint32)(stroke->col[2] * 255.0)) << 8); #endif /* Bitmap transfer to <glgdTexture> */ a = stroke->col[3]; alpha = (guint32)(255.0 * a); row = bitmap.buffer + bitmap.rows * bitmap.width; row_end = bitmap.buffer; t = (guint32 *)tex->texels; if (graph->flags & GLGDGRAPH_FLAG_PANGOBOLD) { do { row -= bitmap.width; for (i=0; i<bitmap.width; i++) { #if !defined(GL_VERSION_1_2) && G_BYTE_ORDER == G_LITTLE_ENDIAN if (row[i] > 0) *t++ = rgb | (alpha << 24); else *t++ = rgb; #else if (row[i] > 0) *t++ = rgb | alpha; else *t++ = rgb; #endif } } while (row != row_end); } else { do { row -= bitmap.width; for (i=0; i<bitmap.width; i++) { #if !defined(GL_VERSION_1_2) && G_BYTE_ORDER == G_LITTLE_ENDIAN *t++ = rgb | ((guint32)(a * row[i]) << 24); #else *t++ = rgb | (guint32)(a * row[i]); #endif } } while (row != row_end); } glPixelStorei(GL_UNPACK_ALIGNMENT, 4); glBindTexture(GL_TEXTURE_2D, tex->name); #if !defined(GL_VERSION_1_2) glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width, bitmap.rows, GL_RGBA, GL_UNSIGNED_BYTE, tex->texels); #else glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width, bitmap.rows, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, tex->texels); #endif /* <glgdTexture> render */ s0 = 0.0; s1 = (GLdouble)bitmap.width / (GLdouble)tex->width; t0 = 0.0; t1 = (GLdouble)bitmap.rows / (GLdouble)tex->height; center[0] = node->pos[0] + GLGD_HALF(graph->dim[0]); center[1] = node->pos[1] + GLGD_HALF(graph->dim[1]); pnt[0][0] = center[0] - GLGD_HALF(bitmap.width / _PANGO_SCALE); pnt[0][1] = center[1] - GLGD_HALF(bitmap.rows / _PANGO_SCALE); pnt[1][0] = center[0] + GLGD_HALF(bitmap.width / _PANGO_SCALE); pnt[1][1] = center[1] + GLGD_HALF(bitmap.rows / _PANGO_SCALE); GLGD_FREE(bitmap.buffer); glColor3d(stroke->col[0], stroke->col[1], stroke->col[2]); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBindTexture(GL_TEXTURE_2D, tex->name); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glBegin(GL_QUADS); glTexCoord2f(s0, t0); glVertex3f(pnt[0][0], pnt[0][1], 0.0); glTexCoord2f(s0, t1); glVertex3f(pnt[0][0], pnt[1][1], 0.0); glTexCoord2f(s1, t1); glVertex3f(pnt[1][0], pnt[1][1], 0.0); glTexCoord2f(s1, t0); glVertex3f(pnt[1][0], pnt[0][1], 0.0); glEnd(); glDisable(GL_BLEND); glDisable(GL_TEXTURE_2D); return GL_TRUE; } return GL_FALSE; }
static void gl_pango_ft2_render_layout (PangoLayout *layout) { PangoRectangle logical_rect; FT_Bitmap bitmap; GLvoid *pixels; guint32 *p; GLfloat color[4]; guint32 rgb; GLfloat a; guint8 *row, *row_end; int i; pango_layout_get_extents (layout, NULL, &logical_rect); if (logical_rect.width == 0 || logical_rect.height == 0) return; bitmap.rows = PANGO_PIXELS (logical_rect.height); bitmap.width = PANGO_PIXELS (logical_rect.width); bitmap.pitch = bitmap.width; bitmap.buffer = g_malloc (bitmap.rows * bitmap.width); bitmap.num_grays = 256; bitmap.pixel_mode = ft_pixel_mode_grays; memset (bitmap.buffer, 0, bitmap.rows * bitmap.width); pango_ft2_render_layout (&bitmap, layout, PANGO_PIXELS (-logical_rect.x), 0); pixels = g_malloc (bitmap.rows * bitmap.width * 4); p = (guint32 *) pixels; glGetFloatv (GL_CURRENT_COLOR, color); #if !defined(GL_VERSION_1_2) && G_BYTE_ORDER == G_LITTLE_ENDIAN rgb = ((guint32) (color[0] * 255.0)) | (((guint32) (color[1] * 255.0)) << 8) | (((guint32) (color[2] * 255.0)) << 16); #else rgb = (((guint32) (color[0] * 255.0)) << 24) | (((guint32) (color[1] * 255.0)) << 16) | (((guint32) (color[2] * 255.0)) << 8); #endif a = color[3]; row = bitmap.buffer + bitmap.rows * bitmap.width; /* past-the-end */ row_end = bitmap.buffer; /* beginning */ if (a == 1.0) { do { row -= bitmap.width; for (i = 0; i < bitmap.width; i++) #if !defined(GL_VERSION_1_2) && G_BYTE_ORDER == G_LITTLE_ENDIAN *p++ = rgb | (((guint32) row[i]) << 24); #else *p++ = rgb | ((guint32) row[i]); #endif } while (row != row_end); } else { do { row -= bitmap.width; for (i = 0; i < bitmap.width; i++) #if !defined(GL_VERSION_1_2) && G_BYTE_ORDER == G_LITTLE_ENDIAN *p++ = rgb | (((guint32) (a * row[i])) << 24); #else *p++ = rgb | ((guint32) (a * row[i])); #endif } while (row != row_end); } glPixelStorei (GL_UNPACK_ALIGNMENT, 4); glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); #if !defined(GL_VERSION_1_2) glDrawPixels (bitmap.width, bitmap.rows, GL_RGBA, GL_UNSIGNED_BYTE, pixels); #else glDrawPixels (bitmap.width, bitmap.rows, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, pixels); #endif glDisable (GL_BLEND); g_free (bitmap.buffer); g_free (pixels); }