/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % M a g i c k Q u e r y M u l t i l i n e F o n t M e t r i c s % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % MagickQueryMultilineFontMetrics() returns a 13 element array representing the % following font metrics: % % Element Description % ------------------------------------------------- % 0 character width % 1 character height % 2 ascender % 3 descender % 4 text width % 5 text height % 6 maximum horizontal advance % 7 bounding box: x1 % 8 bounding box: y1 % 9 bounding box: x2 % 10 bounding box: y2 % 11 origin: x % 12 origin: y % % This method is like MagickQueryFontMetrics() but it returns the maximum text % width and height for multiple lines of text. % % The format of the MagickQueryFontMetrics method is: % % double *MagickQueryMultilineFontMetrics(MagickWand *wand, % const DrawingWand *drawing_wand,const char *text) % % A description of each parameter follows: % % o wand: the Magick wand. % % o drawing_wand: the drawing wand. % % o text: the text. % */ WandExport double *MagickQueryMultilineFontMetrics(MagickWand *wand, const DrawingWand *drawing_wand,const char *text) { double *font_metrics; DrawInfo *draw_info; MagickBooleanType status; TypeMetric metrics; assert(wand != (MagickWand *) NULL); assert(wand->signature == WandSignature); if (wand->debug != MagickFalse) (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand->name); assert(drawing_wand != (const DrawingWand *) NULL); if (wand->images == (Image *) NULL) { (void) ThrowMagickException(wand->exception,GetMagickModule(),WandError, "ContainsNoImages","`%s'",wand->name); return((double *) NULL); } font_metrics=(double *) AcquireQuantumMemory(13UL,sizeof(*font_metrics)); if (font_metrics == (double *) NULL) return((double *) NULL); draw_info=PeekDrawingWand(drawing_wand); if (draw_info == (DrawInfo *) NULL) { font_metrics=(double *) RelinquishMagickMemory(font_metrics); return((double *) NULL); } (void) CloneString(&draw_info->text,text); (void) ResetMagickMemory(&metrics,0,sizeof(metrics)); status=GetMultilineTypeMetrics(wand->images,draw_info,&metrics, wand->exception); draw_info=DestroyDrawInfo(draw_info); if (status == MagickFalse) { font_metrics=(double *) RelinquishMagickMemory(font_metrics); return((double *) NULL); } font_metrics[0]=metrics.pixels_per_em.x; font_metrics[1]=metrics.pixels_per_em.y; font_metrics[2]=metrics.ascent; font_metrics[3]=metrics.descent; font_metrics[4]=metrics.width; font_metrics[5]=metrics.height; font_metrics[6]=metrics.max_advance; font_metrics[7]=metrics.bounds.x1; font_metrics[8]=metrics.bounds.y1; font_metrics[9]=metrics.bounds.x2; font_metrics[10]=metrics.bounds.y2; font_metrics[11]=metrics.origin.x; font_metrics[12]=metrics.origin.y; return(font_metrics); }
Magick::Options::~Options() { // Destroy image info _imageInfo=DestroyImageInfo(_imageInfo); // Destroy quantization info _quantizeInfo=DestroyQuantizeInfo(_quantizeInfo); // Destroy drawing info _drawInfo=DestroyDrawInfo(_drawInfo); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + D e s t r o y W a n d C L I % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % DestroyMagickCLI() destorys everything in a CLI wand, including image_info % and any exceptions, if still present in the wand. % % The format of the NewMagickWand method is: % % MagickWand *DestroyMagickCLI() % Exception *exception) % */ WandExport MagickCLI *DestroyMagickCLI(MagickCLI *cli_wand) { Stack *node; assert(cli_wand != (MagickCLI *) NULL); assert(cli_wand->signature == WandSignature); assert(cli_wand->wand.signature == WandSignature); if (IfMagickTrue(cli_wand->wand.debug)) (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name); /* Destroy CLI part of MagickCLI */ if (cli_wand->draw_info != (DrawInfo *) NULL ) cli_wand->draw_info=DestroyDrawInfo(cli_wand->draw_info); if (cli_wand->quantize_info != (QuantizeInfo *) NULL ) cli_wand->quantize_info=DestroyQuantizeInfo(cli_wand->quantize_info); while(cli_wand->image_list_stack != (Stack *)NULL) { node=cli_wand->image_list_stack; cli_wand->image_list_stack=node->next; (void) DestroyImageList((Image *)node->data); (void) RelinquishMagickMemory(node); } while(cli_wand->image_info_stack != (Stack *)NULL) { node=cli_wand->image_info_stack; cli_wand->image_info_stack=node->next; (void) DestroyImageInfo((ImageInfo *)node->data); (void) RelinquishMagickMemory(node); } cli_wand->signature=(~WandSignature); /* Destroy Wand part MagickCLI */ cli_wand->wand.images=DestroyImageList(cli_wand->wand.images); if (cli_wand->wand.image_info != (ImageInfo *) NULL ) cli_wand->wand.image_info=DestroyImageInfo(cli_wand->wand.image_info); if (cli_wand->wand.exception != (ExceptionInfo *) NULL ) cli_wand->wand.exception=DestroyExceptionInfo(cli_wand->wand.exception); RelinquishWandId(cli_wand->wand.id); cli_wand->wand.signature=(~WandSignature); return((MagickCLI *)NULL); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e a d L A B E L I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ReadLABELImage() reads a LABEL image file and returns it. It % allocates the memory necessary for the new Image structure and returns a % pointer to the new image. % % The format of the ReadLABELImage method is: % % Image *ReadLABELImage(const ImageInfo *image_info, % ExceptionInfo *exception) % % A description of each parameter follows: % % o image_info: the image info. % % o exception: return any errors or warnings in this structure. % */ static Image *ReadLABELImage(const ImageInfo *image_info, ExceptionInfo *exception) { char geometry[MaxTextExtent], *property; const char *label; DrawInfo *draw_info; Image *image; MagickBooleanType status; TypeMetric metrics; size_t height, width; /* 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"); property=InterpretImageProperties(image_info,image,image_info->filename); (void) SetImageProperty(image,"label",property); property=DestroyString(property); label=GetImageProperty(image,"label"); draw_info=CloneDrawInfo(image_info,(DrawInfo *) NULL); draw_info->text=ConstantString(label); if (((image->columns != 0) || (image->rows != 0)) && (image_info->pointsize == 0.0)) { /* Fit label to canvas size. */ status=GetMultilineTypeMetrics(image,draw_info,&metrics); for ( ; status != MagickFalse; draw_info->pointsize*=2.0) { width=(size_t) floor(metrics.width+draw_info->stroke_width+0.5); height=(size_t) floor(metrics.height+draw_info->stroke_width+0.5); if (((image->columns != 0) && (width > (image->columns+1))) || ((image->rows != 0) && (height > (image->rows+1)))) break; status=GetMultilineTypeMetrics(image,draw_info,&metrics); } for ( ; status != MagickFalse; draw_info->pointsize--) { width=(size_t) floor(metrics.width+draw_info->stroke_width+0.5); height=(size_t) floor(metrics.height+draw_info->stroke_width+0.5); if ((image->columns != 0) && (width <= (image->columns+1)) && ((image->rows == 0) || (height <= (image->rows+1)))) break; if ((image->rows != 0) && (height <= (image->rows+1)) && ((image->columns == 0) || (width <= (image->columns+1)))) break; if (draw_info->pointsize < 2.0) break; status=GetMultilineTypeMetrics(image,draw_info,&metrics); } } status=GetMultilineTypeMetrics(image,draw_info,&metrics); if (status == MagickFalse) { InheritException(exception,&image->exception); image=DestroyImageList(image); return((Image *) NULL); } if (image->columns == 0) image->columns=(size_t) (metrics.width+draw_info->stroke_width+1.5); if (image->columns == 0) image->columns=(size_t) (draw_info->pointsize+ draw_info->stroke_width+1.5); if (draw_info->gravity == UndefinedGravity) { (void) FormatLocaleString(geometry,MaxTextExtent,"%+g%+g", -metrics.bounds.x1+draw_info->stroke_width/2.0,metrics.ascent+ draw_info->stroke_width/2.0); draw_info->geometry=AcquireString(geometry); } if (image->rows == 0) image->rows=(size_t) floor(metrics.height+draw_info->stroke_width+0.5); if (image->rows == 0) image->rows=(size_t) floor(draw_info->pointsize+draw_info->stroke_width+ 0.5); if (SetImageBackgroundColor(image) == MagickFalse) { InheritException(exception,&image->exception); image=DestroyImageList(image); return((Image *) NULL); } (void) AnnotateImage(image,draw_info); if (image_info->pointsize == 0.0) { char pointsize[MaxTextExtent]; (void) FormatLocaleString(pointsize,MaxTextExtent,"%.20g", draw_info->pointsize); (void) SetImageProperty(image,"label:pointsize",pointsize); } draw_info=DestroyDrawInfo(draw_info); return(GetFirstImageInList(image)); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e a d C A P T I O N I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ReadCAPTIONImage() reads a CAPTION image file and returns it. It % allocates the memory necessary for the new Image structure and returns a % pointer to the new image. % % The format of the ReadCAPTIONImage method is: % % Image *ReadCAPTIONImage(const ImageInfo *image_info, % ExceptionInfo *exception) % % A description of each parameter follows: % % o image_info: the image info. % % o exception: return any errors or warnings in this structure. % */ static Image *ReadCAPTIONImage(const ImageInfo *image_info, ExceptionInfo *exception) { char *caption, geometry[MaxTextExtent], *property; const char *gravity; DrawInfo *draw_info; Image *image; MagickBooleanType status; register long i; TypeMetric metrics; unsigned long height, width; /* 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); if (image->columns == 0) ThrowReaderException(OptionError,"MustSpecifyImageSize"); (void) ResetImagePage(image,"0x0+0+0"); /* Format caption. */ property=InterpretImageProperties(image_info,image,image_info->filename); (void) SetImageProperty(image,"caption",property); property=DestroyString(property); caption=ConstantString(GetImageProperty(image,"caption")); draw_info=CloneDrawInfo(image_info,(DrawInfo *) NULL); draw_info->text=ConstantString(caption); gravity=GetImageOption(image_info,"gravity"); if (gravity != (char *) NULL) draw_info->gravity=(GravityType) ParseMagickOption(MagickGravityOptions, MagickFalse,gravity); if ((*caption != '\0') && (image->rows != 0) && (image_info->pointsize == 0.0)) { char *text; /* Scale text to fit bounding box. */ for ( ; ; ) { text=AcquireString(caption); i=FormatMagickCaption(image,draw_info,&metrics,&text); (void) CloneString(&draw_info->text,text); text=DestroyString(text); (void) FormatMagickString(geometry,MaxTextExtent,"%+g%+g", -metrics.bounds.x1,metrics.ascent); if (draw_info->gravity == UndefinedGravity) (void) CloneString(&draw_info->geometry,geometry); status=GetMultilineTypeMetrics(image,draw_info,&metrics); width=(unsigned long) floor(metrics.width+draw_info->stroke_width+0.5); height=(unsigned long) floor(metrics.height+draw_info->stroke_width+ 0.5); if ((width > (image->columns+1)) || (height > (image->rows+1))) break; draw_info->pointsize*=2.0; } draw_info->pointsize/=2.0; for ( ; ; ) { text=AcquireString(caption); i=FormatMagickCaption(image,draw_info,&metrics,&text); (void) CloneString(&draw_info->text,text); text=DestroyString(text); (void) FormatMagickString(geometry,MaxTextExtent,"%+g%+g", -metrics.bounds.x1,metrics.ascent); if (draw_info->gravity == UndefinedGravity) (void) CloneString(&draw_info->geometry,geometry); status=GetMultilineTypeMetrics(image,draw_info,&metrics); width=(unsigned long) floor(metrics.width+draw_info->stroke_width+0.5); height=(unsigned long) floor(metrics.height+draw_info->stroke_width+ 0.5); if ((width > (image->columns+1)) || (height > (image->rows+1))) break; draw_info->pointsize++; } draw_info->pointsize--; } i=FormatMagickCaption(image,draw_info,&metrics,&caption); if (image->rows == 0) image->rows=(unsigned long) ((i+1)*(metrics.ascent-metrics.descent+ draw_info->stroke_width)+0.5); if (image->rows == 0) image->rows=(unsigned long) ((i+1)*draw_info->pointsize+ draw_info->stroke_width+0.5); if (SetImageBackgroundColor(image) == MagickFalse) { InheritException(exception,&image->exception); image=DestroyImageList(image); return((Image *) NULL); } /* Draw caption. */ (void) CloneString(&draw_info->text,caption); status=GetMultilineTypeMetrics(image,draw_info,&metrics); if (draw_info->gravity != UndefinedGravity) image->page.x=(long) (metrics.bounds.x1-draw_info->stroke_width/2.0); else { (void) FormatMagickString(geometry,MaxTextExtent,"%+g%+g", -metrics.bounds.x1+draw_info->stroke_width/2.0,metrics.ascent+ draw_info->stroke_width/2.0); (void) CloneString(&draw_info->geometry,geometry); } (void) AnnotateImage(image,draw_info); draw_info=DestroyDrawInfo(draw_info); caption=DestroyString(caption); return(GetFirstImageInList(image)); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e a d C A P T I O N I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ReadCAPTIONImage() reads a CAPTION image file and returns it. It % allocates the memory necessary for the new Image structure and returns a % pointer to the new image. % % The format of the ReadCAPTIONImage method is: % % Image *ReadCAPTIONImage(const ImageInfo *image_info, % ExceptionInfo *exception) % % A description of each parameter follows: % % o image_info: the image info. % % o exception: return any errors or warnings in this structure. % */ static Image *ReadCAPTIONImage(const ImageInfo *image_info, ExceptionInfo *exception) { char *caption, geometry[MaxTextExtent], *property, *text; const char *gravity, *option; DrawInfo *draw_info; Image *image; MagickBooleanType split, status; register ssize_t i; size_t height, width; TypeMetric metrics; /* 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"); /* Format caption. */ option=GetImageOption(image_info,"filename"); if (option == (const char *) NULL) property=InterpretImageProperties(image_info,image,image_info->filename); else if (LocaleNCompare(option,"caption:",8) == 0) property=InterpretImageProperties(image_info,image,option+8); else property=InterpretImageProperties(image_info,image,option); (void) SetImageProperty(image,"caption",property); property=DestroyString(property); caption=ConstantString(GetImageProperty(image,"caption")); draw_info=CloneDrawInfo(image_info,(DrawInfo *) NULL); (void) CloneString(&draw_info->text,caption); gravity=GetImageOption(image_info,"gravity"); if (gravity != (char *) NULL) draw_info->gravity=(GravityType) ParseCommandOption(MagickGravityOptions, MagickFalse,gravity); split=MagickFalse; status=MagickTrue; if (image->columns == 0) { text=AcquireString(caption); i=FormatMagickCaption(image,draw_info,split,&metrics,&text); (void) CloneString(&draw_info->text,text); text=DestroyString(text); (void) FormatLocaleString(geometry,MaxTextExtent,"%+g%+g", -metrics.bounds.x1,metrics.ascent); if (draw_info->gravity == UndefinedGravity) (void) CloneString(&draw_info->geometry,geometry); status=GetMultilineTypeMetrics(image,draw_info,&metrics); width=(size_t) floor(metrics.width+draw_info->stroke_width+0.5); image->columns=width; } if (image->rows == 0) { split=MagickTrue; text=AcquireString(caption); i=FormatMagickCaption(image,draw_info,split,&metrics,&text); (void) CloneString(&draw_info->text,text); text=DestroyString(text); (void) FormatLocaleString(geometry,MaxTextExtent,"%+g%+g", -metrics.bounds.x1,metrics.ascent); if (draw_info->gravity == UndefinedGravity) (void) CloneString(&draw_info->geometry,geometry); status=GetMultilineTypeMetrics(image,draw_info,&metrics); image->rows=(size_t) ((i+1)*(metrics.ascent-metrics.descent+ draw_info->interline_spacing+draw_info->stroke_width)+0.5); } if (status != MagickFalse) status=SetImageExtent(image,image->columns,image->rows); if (status == MagickFalse) { draw_info=DestroyDrawInfo(draw_info); InheritException(exception,&image->exception); return(DestroyImageList(image)); } if (SetImageBackgroundColor(image) == MagickFalse) { draw_info=DestroyDrawInfo(draw_info); InheritException(exception,&image->exception); image=DestroyImageList(image); return((Image *) NULL); } if (fabs(image_info->pointsize) < MagickEpsilon) { double high, low; /* Auto fit text into bounding box. */ for ( ; ; draw_info->pointsize*=2.0) { text=AcquireString(caption); i=FormatMagickCaption(image,draw_info,split,&metrics,&text); (void) CloneString(&draw_info->text,text); text=DestroyString(text); (void) FormatLocaleString(geometry,MaxTextExtent,"%+g%+g", -metrics.bounds.x1,metrics.ascent); if (draw_info->gravity == UndefinedGravity) (void) CloneString(&draw_info->geometry,geometry); status=GetMultilineTypeMetrics(image,draw_info,&metrics); (void) status; width=(size_t) floor(metrics.width+draw_info->stroke_width+0.5); height=(size_t) floor(metrics.height+draw_info->stroke_width+0.5); if ((image->columns != 0) && (image->rows != 0)) { if ((width >= image->columns) && (height >= image->rows)) break; } else if (((image->columns != 0) && (width >= image->columns)) || ((image->rows != 0) && (height >= image->rows))) break; } high=draw_info->pointsize; for (low=1.0; (high-low) > 0.5; ) { draw_info->pointsize=(low+high)/2.0; text=AcquireString(caption); i=FormatMagickCaption(image,draw_info,split,&metrics,&text); (void) CloneString(&draw_info->text,text); text=DestroyString(text); (void) FormatLocaleString(geometry,MaxTextExtent,"%+g%+g", -metrics.bounds.x1,metrics.ascent); if (draw_info->gravity == UndefinedGravity) (void) CloneString(&draw_info->geometry,geometry); (void) GetMultilineTypeMetrics(image,draw_info,&metrics); width=(size_t) floor(metrics.width+draw_info->stroke_width+0.5); height=(size_t) floor(metrics.height+draw_info->stroke_width+0.5); if ((image->columns != 0) && (image->rows != 0)) { if ((width < image->columns) && (height < image->rows)) low=draw_info->pointsize+0.5; else high=draw_info->pointsize-0.5; } else if (((image->columns != 0) && (width < image->columns)) || ((image->rows != 0) && (height < image->rows))) low=draw_info->pointsize+0.5; else high=draw_info->pointsize-0.5; } draw_info->pointsize=(low+high)/2.0-0.5; } /* Draw caption. */ i=FormatMagickCaption(image,draw_info,split,&metrics,&caption); (void) CloneString(&draw_info->text,caption); (void) FormatLocaleString(geometry,MaxTextExtent,"%+g%+g",MagickMax( draw_info->direction == RightToLeftDirection ? image->columns- metrics.bounds.x2 : -metrics.bounds.x1,0.0),draw_info->gravity == UndefinedGravity ? metrics.ascent : 0.0); draw_info->geometry=AcquireString(geometry); status=AnnotateImage(image,draw_info); if (image_info->pointsize == 0.0) { char pointsize[MaxTextExtent]; (void) FormatLocaleString(pointsize,MaxTextExtent,"%.20g", draw_info->pointsize); (void) SetImageProperty(image,"caption:pointsize",pointsize); } draw_info=DestroyDrawInfo(draw_info); caption=DestroyString(caption); if (status == MagickFalse) { image=DestroyImageList(image); return((Image *) NULL); } return(GetFirstImageInList(image)); }
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)); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e a d C A P T I O N I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ReadCAPTIONImage() reads a CAPTION image file and returns it. It % allocates the memory necessary for the new Image structure and returns a % pointer to the new image. % % The format of the ReadCAPTIONImage method is: % % Image *ReadCAPTIONImage(const ImageInfo *image_info, % ExceptionInfo *exception) % % A description of each parameter follows: % % o image_info: the image info. % % o exception: return any errors or warnings in this structure. % */ static Image *ReadCAPTIONImage(const ImageInfo *image_info, ExceptionInfo *exception) { char *caption, geometry[MaxTextExtent], *property; const char *gravity, *option; DrawInfo *draw_info; Image *image; MagickBooleanType status; register ssize_t i; size_t height, width; TypeMetric metrics; /* 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,exception); if (image->columns == 0) ThrowReaderException(OptionError,"MustSpecifyImageSize"); (void) ResetImagePage(image,"0x0+0+0"); /* Format caption. */ option=GetImageOption(image_info,"filename"); if (option == (const char *) NULL) property=InterpretImageProperties(image_info,image,image_info->filename, exception); else if (LocaleNCompare(option,"caption:",8) == 0) property=InterpretImageProperties(image_info,image,option+8,exception); else property=InterpretImageProperties(image_info,image,option,exception); (void) SetImageProperty(image,"caption",property,exception); property=DestroyString(property); caption=ConstantString(GetImageProperty(image,"caption",exception)); draw_info=CloneDrawInfo(image_info,(DrawInfo *) NULL); (void) CloneString(&draw_info->text,caption); gravity=GetImageOption(image_info,"gravity"); if (gravity != (char *) NULL) draw_info->gravity=(GravityType) ParseCommandOption(MagickGravityOptions, MagickFalse,gravity); if ((*caption != '\0') && (image->rows != 0) && (image_info->pointsize == 0.0)) { char *text; double high, low; /* Auto fit text into bounding box. */ for ( ; ; ) { text=AcquireString(caption); i=FormatMagickCaption(image,draw_info,MagickTrue,&metrics,&text, exception); (void) CloneString(&draw_info->text,text); text=DestroyString(text); (void) FormatLocaleString(geometry,MaxTextExtent,"%+g%+g", -metrics.bounds.x1,metrics.ascent); if (draw_info->gravity == UndefinedGravity) (void) CloneString(&draw_info->geometry,geometry); status=GetMultilineTypeMetrics(image,draw_info,&metrics,exception); (void) status; width=(size_t) floor(metrics.width+draw_info->stroke_width+0.5); height=(size_t) floor(metrics.height+draw_info->stroke_width+0.5); if ((width > image->columns) && (height > image->rows)) break; draw_info->pointsize*=2.0; } high=draw_info->pointsize/2.0; low=high/2.0; while ((high-low) > 1.0) { draw_info->pointsize=(low+high)/2.0; text=AcquireString(caption); i=FormatMagickCaption(image,draw_info,MagickTrue,&metrics,&text, exception); (void) CloneString(&draw_info->text,text); text=DestroyString(text); (void) FormatLocaleString(geometry,MaxTextExtent,"%+g%+g", -metrics.bounds.x1,metrics.ascent); if (draw_info->gravity == UndefinedGravity) (void) CloneString(&draw_info->geometry,geometry); status=GetMultilineTypeMetrics(image,draw_info,&metrics,exception); width=(size_t) floor(metrics.width+draw_info->stroke_width+0.5); height=(size_t) floor(metrics.height+draw_info->stroke_width+0.5); if ((width <= image->columns) && (height <= image->rows)) low=draw_info->pointsize+1.0; else high=draw_info->pointsize-1.0; } for (draw_info->pointsize=(low+high)/2.0; ; ) { text=AcquireString(caption); i=FormatMagickCaption(image,draw_info,MagickTrue,&metrics,&text, exception); (void) CloneString(&draw_info->text,text); text=DestroyString(text); (void) FormatLocaleString(geometry,MaxTextExtent,"%+g%+g", -metrics.bounds.x1,metrics.ascent); if (draw_info->gravity == UndefinedGravity) (void) CloneString(&draw_info->geometry,geometry); status=GetMultilineTypeMetrics(image,draw_info,&metrics,exception); width=(size_t) floor(metrics.width+draw_info->stroke_width+0.5); height=(size_t) floor(metrics.height+draw_info->stroke_width+0.5); if ((width <= image->columns) && (height <= image->rows)) break; draw_info->pointsize--; } draw_info->pointsize=floor(draw_info->pointsize); } i=FormatMagickCaption(image,draw_info,MagickTrue,&metrics,&caption,exception); if (image->rows == 0) image->rows=(size_t) ((i+1)*(metrics.ascent-metrics.descent+ draw_info->interline_spacing+draw_info->stroke_width)+0.5); if (image->rows == 0) image->rows=(size_t) ((i+1)*draw_info->pointsize+ draw_info->interline_spacing+draw_info->stroke_width+0.5); if (SetImageBackgroundColor(image,exception) == MagickFalse) { image=DestroyImageList(image); return((Image *) NULL); } /* Draw caption. */ (void) CloneString(&draw_info->text,caption); status=GetMultilineTypeMetrics(image,draw_info,&metrics,exception); if ((draw_info->gravity != UndefinedGravity) && (draw_info->direction != RightToLeftDirection)) image->page.x=(ssize_t) (metrics.bounds.x1-draw_info->stroke_width/2.0); else { (void) FormatLocaleString(geometry,MaxTextExtent,"%+g%+g", -metrics.bounds.x1+draw_info->stroke_width/2.0,metrics.ascent+ draw_info->stroke_width/2.0); if (draw_info->direction == RightToLeftDirection) (void) FormatLocaleString(geometry,MaxTextExtent,"%+g%+g", image->columns-(metrics.bounds.x2+draw_info->stroke_width/2.0), metrics.ascent+draw_info->stroke_width/2.0); draw_info->geometry=AcquireString(geometry); } status=AnnotateImage(image,draw_info,exception); draw_info=DestroyDrawInfo(draw_info); caption=DestroyString(caption); if (status == MagickFalse) { image=DestroyImageList(image); return((Image *) NULL); } return(GetFirstImageInList(image)); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e a d T T F I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ReadTTFImage() reads a TrueType font file and returns it. It % allocates the memory necessary for the new Image structure and returns a % pointer to the new image. % % The format of the ReadTTFImage method is: % % Image *ReadTTFImage(const ImageInfo *image_info,ExceptionInfo *exception) % % A description of each parameter follows: % % o image_info: the image info. % % o exception: return any errors or warnings in this structure. % */ static Image *ReadTTFImage(const ImageInfo *image_info,ExceptionInfo *exception) { char buffer[MaxTextExtent], *text; const char *Text = (char *) "abcdefghijklmnopqrstuvwxyz\n" "ABCDEFGHIJKLMNOPQRSTUVWXYZ\n" "0123456789.:,;(*!?}^)#${%^&[email protected]\n"; const TypeInfo *type_info; DrawInfo *draw_info; Image *image; MagickBooleanType status; PixelPacket background_color; register ssize_t i, x; register PixelPacket *q; ssize_t y; /* Open image file. */ 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); image->columns=800; image->rows=480; type_info=GetTypeInfo(image_info->filename,exception); if ((type_info != (const TypeInfo *) NULL) && (type_info->glyphs != (char *) NULL)) (void) CopyMagickString(image->filename,type_info->glyphs,MaxTextExtent); status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); if (status == MagickFalse) { image=DestroyImageList(image); return((Image *) NULL); } /* Color canvas with background color */ background_color=image_info->background_color; for (y=0; y < (ssize_t) image->rows; y++) { q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); if (q == (PixelPacket *) NULL) break; for (x=0; x < (ssize_t) image->columns; x++) *q++=background_color; if (SyncAuthenticPixels(image,exception) == MagickFalse) break; } (void) CopyMagickString(image->magick,image_info->magick,MaxTextExtent); (void) CopyMagickString(image->filename,image_info->filename,MaxTextExtent); /* Prepare drawing commands */ y=20; draw_info=CloneDrawInfo(image_info,(DrawInfo *) NULL); draw_info->font=AcquireString(image->filename); ConcatenateString(&draw_info->primitive,"push graphic-context\n"); (void) FormatLocaleString(buffer,MaxTextExtent," viewbox 0 0 %.20g %.20g\n", (double) image->columns,(double) image->rows); ConcatenateString(&draw_info->primitive,buffer); ConcatenateString(&draw_info->primitive," font-size 18\n"); (void) FormatLocaleString(buffer,MaxTextExtent," text 10,%.20g '",(double) y); ConcatenateString(&draw_info->primitive,buffer); text=EscapeString(Text,'"'); ConcatenateString(&draw_info->primitive,text); text=DestroyString(text); (void) FormatLocaleString(buffer,MaxTextExtent,"'\n"); ConcatenateString(&draw_info->primitive,buffer); y+=20*(ssize_t) MultilineCensus((char *) Text)+20; for (i=12; i <= 72; i+=6) { y+=i+12; ConcatenateString(&draw_info->primitive," font-size 18\n"); (void) FormatLocaleString(buffer,MaxTextExtent," text 10,%.20g '%.20g'\n", (double) y,(double) i); ConcatenateString(&draw_info->primitive,buffer); (void) FormatLocaleString(buffer,MaxTextExtent," font-size %.20g\n", (double) i); ConcatenateString(&draw_info->primitive,buffer); (void) FormatLocaleString(buffer,MaxTextExtent," text 50,%.20g " "'That which does not destroy me, only makes me stronger.'\n",(double) y); ConcatenateString(&draw_info->primitive,buffer); if (i >= 24) i+=6; } ConcatenateString(&draw_info->primitive,"pop graphic-context"); (void) DrawImage(image,draw_info); /* Relinquish resources. */ draw_info=DestroyDrawInfo(draw_info); (void) CloseBlob(image); return(GetFirstImageInList(image)); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e a d P A N G O I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ReadPANGOImage() reads an image in the Pango Markup Language Format. % % The format of the ReadPANGOImage method is: % % Image *ReadPANGOImage(const ImageInfo *image_info, % ExceptionInfo *exception) % % A description of each parameter follows: % % o image_info: the image info. % % o exception: return any errors or warnings in this structure. % */ static Image *ReadPANGOImage(const ImageInfo *image_info, ExceptionInfo *exception) { cairo_font_options_t *font_options; cairo_surface_t *surface; char *caption, *property; cairo_t *cairo_image; const char *option; DrawInfo *draw_info; Image *image; MagickBooleanType status; PangoAlignment align; PangoContext *context; PangoFontMap *fontmap; PangoGravity gravity; PangoLayout *layout; PangoRectangle extent; PixelInfo fill_color; RectangleInfo page; register unsigned char *p; size_t stride; ssize_t y; unsigned char *pixels; /* 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,exception); (void) ResetImagePage(image,"0x0+0+0"); /* Format caption. */ option=GetImageArtifact(image,"filename"); if (option == (const char *) NULL) property=InterpretImageProperties(image_info,image,image_info->filename, exception); else if (LocaleNCompare(option,"pango:",6) == 0) property=InterpretImageProperties(image_info,image,option+6,exception); else property=InterpretImageProperties(image_info,image,option,exception); (void) SetImageProperty(image,"caption",property,exception); property=DestroyString(property); caption=ConstantString(GetImageProperty(image,"caption",exception)); /* Get context. */ fontmap=pango_cairo_font_map_new(); pango_cairo_font_map_set_resolution(PANGO_CAIRO_FONT_MAP(fontmap), image->resolution.x == 0.0 ? 90.0 : image->resolution.x); font_options=cairo_font_options_create(); option=GetImageArtifact(image,"pango:hinting"); if (option != (const char *) NULL) { if (LocaleCompare(option,"none") != 0) cairo_font_options_set_hint_style(font_options,CAIRO_HINT_STYLE_NONE); if (LocaleCompare(option,"full") != 0) cairo_font_options_set_hint_style(font_options,CAIRO_HINT_STYLE_FULL); } context=pango_font_map_create_context(fontmap); pango_cairo_context_set_font_options(context,font_options); cairo_font_options_destroy(font_options); option=GetImageArtifact(image,"pango: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 NorthWestGravity: case WestGravity: case SouthWestGravity: { gravity=PANGO_GRAVITY_WEST; break; } case NorthEastGravity: case EastGravity: case SouthEastGravity: { 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=GetImageArtifact(image,"pango: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=GetImageArtifact(image,"pango:auto-dir"); if (option != (const char *) NULL) pango_layout_set_auto_dir(layout,1); option=GetImageArtifact(image,"pango: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=GetImageArtifact(image,"pango:justify"); if (IfMagickTrue(IsStringTrue(option))) pango_layout_set_justify(layout,1); option=GetImageArtifact(image,"pango:single-paragraph"); if (IfMagickTrue(IsStringTrue(option))) pango_layout_set_single_paragraph_mode(layout,1); option=GetImageArtifact(image,"pango: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=GetImageArtifact(image,"pango:indent"); if (option != (const char *) NULL) pango_layout_set_indent(layout,(int) ((StringToLong(option)* (image->resolution.x == 0.0 ? 90.0 : image->resolution.x)*PANGO_SCALE+36)/ 90.0+0.5)); switch (draw_info->align) { case CenterAlign: align=PANGO_ALIGN_CENTER; break; case RightAlign: align=PANGO_ALIGN_RIGHT; break; case LeftAlign: align=PANGO_ALIGN_LEFT; break; default: { if (draw_info->gravity == CenterGravity) { align=PANGO_ALIGN_CENTER; break; } 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); if (draw_info->font != (char *) NULL) { PangoFontDescription *description; /* Set font. */ description=pango_font_description_from_string(draw_info->font); pango_font_description_set_size(description,(int) (PANGO_SCALE* draw_info->pointsize+0.5)); pango_layout_set_font_description(layout,description); pango_font_description_free(description); } option=GetImageArtifact(image,"pango:markup"); if ((option != (const char *) NULL) && (IsStringTrue(option) == MagickFalse)) pango_layout_set_text(layout,caption,-1); else { GError *error; error=(GError *) NULL; if (pango_parse_markup(caption,-1,0,NULL,NULL,NULL,&error) == 0) (void) ThrowMagickException(exception,GetMagickModule(),CoderError, error->message,"`%s'",image_info->filename); pango_layout_set_markup(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_extents(layout,NULL,&extent); image->columns=(extent.x+extent.width+PANGO_SCALE/2)/PANGO_SCALE+2*page.x; } else { image->columns-=2*page.x; pango_layout_set_width(layout,(int) ((PANGO_SCALE*image->columns* (image->resolution.x == 0.0 ? 90.0 : image->resolution.x)+45.0)/90.0+ 0.5)); } if (image->rows == 0) { pango_layout_get_extents(layout,NULL,&extent); image->rows=(extent.y+extent.height+PANGO_SCALE/2)/PANGO_SCALE+2*page.y; } else { image->rows-=2*page.y; pango_layout_set_height(layout,(int) ((PANGO_SCALE*image->rows* (image->resolution.y == 0.0 ? 90.0 : image->resolution.y)+45.0)/90.0+ 0.5)); } /* Render markup. */ stride=(size_t) cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, image->columns); pixels=(unsigned char *) AcquireQuantumMemory(image->rows,stride* sizeof(*pixels)); if (pixels == (unsigned char *) NULL) { draw_info=DestroyDrawInfo(draw_info); caption=DestroyString(caption); ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); } surface=cairo_image_surface_create_for_data(pixels,CAIRO_FORMAT_ARGB32, image->columns,image->rows,stride); cairo_image=cairo_create(surface); cairo_set_operator(cairo_image,CAIRO_OPERATOR_CLEAR); cairo_paint(cairo_image); cairo_set_operator(cairo_image,CAIRO_OPERATOR_OVER); cairo_translate(cairo_image,page.x,page.y); pango_cairo_show_layout(cairo_image,layout); cairo_destroy(cairo_image); cairo_surface_destroy(surface); g_object_unref(layout); g_object_unref(fontmap); /* Convert surface to image. */ (void) SetImageBackgroundColor(image,exception); p=pixels; GetPixelInfo(image,&fill_color); for (y=0; y < (ssize_t) image->rows; y++) { register Quantum *q; register ssize_t x; q=GetAuthenticPixels(image,0,y,image->columns,1,exception); if (q == (Quantum *) NULL) break; for (x=0; x < (ssize_t) image->columns; x++) { double gamma; fill_color.blue=(double) ScaleCharToQuantum(*p++); fill_color.green=(double) ScaleCharToQuantum(*p++); fill_color.red=(double) ScaleCharToQuantum(*p++); fill_color.alpha=(double) ScaleCharToQuantum(*p++); /* Disassociate alpha. */ gamma=1.0-QuantumScale*fill_color.alpha; gamma=PerceptibleReciprocal(gamma); fill_color.blue*=gamma; fill_color.green*=gamma; fill_color.red*=gamma; CompositePixelOver(image,&fill_color,fill_color.alpha,q,(double) GetPixelAlpha(image,q),q); q+=GetPixelChannels(image); } if (SyncAuthenticPixels(image,exception) == MagickFalse) break; if (image->previous == (Image *) NULL) { status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, image->rows); if (status == MagickFalse) break; } } /* Relinquish resources. */ pixels=(unsigned char *) RelinquishMagickMemory(pixels); draw_info=DestroyDrawInfo(draw_info); caption=DestroyString(caption); return(GetFirstImageInList(image)); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e a d M V G I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Method ReadMVGImage creates a gradient image and initializes it to % the X server color range as specified by the filename. It allocates the % memory necessary for the new Image structure and returns a pointer to the % new image. % % The format of the ReadMVGImage method is: % % Image *ReadMVGImage(const ImageInfo *image_info,ExceptionInfo *exception) % % A description of each parameter follows: % % o image: Method ReadMVGImage returns a pointer to the image after % creating it. A null image is returned if there is a memory shortage % or if the image cannot be read. % % o image_info: Specifies a pointer to a ImageInfo structure. % % o exception: return any errors or warnings in this structure. % % */ static Image *ReadMVGImage(const ImageInfo *image_info,ExceptionInfo *exception) { #define BoundingBox "viewbox" DrawInfo *draw_info; Image *image; size_t length; unsigned int status; /* Open image. */ assert(image_info != (const ImageInfo *) NULL); assert(image_info->signature == MagickSignature); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickSignature); image=AllocateImage(image_info); status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); if (status == False) ThrowReaderException(FileOpenError,UnableToOpenFile,image); if ((image->columns == 0) || (image->rows == 0)) { char primitive[MaxTextExtent]; register char *p; SegmentInfo bounds; /* Determine size of image canvas. */ while (ReadBlobString(image,primitive) != (char *) NULL) { for (p=primitive; (*p == ' ') || (*p == '\t'); p++); if (LocaleNCompare(BoundingBox,p,strlen(BoundingBox)) != 0) continue; (void) sscanf(p,"viewbox %lf %lf %lf %lf",&bounds.x1,&bounds.y1, &bounds.x2,&bounds.y2); image->columns=(unsigned long) (bounds.x2-bounds.x1+0.5); image->rows=(unsigned long) (bounds.y2-bounds.y1+0.5); break; } } if ((image->columns == 0) || (image->rows == 0)) ThrowReaderException(OptionError,MustSpecifyImageSize,image); if (CheckImagePixelLimits(image, exception) != MagickPass) ThrowReaderException(ResourceLimitError,ImagePixelLimitExceeded,image); /* Render drawing. */ (void) SetImage(image,OpaqueOpacity); draw_info=CloneDrawInfo(image_info,(DrawInfo *) NULL); draw_info->fill=image_info->pen; if (GetBlobStreamData(image)) draw_info->primitive=AllocateString((char *) GetBlobStreamData(image)); else draw_info->primitive=(char *) FileToBlob(image->filename,&length,exception); if (draw_info->primitive == (char *) NULL) { DestroyDrawInfo(draw_info); CloseBlob(image); return (Image *) NULL; } (void) DrawImage(image,draw_info); DestroyDrawInfo(draw_info); CloseBlob(image); return(image); }
MagickExport MagickBooleanType GradientImage(Image *image, const GradientType type,const SpreadMethod method, const PixelPacket *start_color,const PixelPacket *stop_color) { DrawInfo *draw_info; GradientInfo *gradient; MagickBooleanType status; register ssize_t i; /* Set gradient start-stop end points. */ assert(image != (const Image *) NULL); assert(image->signature == MagickSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); assert(start_color != (const PixelPacket *) NULL); assert(stop_color != (const PixelPacket *) NULL); draw_info=AcquireDrawInfo(); gradient=(&draw_info->gradient); gradient->type=type; gradient->bounding_box.width=image->columns; gradient->bounding_box.height=image->rows; gradient->gradient_vector.x2=(double) image->columns-1.0; gradient->gradient_vector.y2=(double) image->rows-1.0; if ((type == LinearGradient) && (gradient->gradient_vector.y2 != 0.0)) gradient->gradient_vector.x2=0.0; gradient->center.x=(double) gradient->gradient_vector.x2/2.0; gradient->center.y=(double) gradient->gradient_vector.y2/2.0; gradient->radius=MagickMax(gradient->center.x,gradient->center.y); gradient->spread=method; /* Define the gradient to fill between the stops. */ gradient->number_stops=2; gradient->stops=(StopInfo *) AcquireQuantumMemory(gradient->number_stops, sizeof(*gradient->stops)); if (gradient->stops == (StopInfo *) NULL) ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", image->filename); (void) ResetMagickMemory(gradient->stops,0,gradient->number_stops* sizeof(*gradient->stops)); for (i=0; i < (ssize_t) gradient->number_stops; i++) GetMagickPixelPacket(image,&gradient->stops[i].color); SetMagickPixelPacket(image,start_color,(IndexPacket *) NULL, &gradient->stops[0].color); gradient->stops[0].offset=0.0; SetMagickPixelPacket(image,stop_color,(IndexPacket *) NULL, &gradient->stops[1].color); gradient->stops[1].offset=1.0; /* Draw a gradient on the image. */ status=DrawGradientImage(image,draw_info); draw_info=DestroyDrawInfo(draw_info); if ((start_color->opacity == OpaqueOpacity) && (stop_color->opacity == OpaqueOpacity)) image->matte=MagickFalse; if ((IsGrayPixel(start_color) != MagickFalse) && (IsGrayPixel(stop_color) != MagickFalse)) image->type=GrayscaleType; return(status); }
MagickExport MagickBooleanType GradientImage(Image *image, const GradientType type,const SpreadMethod method,const StopInfo *stops, const size_t number_stops,ExceptionInfo *exception) { const char *artifact; DrawInfo *draw_info; GeometryInfo geometry_info; GradientInfo *gradient; MagickBooleanType status; MagickStatusType flags; /* Set gradient start-stop end points. */ assert(image != (const Image *) NULL); assert(image->signature == MagickCoreSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); assert(stops != (const StopInfo *) NULL); assert(number_stops > 0); draw_info=AcquireDrawInfo(); gradient=(&draw_info->gradient); gradient->type=type; gradient->bounding_box.width=image->columns; gradient->bounding_box.height=image->rows; artifact=GetImageArtifact(image,"gradient:bounding-box"); if (artifact != (const char *) NULL) (void) ParseAbsoluteGeometry(artifact,&gradient->bounding_box); gradient->gradient_vector.x2=(double) image->columns-1.0; gradient->gradient_vector.y2=(double) image->rows-1.0; if ((type == LinearGradient) && (gradient->gradient_vector.y2 != 0.0)) gradient->gradient_vector.x2=0.0; artifact=GetImageArtifact(image,"gradient:vector"); if (artifact != (const char *) NULL) { flags=ParseGeometry(artifact,&geometry_info); gradient->gradient_vector.x1=geometry_info.rho; if ((flags & SigmaValue) != 0) gradient->gradient_vector.y1=geometry_info.sigma; if ((flags & XiValue) != 0) gradient->gradient_vector.x2=geometry_info.xi; if ((flags & PsiValue) != 0) gradient->gradient_vector.y2=geometry_info.psi; } gradient->center.x=(double) gradient->gradient_vector.x2/2.0; gradient->center.y=(double) gradient->gradient_vector.y2/2.0; artifact=GetImageArtifact(image,"gradient:center"); if (artifact != (const char *) NULL) { flags=ParseGeometry(artifact,&geometry_info); gradient->center.x=geometry_info.rho; if ((flags & SigmaValue) != 0) gradient->center.y=geometry_info.sigma; } gradient->radius=MagickMax(gradient->center.x,gradient->center.y); artifact=GetImageArtifact(image,"gradient:radius"); if (artifact != (const char *) NULL) gradient->radius=StringToDouble(artifact,(char **) NULL); gradient->spread=method; /* Define the gradient to fill between the stops. */ gradient->number_stops=number_stops; gradient->stops=(StopInfo *) AcquireQuantumMemory(gradient->number_stops, sizeof(*gradient->stops)); if (gradient->stops == (StopInfo *) NULL) ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", image->filename); (void) CopyMagickMemory(gradient->stops,stops,(size_t) number_stops* sizeof(*stops)); /* Draw a gradient on the image. */ status=DrawGradientImage(image,draw_info,exception); draw_info=DestroyDrawInfo(draw_info); return(status); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e a d T T F I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ReadTTFImage() reads a TrueType font file and returns it. It % allocates the memory necessary for the new Image structure and returns a % pointer to the new image. % % The format of the ReadTTFImage method is: % % Image *ReadTTFImage(const ImageInfo *image_info,ExceptionInfo *exception) % % A description of each parameter follows: % % o image_info: The image info. % % o exception: return any errors or warnings in this structure. % % */ static Image *ReadTTFImage(const ImageInfo *image_info,ExceptionInfo *exception) { char buffer[MaxTextExtent]; const char *Text = (char *) "The quick brown fox jumps over the lazy dog 0123456789\n" "ABCDEFGHIJKLMNOPQRSTUVWXYZ &#~\"\\'(-`_^@)=+\260\n" "$\243^\250*\265\371%!\247:/;.,?<> " "\342\352\356\373\364\344\353\357\366\374\377\340\371\351\350\347 "; const TypeInfo *type_info; DrawInfo *draw_info; Image *image; long y; MagickBooleanType status; PixelPacket background_color; register long i, x; register PixelPacket *q; /* Open image file. */ 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=AllocateImage(image_info); image->columns=800; image->rows=480; type_info=GetTypeInfo(image_info->filename,exception); if ((type_info != (const TypeInfo *) NULL) && (type_info->glyphs != (char *) NULL)) (void) CopyMagickString(image->filename,type_info->glyphs,MaxTextExtent); status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); if (status == MagickFalse) { image=DestroyImageList(image); return((Image *) NULL); } /* Color canvas with background color */ background_color=image_info->background_color; for (y=0; y < (long) image->rows; y++) { q=SetImagePixels(image,0,y,image->columns,1); if (q == (PixelPacket *) NULL) break; for (x=0; x < (long) image->columns; x++) *q++=background_color; if (SyncImagePixels(image) == MagickFalse) break; } (void) CopyMagickString(image->magick,image_info->magick,MaxTextExtent); (void) CopyMagickString(image->filename,image_info->filename,MaxTextExtent); /* Prepare drawing commands */ y=20; draw_info=CloneDrawInfo(image_info,(DrawInfo *) NULL); draw_info->font=AcquireString(image->filename); draw_info->fill=image_info->pen; ConcatenateString(&draw_info->primitive,"push graphic-context\n"); (void) FormatMagickString(buffer,MaxTextExtent," viewbox 0 0 %lu %lu\n", image->columns,image->rows); ConcatenateString(&draw_info->primitive,buffer); ConcatenateString(&draw_info->primitive," font-size 18\n"); (void) FormatMagickString(buffer,MaxTextExtent," text 10,%ld '",y); ConcatenateString(&draw_info->primitive,buffer); ConcatenateString(&draw_info->primitive,Text); (void) FormatMagickString(buffer,MaxTextExtent,"'\n"); ConcatenateString(&draw_info->primitive,buffer); y+=20*MultilineCensus((char *) Text)+20; for (i=12; i <= 72; i+=6) { y+=i+12; ConcatenateString(&draw_info->primitive," font-size 18\n"); (void) FormatMagickString(buffer,MaxTextExtent," text 10,%ld '%ld'\n",y,i); ConcatenateString(&draw_info->primitive,buffer); (void) FormatMagickString(buffer,MaxTextExtent," font-size %ld\n",i); ConcatenateString(&draw_info->primitive,buffer); (void) FormatMagickString(buffer,MaxTextExtent," text 50,%ld " "'That which does not destroy me, only makes me stronger.'\n",y); ConcatenateString(&draw_info->primitive,buffer); if (i >= 24) i+=6; } ConcatenateString(&draw_info->primitive,"pop graphic-context"); (void) DrawImage(image,draw_info); /* Free resources. */ draw_info=DestroyDrawInfo(draw_info); CloseBlob(image); return(GetFirstImageInList(image)); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e a d L A B E L I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ReadLABELImage() reads a LABEL image file and returns it. It % allocates the memory necessary for the new Image structure and returns a % pointer to the new image. % % The format of the ReadLABELImage method is: % % Image *ReadLABELImage(const ImageInfo *image_info, % ExceptionInfo *exception) % % A description of each parameter follows: % % o image_info: the image info. % % o exception: return any errors or warnings in this structure. % */ static Image *ReadLABELImage(const ImageInfo *image_info, ExceptionInfo *exception) { char geometry[MaxTextExtent], *property; const char *label; DrawInfo *draw_info; Image *image; MagickBooleanType status; TypeMetric metrics; size_t height, width; /* 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"); property=InterpretImageProperties(image_info,image,image_info->filename); (void) SetImageProperty(image,"label",property); property=DestroyString(property); label=GetImageProperty(image,"label"); draw_info=CloneDrawInfo(image_info,(DrawInfo *) NULL); draw_info->text=ConstantString(label); status=GetMultilineTypeMetrics(image,draw_info,&metrics); if (image->columns == 0) { (void) FormatLocaleString(geometry,MaxTextExtent,"%+g%+g", -metrics.bounds.x1,metrics.ascent); if (draw_info->gravity == UndefinedGravity) (void) CloneString(&draw_info->geometry,geometry); status=GetMultilineTypeMetrics(image,draw_info,&metrics); (void) status; image->columns=(size_t) floor(metrics.width+draw_info->stroke_width+0.5); } if (image->rows == 0) { (void) FormatLocaleString(geometry,MaxTextExtent,"%+g%+g", -metrics.bounds.x1,metrics.ascent); if (draw_info->gravity == UndefinedGravity) (void) CloneString(&draw_info->geometry,geometry); status=GetMultilineTypeMetrics(image,draw_info,&metrics); image->rows=(size_t) floor(metrics.height+draw_info->stroke_width+0.5); } if (image_info->pointsize == 0.0) { double high, low; /* Auto fit text into bounding box. */ for ( ; ; draw_info->pointsize*=2.0) { (void) FormatLocaleString(geometry,MaxTextExtent,"%+g%+g", -metrics.bounds.x1,metrics.ascent); if (draw_info->gravity == UndefinedGravity) (void) CloneString(&draw_info->geometry,geometry); status=GetMultilineTypeMetrics(image,draw_info,&metrics); (void) status; width=(size_t) floor(metrics.width+draw_info->stroke_width+0.5); height=(size_t) floor(metrics.height+draw_info->stroke_width+0.5); if ((width >= image->columns) && (height >= image->rows)) break; if ((width >= (image->columns << 1)) || (height >= (image->rows << 1))) break; } high=draw_info->pointsize/2.0; for (low=high/2.0; (high-low) > 1.0; ) { draw_info->pointsize=(low+high)/2.0; (void) FormatLocaleString(geometry,MaxTextExtent,"%+g%+g", -metrics.bounds.x1,metrics.ascent); if (draw_info->gravity == UndefinedGravity) (void) CloneString(&draw_info->geometry,geometry); status=GetMultilineTypeMetrics(image,draw_info,&metrics); width=(size_t) floor(metrics.width+draw_info->stroke_width+0.5); height=(size_t) floor(metrics.height+draw_info->stroke_width+0.5); if ((width <= image->columns) && (height <= image->rows)) low=draw_info->pointsize+1.0; else high=draw_info->pointsize-1.0; } for (draw_info->pointsize=(low+high)/2.0; (high-low) > 1.0; ) { (void) FormatLocaleString(geometry,MaxTextExtent,"%+g%+g", -metrics.bounds.x1,metrics.ascent); if (draw_info->gravity == UndefinedGravity) (void) CloneString(&draw_info->geometry,geometry); status=GetMultilineTypeMetrics(image,draw_info,&metrics); width=(size_t) floor(metrics.width+draw_info->stroke_width+0.5); height=(size_t) floor(metrics.height+draw_info->stroke_width+0.5); if ((width <= image->columns) && (height <= image->rows)) break; draw_info->pointsize--; } draw_info->pointsize=floor(draw_info->pointsize+0.5); } status=GetMultilineTypeMetrics(image,draw_info,&metrics); if (status == MagickFalse) { InheritException(exception,&image->exception); image=DestroyImageList(image); return((Image *) NULL); } if (draw_info->gravity == UndefinedGravity) { (void) FormatLocaleString(geometry,MaxTextExtent,"%+g%+g", -metrics.bounds.x1+draw_info->stroke_width/2.0,metrics.ascent+ draw_info->stroke_width/2.0); (void) CloneString(&draw_info->geometry,geometry); } if (draw_info->direction == RightToLeftDirection) { if (draw_info->direction == RightToLeftDirection) (void) FormatLocaleString(geometry,MaxTextExtent,"%+g%+g", image->columns-(metrics.bounds.x2+draw_info->stroke_width/2.0), metrics.ascent+draw_info->stroke_width/2.0); (void) CloneString(&draw_info->geometry,geometry); } if (SetImageBackgroundColor(image) == MagickFalse) { InheritException(exception,&image->exception); image=DestroyImageList(image); return((Image *) NULL); } (void) AnnotateImage(image,draw_info); if (image_info->pointsize == 0.0) { char pointsize[MaxTextExtent]; (void) FormatLocaleString(pointsize,MaxTextExtent,"%.20g", draw_info->pointsize); (void) SetImageProperty(image,"label:pointsize",pointsize); } draw_info=DestroyDrawInfo(draw_info); return(GetFirstImageInList(image)); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e a d T E X T I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ReadTEXTImage() reads a text file and returns it as an image. It % allocates the memory necessary for the new Image structure and returns a % pointer to the new image. % % The format of the ReadTEXTImage method is: % % Image *ReadTEXTImage(const ImageInfo *image_info,Image *image, % char *text,ExceptionInfo *exception) % % A description of each parameter follows: % % o image_info: the image info. % % o image: the image. % % o text: the text storage buffer. % % o exception: return any errors or warnings in this structure. % */ static Image *ReadTEXTImage(const ImageInfo *image_info,Image *image, char *text,ExceptionInfo *exception) { char filename[MaxTextExtent], geometry[MaxTextExtent], *p; DrawInfo *draw_info; Image *texture; MagickBooleanType status; PointInfo delta; RectangleInfo page; ssize_t offset; TypeMetric metrics; /* Open image file. */ 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); /* Set the page geometry. */ delta.x=DefaultResolution; delta.y=DefaultResolution; if ((image->x_resolution == 0.0) || (image->y_resolution == 0.0)) { GeometryInfo geometry_info; MagickStatusType flags; flags=ParseGeometry(PSDensityGeometry,&geometry_info); image->x_resolution=geometry_info.rho; image->y_resolution=geometry_info.sigma; if ((flags & SigmaValue) == 0) image->y_resolution=image->x_resolution; } page.width=612; page.height=792; page.x=43; page.y=43; if (image_info->page != (char *) NULL) (void) ParseAbsoluteGeometry(image_info->page,&page); /* Initialize Image structure. */ image->columns=(size_t) floor((((double) page.width*image->x_resolution)/ delta.x)+0.5); image->rows=(size_t) floor((((double) page.height*image->y_resolution)/ delta.y)+0.5); image->page.x=0; image->page.y=0; texture=(Image *) NULL; if (image_info->texture != (char *) NULL) { ImageInfo *read_info; read_info=CloneImageInfo(image_info); SetImageInfoBlob(read_info,(void *) NULL,0); (void) CopyMagickString(read_info->filename,image_info->texture, MaxTextExtent); texture=ReadImage(read_info,exception); read_info=DestroyImageInfo(read_info); } /* Annotate the text image. */ (void) SetImageBackgroundColor(image); draw_info=CloneDrawInfo(image_info,(DrawInfo *) NULL); (void) CloneString(&draw_info->text,image_info->filename); (void) FormatLocaleString(geometry,MaxTextExtent,"0x0%+ld%+ld",(long) page.x, (long) page.y); (void) CloneString(&draw_info->geometry,geometry); status=GetTypeMetrics(image,draw_info,&metrics); if (status == MagickFalse) ThrowReaderException(TypeError,"UnableToGetTypeMetrics"); page.y=(ssize_t) ceil((double) page.y+metrics.ascent-0.5); (void) FormatLocaleString(geometry,MaxTextExtent,"0x0%+ld%+ld",(long) page.x, (long) page.y); (void) CloneString(&draw_info->geometry,geometry); (void) CopyMagickString(filename,image_info->filename,MaxTextExtent); if (*draw_info->text != '\0') *draw_info->text='\0'; p=text; for (offset=2*page.y; p != (char *) NULL; ) { /* Annotate image with text. */ (void) ConcatenateString(&draw_info->text,text); (void) ConcatenateString(&draw_info->text,"\n"); offset+=(ssize_t) (metrics.ascent-metrics.descent); if (image->previous == (Image *) NULL) { status=SetImageProgress(image,LoadImageTag,offset,image->rows); if (status == MagickFalse) break; } p=ReadBlobString(image,text); if ((offset < (ssize_t) image->rows) && (p != (char *) NULL)) continue; if (texture != (Image *) NULL) { MagickProgressMonitor progress_monitor; progress_monitor=SetImageProgressMonitor(image, (MagickProgressMonitor) NULL,image->client_data); (void) TextureImage(image,texture); (void) SetImageProgressMonitor(image,progress_monitor, image->client_data); } (void) AnnotateImage(image,draw_info); if (p == (char *) NULL) break; /* Page is full-- allocate next image structure. */ *draw_info->text='\0'; offset=2*page.y; AcquireNextImage(image_info,image); if (GetNextImageInList(image) == (Image *) NULL) { image=DestroyImageList(image); return((Image *) NULL); } image->next->columns=image->columns; image->next->rows=image->rows; image=SyncNextImageInList(image); (void) CopyMagickString(image->filename,filename,MaxTextExtent); (void) SetImageBackgroundColor(image); status=SetImageProgress(image,LoadImagesTag,TellBlob(image), GetBlobSize(image)); if (status == MagickFalse) break; } if (texture != (Image *) NULL) { MagickProgressMonitor progress_monitor; progress_monitor=SetImageProgressMonitor(image, (MagickProgressMonitor) NULL,image->client_data); (void) TextureImage(image,texture); (void) SetImageProgressMonitor(image,progress_monitor,image->client_data); } (void) AnnotateImage(image,draw_info); if (texture != (Image *) NULL) texture=DestroyImage(texture); draw_info=DestroyDrawInfo(draw_info); (void) CloseBlob(image); return(GetFirstImageInList(image)); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e a d M V G I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ReadMVGImage creates a gradient image and initializes it to % the X server color range as specified by the filename. It allocates the % memory necessary for the new Image structure and returns a pointer to the % new image. % % The format of the ReadMVGImage method is: % % Image *ReadMVGImage(const ImageInfo *image_info,ExceptionInfo *exception) % % A description of each parameter follows: % % o image_info: the image info. % % o exception: return any errors or warnings in this structure. % */ static Image *ReadMVGImage(const ImageInfo *image_info,ExceptionInfo *exception) { #define BoundingBox "viewbox" DrawInfo *draw_info; Image *image; MagickBooleanType status; /* Open image. */ 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); status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); if (status == MagickFalse) { image=DestroyImageList(image); return((Image *) NULL); } if ((image->columns == 0) || (image->rows == 0)) { char primitive[MaxTextExtent]; register char *p; SegmentInfo bounds; /* Determine size of image canvas. */ while (ReadBlobString(image,primitive) != (char *) NULL) { for (p=primitive; (*p == ' ') || (*p == '\t'); p++) ; if (LocaleNCompare(BoundingBox,p,strlen(BoundingBox)) != 0) continue; (void) sscanf(p,"viewbox %lf %lf %lf %lf",&bounds.x1,&bounds.y1, &bounds.x2,&bounds.y2); image->columns=(size_t) floor((bounds.x2-bounds.x1)+0.5); image->rows=(size_t) floor((bounds.y2-bounds.y1)+0.5); break; } } if ((image->columns == 0) || (image->rows == 0)) ThrowReaderException(OptionError,"MustSpecifyImageSize"); draw_info=CloneDrawInfo(image_info,(DrawInfo *) NULL); draw_info->affine.sx=image->x_resolution == 0.0 ? 1.0 : image->x_resolution/ DefaultResolution; draw_info->affine.sy=image->y_resolution == 0.0 ? 1.0 : image->y_resolution/ DefaultResolution; image->columns=(size_t) (draw_info->affine.sx*image->columns); image->rows=(size_t) (draw_info->affine.sy*image->rows); if (SetImageBackgroundColor(image) == MagickFalse) { InheritException(exception,&image->exception); image=DestroyImageList(image); return((Image *) NULL); } /* Render drawing. */ if (GetBlobStreamData(image) == (unsigned char *) NULL) draw_info->primitive=FileToString(image->filename,~0UL,exception); else { draw_info->primitive=(char *) AcquireMagickMemory(GetBlobSize(image)+1); if (draw_info->primitive != (char *) NULL) { CopyMagickMemory(draw_info->primitive,GetBlobStreamData(image), GetBlobSize(image)); draw_info->primitive[GetBlobSize(image)]='\0'; } } (void) DrawImage(image,draw_info); draw_info=DestroyDrawInfo(draw_info); (void) CloseBlob(image); return(GetFirstImageInList(image)); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e a d L A B E L I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ReadLABELImage() reads a LABEL image file and returns it. It % allocates the memory necessary for the new Image structure and returns a % pointer to the new image. % % The format of the ReadLABELImage method is: % % Image *ReadLABELImage(const ImageInfo *image_info, % ExceptionInfo *exception) % % A description of each parameter follows: % % o image_info: the image info. % % o exception: return any errors or warnings in this structure. % */ static Image *ReadLABELImage(const ImageInfo *image_info, ExceptionInfo *exception) { char geometry[MagickPathExtent], *property; const char *label; DrawInfo *draw_info; Image *image; MagickBooleanType status; TypeMetric metrics; size_t height, width; /* Initialize Image structure. */ assert(image_info != (const ImageInfo *) NULL); assert(image_info->signature == MagickCoreSignature); if (image_info->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", image_info->filename); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickCoreSignature); image=AcquireImage(image_info,exception); (void) ResetImagePage(image,"0x0+0+0"); property=InterpretImageProperties((ImageInfo *) image_info,image, image_info->filename,exception); (void) SetImageProperty(image,"label",property,exception); property=DestroyString(property); label=GetImageProperty(image,"label",exception); draw_info=CloneDrawInfo(image_info,(DrawInfo *) NULL); draw_info->text=ConstantString(label); metrics.width=0; metrics.ascent=0.0; status=GetMultilineTypeMetrics(image,draw_info,&metrics,exception); if ((image->columns == 0) && (image->rows == 0)) { image->columns=(size_t) (metrics.width+draw_info->stroke_width+0.5); image->rows=(size_t) floor(metrics.height+draw_info->stroke_width+0.5); } else if (((image->columns == 0) || (image->rows == 0)) || (fabs(image_info->pointsize) < MagickEpsilon)) { double high, low; /* Auto fit text into bounding box. */ for ( ; ; draw_info->pointsize*=2.0) { (void) FormatLocaleString(geometry,MagickPathExtent,"%+g%+g", -metrics.bounds.x1,metrics.ascent); if (draw_info->gravity == UndefinedGravity) (void) CloneString(&draw_info->geometry,geometry); status=GetMultilineTypeMetrics(image,draw_info,&metrics,exception); width=(size_t) floor(metrics.width+draw_info->stroke_width+0.5); height=(size_t) floor(metrics.height+draw_info->stroke_width+0.5); if ((image->columns != 0) && (image->rows != 0)) { if ((width >= image->columns) && (height >= image->rows)) break; } else if (((image->columns != 0) && (width >= image->columns)) || ((image->rows != 0) && (height >= image->rows))) break; } high=draw_info->pointsize; for (low=1.0; (high-low) > 0.5; ) { draw_info->pointsize=(low+high)/2.0; (void) FormatLocaleString(geometry,MagickPathExtent,"%+g%+g", -metrics.bounds.x1,metrics.ascent); if (draw_info->gravity == UndefinedGravity) (void) CloneString(&draw_info->geometry,geometry); status=GetMultilineTypeMetrics(image,draw_info,&metrics,exception); width=(size_t) floor(metrics.width+draw_info->stroke_width+0.5); height=(size_t) floor(metrics.height+draw_info->stroke_width+0.5); if ((image->columns != 0) && (image->rows != 0)) { if ((width < image->columns) && (height < image->rows)) low=draw_info->pointsize+0.5; else high=draw_info->pointsize-0.5; } else if (((image->columns != 0) && (width < image->columns)) || ((image->rows != 0) && (height < image->rows))) low=draw_info->pointsize+0.5; else high=draw_info->pointsize-0.5; } draw_info->pointsize=(low+high)/2.0-0.5; } status=GetMultilineTypeMetrics(image,draw_info,&metrics,exception); if (status == MagickFalse) { draw_info=DestroyDrawInfo(draw_info); image=DestroyImageList(image); return((Image *) NULL); } if (image->columns == 0) image->columns=(size_t) (metrics.width+draw_info->stroke_width+0.5); if (image->columns == 0) image->columns=(size_t) (draw_info->pointsize+draw_info->stroke_width+0.5); if (image->rows == 0) image->rows=(size_t) (metrics.ascent-metrics.descent+ draw_info->stroke_width+0.5); if (image->rows == 0) image->rows=(size_t) (draw_info->pointsize+draw_info->stroke_width+0.5); status=SetImageExtent(image,image->columns,image->rows,exception); if (status == MagickFalse) { draw_info=DestroyDrawInfo(draw_info); return(DestroyImageList(image)); } if (SetImageBackgroundColor(image,exception) == MagickFalse) { draw_info=DestroyDrawInfo(draw_info); image=DestroyImageList(image); return((Image *) NULL); } /* Draw label. */ (void) FormatLocaleString(geometry,MagickPathExtent,"%+g%+g", draw_info->direction == RightToLeftDirection ? image->columns- metrics.bounds.x2 : 0.0,draw_info->gravity == UndefinedGravity ? metrics.ascent : 0.0); draw_info->geometry=AcquireString(geometry); status=AnnotateImage(image,draw_info,exception); if (image_info->pointsize == 0.0) { char pointsize[MagickPathExtent]; (void) FormatLocaleString(pointsize,MagickPathExtent,"%.20g", draw_info->pointsize); (void) SetImageProperty(image,"label:pointsize",pointsize,exception); } draw_info=DestroyDrawInfo(draw_info); if (status == MagickFalse) { image=DestroyImageList(image); return((Image *) NULL); } return(GetFirstImageInList(image)); }
MagickExport Image *MontageImageList(const ImageInfo *image_info, const MontageInfo *montage_info,const Image *images,ExceptionInfo *exception) { #define MontageImageTag "Montage/Image" #define TileImageTag "Tile/Image" char tile_geometry[MagickPathExtent], *title; const char *value; DrawInfo *draw_info; FrameInfo frame_info; Image *image, **image_list, **master_list, *montage, *texture, *tile_image, *thumbnail; ImageInfo *clone_info; MagickBooleanType concatenate, proceed, status; MagickOffsetType tiles; MagickProgressMonitor progress_monitor; MagickStatusType flags; register ssize_t i; RectangleInfo bounds, geometry, extract_info; size_t border_width, extent, height, images_per_page, max_height, number_images, number_lines, sans, tiles_per_column, tiles_per_page, tiles_per_row, title_offset, total_tiles, width; ssize_t bevel_width, tile, x, x_offset, y, y_offset; TypeMetric metrics; /* Create image tiles. */ assert(images != (Image *) NULL); assert(images->signature == MagickCoreSignature); if (images->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename); assert(montage_info != (MontageInfo *) NULL); assert(montage_info->signature == MagickCoreSignature); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickCoreSignature); number_images=GetImageListLength(images); master_list=ImageListToArray(images,exception); image_list=master_list; image=image_list[0]; if (master_list == (Image **) NULL) ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); thumbnail=NewImageList(); for (i=0; i < (ssize_t) number_images; i++) { image=CloneImage(image_list[i],0,0,MagickTrue,exception); if (image == (Image *) NULL) break; (void) ParseAbsoluteGeometry("0x0+0+0",&image->page); progress_monitor=SetImageProgressMonitor(image,(MagickProgressMonitor) NULL, image->client_data); flags=ParseRegionGeometry(image,montage_info->geometry,&geometry,exception); thumbnail=ThumbnailImage(image,geometry.width,geometry.height,exception); if (thumbnail == (Image *) NULL) break; image_list[i]=thumbnail; (void) SetImageProgressMonitor(image,progress_monitor,image->client_data); proceed=SetImageProgress(image,TileImageTag,(MagickOffsetType) i, number_images); if (proceed == MagickFalse) break; image=DestroyImage(image); } if (i < (ssize_t) number_images) { if (thumbnail == (Image *) NULL) i--; for (tile=0; (ssize_t) tile <= i; tile++) if (image_list[tile] != (Image *) NULL) image_list[tile]=DestroyImage(image_list[tile]); master_list=(Image **) RelinquishMagickMemory(master_list); return((Image *) NULL); } /* Sort image list by increasing tile number. */ for (i=0; i < (ssize_t) number_images; i++) if (image_list[i]->scene == 0) break; if (i == (ssize_t) number_images) qsort((void *) image_list,(size_t) number_images,sizeof(*image_list), SceneCompare); /* Determine tiles per row and column. */ tiles_per_column=(size_t) sqrt((double) number_images); tiles_per_row=(size_t) ceil((double) number_images/tiles_per_column); x_offset=0; y_offset=0; if (montage_info->tile != (char *) NULL) GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset, &tiles_per_column,&tiles_per_row); /* Determine tile sizes. */ concatenate=MagickFalse; SetGeometry(image_list[0],&extract_info); extract_info.x=(ssize_t) montage_info->border_width; extract_info.y=(ssize_t) montage_info->border_width; if (montage_info->geometry != (char *) NULL) { /* Initialize tile geometry. */ flags=GetGeometry(montage_info->geometry,&extract_info.x,&extract_info.y, &extract_info.width,&extract_info.height); concatenate=((flags & RhoValue) == 0) && ((flags & SigmaValue) == 0) ? MagickTrue : MagickFalse; } border_width=montage_info->border_width; bevel_width=0; (void) ResetMagickMemory(&frame_info,0,sizeof(frame_info)); if (montage_info->frame != (char *) NULL) { char absolute_geometry[MagickPathExtent]; frame_info.width=extract_info.width; frame_info.height=extract_info.height; (void) FormatLocaleString(absolute_geometry,MagickPathExtent,"%s!", montage_info->frame); flags=ParseMetaGeometry(absolute_geometry,&frame_info.outer_bevel, &frame_info.inner_bevel,&frame_info.width,&frame_info.height); if ((flags & HeightValue) == 0) frame_info.height=frame_info.width; if ((flags & XiValue) == 0) frame_info.outer_bevel=(ssize_t) frame_info.width/2-1; if ((flags & PsiValue) == 0) frame_info.inner_bevel=frame_info.outer_bevel; frame_info.x=(ssize_t) frame_info.width; frame_info.y=(ssize_t) frame_info.height; bevel_width=(ssize_t) MagickMax(frame_info.inner_bevel, frame_info.outer_bevel); border_width=(size_t) MagickMax((ssize_t) frame_info.width, (ssize_t) frame_info.height); } for (i=0; i < (ssize_t) number_images; i++) { if (image_list[i]->columns > extract_info.width) extract_info.width=image_list[i]->columns; if (image_list[i]->rows > extract_info.height) extract_info.height=image_list[i]->rows; } /* Initialize draw attributes. */ clone_info=CloneImageInfo(image_info); clone_info->background_color=montage_info->background_color; clone_info->border_color=montage_info->border_color; draw_info=CloneDrawInfo(clone_info,(DrawInfo *) NULL); if (montage_info->font != (char *) NULL) (void) CloneString(&draw_info->font,montage_info->font); if (montage_info->pointsize != 0.0) draw_info->pointsize=montage_info->pointsize; draw_info->gravity=CenterGravity; draw_info->stroke=montage_info->stroke; draw_info->fill=montage_info->fill; draw_info->text=AcquireString(""); (void) GetTypeMetrics(image_list[0],draw_info,&metrics,exception); texture=NewImageList(); if (montage_info->texture != (char *) NULL) { (void) CopyMagickString(clone_info->filename,montage_info->texture, MagickPathExtent); texture=ReadImage(clone_info,exception); } /* Determine the number of lines in an next label. */ title=InterpretImageProperties(clone_info,image_list[0],montage_info->title, exception); title_offset=0; if (montage_info->title != (char *) NULL) title_offset=(size_t) (2*(metrics.ascent-metrics.descent)* MultilineCensus(title)+2*extract_info.y); number_lines=0; for (i=0; i < (ssize_t) number_images; i++) { value=GetImageProperty(image_list[i],"label",exception); if (value == (const char *) NULL) continue; if (MultilineCensus(value) > number_lines) number_lines=MultilineCensus(value); } /* Allocate next structure. */ tile_image=AcquireImage((ImageInfo *) NULL,exception); montage=AcquireImage(clone_info,exception); montage->background_color=montage_info->background_color; montage->scene=0; images_per_page=(number_images-1)/(tiles_per_row*tiles_per_column)+1; tiles=0; total_tiles=(size_t) number_images; for (i=0; i < (ssize_t) images_per_page; i++) { /* Determine bounding box. */ tiles_per_page=tiles_per_row*tiles_per_column; x_offset=0; y_offset=0; if (montage_info->tile != (char *) NULL) GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset, &sans,&sans); tiles_per_page=tiles_per_row*tiles_per_column; y_offset+=(ssize_t) title_offset; max_height=0; bounds.width=0; bounds.height=0; width=0; for (tile=0; tile < (ssize_t) tiles_per_page; tile++) { if (tile < (ssize_t) number_images) { width=concatenate != MagickFalse ? image_list[tile]->columns : extract_info.width; if (image_list[tile]->rows > max_height) max_height=image_list[tile]->rows; } x_offset+=(ssize_t) (width+2*(extract_info.x+border_width)); if (x_offset > (ssize_t) bounds.width) bounds.width=(size_t) x_offset; if (((tile+1) == (ssize_t) tiles_per_page) || (((tile+1) % tiles_per_row) == 0)) { x_offset=0; if (montage_info->tile != (char *) NULL) GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y, &sans,&sans); height=concatenate != MagickFalse ? max_height : extract_info.height; y_offset+=(ssize_t) (height+(extract_info.y+(ssize_t) border_width)*2+ (metrics.ascent-metrics.descent+4)*number_lines+ (montage_info->shadow != MagickFalse ? 4 : 0)); if (y_offset > (ssize_t) bounds.height) bounds.height=(size_t) y_offset; max_height=0; } } if (montage_info->shadow != MagickFalse) bounds.width+=4; /* Initialize montage image. */ (void) CopyMagickString(montage->filename,montage_info->filename, MagickPathExtent); montage->columns=(size_t) MagickMax((ssize_t) bounds.width,1); montage->rows=(size_t) MagickMax((ssize_t) bounds.height,1); (void) SetImageBackgroundColor(montage,exception); /* Set montage geometry. */ montage->montage=AcquireString((char *) NULL); tile=0; extent=1; while (tile < MagickMin((ssize_t) tiles_per_page,(ssize_t) number_images)) { extent+=strlen(image_list[tile]->filename)+1; tile++; } montage->directory=(char *) AcquireQuantumMemory(extent, sizeof(*montage->directory)); if ((montage->montage == (char *) NULL) || (montage->directory == (char *) NULL)) { if (montage->montage != (char *) NULL) montage->montage=(char *) RelinquishMagickMemory(montage->montage); if (montage->directory != (char *) NULL) montage->directory=(char *) RelinquishMagickMemory( montage->directory); ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); } x_offset=0; y_offset=0; if (montage_info->tile != (char *) NULL) GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset, &sans,&sans); y_offset+=(ssize_t) title_offset; (void) FormatLocaleString(montage->montage,MagickPathExtent, "%.20gx%.20g%+.20g%+.20g",(double) (extract_info.width+ (extract_info.x+border_width)*2),(double) (extract_info.height+ (extract_info.y+border_width)*2+(double) ((metrics.ascent- metrics.descent+4)*number_lines+(montage_info->shadow != MagickFalse ? 4 : 0))),(double) x_offset,(double) y_offset); *montage->directory='\0'; tile=0; while (tile < MagickMin((ssize_t) tiles_per_page,(ssize_t) number_images)) { (void) ConcatenateMagickString(montage->directory, image_list[tile]->filename,extent); (void) ConcatenateMagickString(montage->directory,"\n",extent); tile++; } progress_monitor=SetImageProgressMonitor(montage,(MagickProgressMonitor) NULL,montage->client_data); if (texture != (Image *) NULL) (void) TextureImage(montage,texture,exception); if (montage_info->title != (char *) NULL) { DrawInfo *draw_clone_info; TypeMetric tile_metrics; /* Annotate composite image with title. */ draw_clone_info=CloneDrawInfo(image_info,draw_info); draw_clone_info->gravity=CenterGravity; draw_clone_info->pointsize*=2.0; (void) GetTypeMetrics(image_list[0],draw_clone_info,&tile_metrics, exception); (void) FormatLocaleString(tile_geometry,MagickPathExtent, "%.20gx%.20g%+.20g%+.20g",(double) montage->columns,(double) (tile_metrics.ascent-tile_metrics.descent),0.0, (double) extract_info.y+4); (void) CloneString(&draw_clone_info->geometry,tile_geometry); (void) CloneString(&draw_clone_info->text,title); (void) AnnotateImage(montage,draw_clone_info,exception); draw_clone_info=DestroyDrawInfo(draw_clone_info); } (void) SetImageProgressMonitor(montage,progress_monitor, montage->client_data); /* Copy tile to the composite. */ x_offset=0; y_offset=0; if (montage_info->tile != (char *) NULL) GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset, &sans,&sans); x_offset+=extract_info.x; y_offset+=(ssize_t) title_offset+extract_info.y; max_height=0; status=MagickTrue; for (tile=0; tile < MagickMin((ssize_t) tiles_per_page,(ssize_t) number_images); tile++) { /* Copy this tile to the composite. */ image=CloneImage(image_list[tile],0,0,MagickTrue,exception); if (image == (Image *) NULL) ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); progress_monitor=SetImageProgressMonitor(image, (MagickProgressMonitor) NULL,image->client_data); width=concatenate != MagickFalse ? image->columns : extract_info.width; if (image->rows > max_height) max_height=image->rows; height=concatenate != MagickFalse ? max_height : extract_info.height; if (border_width != 0) { Image *border_image; RectangleInfo border_info; /* Put a border around the image. */ border_info.width=border_width; border_info.height=border_width; if (montage_info->frame != (char *) NULL) { border_info.width=(width-image->columns+1)/2; border_info.height=(height-image->rows+1)/2; } border_image=BorderImage(image,&border_info,image->compose,exception); if (border_image != (Image *) NULL) { image=DestroyImage(image); image=border_image; } if ((montage_info->frame != (char *) NULL) && (image->compose == DstOutCompositeOp)) { (void) SetPixelChannelMask(image,AlphaChannel); (void) NegateImage(image,MagickFalse,exception); (void) SetPixelChannelMask(image,DefaultChannels); } } /* Gravitate as specified by the tile gravity. */ tile_image->columns=width; tile_image->rows=height; tile_image->gravity=montage_info->gravity; if (image->gravity != UndefinedGravity) tile_image->gravity=image->gravity; (void) FormatLocaleString(tile_geometry,MagickPathExtent, "%.20gx%.20g+0+0",(double) image->columns,(double) image->rows); flags=ParseGravityGeometry(tile_image,tile_geometry,&geometry,exception); x=(ssize_t) (geometry.x+border_width); y=(ssize_t) (geometry.y+border_width); if ((montage_info->frame != (char *) NULL) && (bevel_width > 0)) { FrameInfo frame_clone; Image *frame_image; /* Put an ornamental border around this tile. */ frame_clone=frame_info; frame_clone.width=width+2*frame_info.width; frame_clone.height=height+2*frame_info.height; value=GetImageProperty(image,"label",exception); if (value != (const char *) NULL) frame_clone.height+=(size_t) ((metrics.ascent-metrics.descent+4)* MultilineCensus(value)); frame_image=FrameImage(image,&frame_clone,image->compose,exception); if (frame_image != (Image *) NULL) { image=DestroyImage(image); image=frame_image; } x=0; y=0; } if (LocaleCompare(image->magick,"NULL") != 0) { /* Composite background with tile. */ if (montage_info->shadow != MagickFalse) { Image *shadow_image; /* Shadow image. */ (void) QueryColorCompliance("#0000",AllCompliance, &image->background_color,exception); shadow_image=ShadowImage(image,80.0,2.0,5,5,exception); if (shadow_image != (Image *) NULL) { (void) CompositeImage(shadow_image,image,OverCompositeOp, MagickTrue,0,0,exception); image=DestroyImage(image); image=shadow_image; } } (void) CompositeImage(montage,image,image->compose,MagickTrue, x_offset+x,y_offset+y,exception); value=GetImageProperty(image,"label",exception); if (value != (const char *) NULL) { /* Annotate composite tile with label. */ (void) FormatLocaleString(tile_geometry,MagickPathExtent, "%.20gx%.20g%+.20g%+.20g",(double) ((montage_info->frame ? image->columns : width)-2*border_width),(double) (metrics.ascent-metrics.descent+4)*MultilineCensus(value), (double) (x_offset+border_width),(double) ((montage_info->frame ? y_offset+height+border_width+4 : y_offset+extract_info.height+border_width+ (montage_info->shadow != MagickFalse ? 4 : 0))+bevel_width)); (void) CloneString(&draw_info->geometry,tile_geometry); (void) CloneString(&draw_info->text,value); (void) AnnotateImage(montage,draw_info,exception); } } x_offset+=(ssize_t) (width+2*(extract_info.x+border_width)); if (((tile+1) == (ssize_t) tiles_per_page) || (((tile+1) % tiles_per_row) == 0)) { x_offset=extract_info.x; y_offset+=(ssize_t) (height+(extract_info.y+border_width)*2+ (metrics.ascent-metrics.descent+4)*number_lines+ (montage_info->shadow != MagickFalse ? 4 : 0)); max_height=0; } if (images->progress_monitor != (MagickProgressMonitor) NULL) { proceed=SetImageProgress(image,MontageImageTag,tiles,total_tiles); if (proceed == MagickFalse) status=MagickFalse; } image_list[tile]=DestroyImage(image_list[tile]); image=DestroyImage(image); tiles++; } (void) status; if ((i+1) < (ssize_t) images_per_page) { /* Allocate next image structure. */ AcquireNextImage(clone_info,montage,exception); if (GetNextImageInList(montage) == (Image *) NULL) { montage=DestroyImageList(montage); return((Image *) NULL); } montage=GetNextImageInList(montage); montage->background_color=montage_info->background_color; image_list+=tiles_per_page; number_images-=tiles_per_page; } } tile_image=DestroyImage(tile_image); if (texture != (Image *) NULL) texture=DestroyImage(texture); title=DestroyString(title); master_list=(Image **) RelinquishMagickMemory(master_list); draw_info=DestroyDrawInfo(draw_info); clone_info=DestroyImageInfo(clone_info); return(GetFirstImageInList(montage)); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e a d T X T I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Method ReadTXTImage reads a text file and returns it as an image. It % allocates the memory necessary for the new Image structure and returns a % pointer to the new image. % % The format of the ReadTXTImage method is: % % Image *ReadTXTImage(const ImageInfo *image_info,ExceptionInfo *exception) % % A description of each parameter follows: % % o image: Method ReadTXTImage returns a pointer to the image after % reading. A null image is returned if there is a memory shortage or if % the image cannot be read. % % o image_info: Specifies a pointer to a ImageInfo structure. % % o exception: return any errors or warnings in this structure. % % */ static Image *ReadTXTImage(const ImageInfo *image_info,ExceptionInfo *exception) { char filename[MaxTextExtent], geometry[MaxTextExtent], *p, text[MaxTextExtent]; double dx_resolution, dy_resolution; DrawInfo *draw_info; Image *image, *texture; long count, offset; RectangleInfo page; TypeMetric metrics; unsigned int status; int logging; /* Open image file. */ assert(image_info != (const ImageInfo *) NULL); assert(image_info->signature == MagickSignature); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickSignature); logging = LogMagickEvent(CoderEvent,GetMagickModule(),"enter"); image=AllocateImage(image_info); status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); if (status == False) ThrowReaderException(FileOpenError,UnableToOpenFile,image); p = ReadBlobString(image,text); status = IsTXT((unsigned char *)p,strlen(p)); if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(), "File type: %d", status); if(status) { unsigned x,y; unsigned x_min,x_max,y_curr; int ch; unsigned long max,i; char NumOfPlanes; unsigned char *BImgBuff; magick_uint16_t *WImgBuff; magick_uint32_t *DImgBuff; magick_uint32_t R,G,B,A; const PixelPacket *q; ImportPixelAreaOptions import_options; (void) SeekBlob(image,0,SEEK_SET); A=0; x=0; y=0; max=0; switch(status) { case TXT_GM8B_HEX: case TXT_GM8B_HEX_Q: max=255; break; case TXT_GM16B_HEX: case TXT_GM16B_HEX_Q: max=65535; break; case TXT_GM32B_HEX: case TXT_GM32B_HEX_Q: max=65536; break; } if(!strncmp(p,"# ImageMagick pixel enumeration:",32)) { if(sscanf(p+32,"%u,%u,%u",&x_min,&y_curr,&x_max)==3) { if(strstr(p+32,",rgb")!=NULL) { x = x_min-1; y = y_curr-1; max = x_max; } if(strstr(p+32,",rgba")!=NULL) { status = IMAGEMAGICK_TXT_Q; } } } ch=0; if(x==0 && y==0) while(!EOFBlob(image)) /* auto detect sizes and num of planes */ { while(!(ch>='0' && ch<='9')) { /* go to the begin of number */ ch = ReadBlobByte(image); if(ch==EOF) goto EndReading; if(ch=='#') {readln(image,&ch); continue;} if(ch==0 || ch>128 || (ch>='a' && ch<='z') || (ch>='A' && ch<='Z')) { TXT_FAIL: /* not a text data */ ThrowReaderException(CoderError,ImageTypeNotSupported,image); } } /* x,y: (R,G,B) */ i = ReadInt(image,&ch); /* x */ if(i>x) x=i; while(ch!=',') { ch = ReadBlobByte(image); if(ch==EOF) break; if(ch==10 || ch==13) goto TXT_FAIL; } ch=0; i=ReadInt(image,&ch); /* y */ if(i>y) y=i; while(ch!=':') { ch = ReadBlobByte(image); if(ch==10 || ch==13) goto TXT_FAIL; if(ch==EOF) break; } if(status!=TXT_GM8B_PLAIN2_Q) while(ch!='(') { ch = ReadBlobByte(image); if(ch==10 || ch==13) goto TXT_FAIL; if(ch==EOF) break; } ch=0; R = ReadInt(image,&ch); /* R */ if(R>max) max=R; while(ch!=',') { ch = ReadBlobByte(image); if(ch==10 || ch==13) goto TXT_FAIL; if(ch==EOF) break; } ch=0; G = ReadInt(image,&ch); /* G */ if(G>max) max=G; while(ch!=',') { ch = ReadBlobByte(image); if(ch==10 || ch==13) goto TXT_FAIL; if(ch==EOF) break; } ch=0; B = ReadInt(image,&ch); /* B */ if(B>max) max=B; if(status>16) { while(ch!=',') { ch = ReadBlobByte(image); if(ch==10 || ch==13) goto TXT_FAIL; if(ch==EOF) break; } ch=0; A = ReadInt(image,&ch); /* A */ if(A>max) max=A; } if(status!=TXT_GM8B_PLAIN2_Q) while(ch!=')') { ch = ReadBlobByte(image); if(ch==10 || ch==13) goto TXT_FAIL; if(ch==EOF) break; } readln(image,&ch); } EndReading: x_min = 1; x_max = 0; y_curr = 0; NumOfPlanes=8; /* if(max>= 2) i=2; */ /* if(max>= 4) i=4; */ /* if(max>= 16) i=8; */ if(max>= 256) NumOfPlanes=16; if(max>=65536) NumOfPlanes=32; if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(), "Image detected [%u * %u]: %d", x, y, NumOfPlanes); image->depth = Min(QuantumDepth,NumOfPlanes); ImportPixelAreaOptionsInit(&import_options); import_options.endian = NativeEndian; BImgBuff = MagickAllocateMemory(unsigned char *, (size_t)(x+1) * ( ((status>16)?4:3) * NumOfPlanes/8)); WImgBuff = (magick_uint16_t *)BImgBuff; DImgBuff = (magick_uint32_t *)BImgBuff; if(BImgBuff==NULL) ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image); image->columns = x+1; image->rows = y+1; (void) SeekBlob(image,0,SEEK_SET); while(!EOFBlob(image)) /* load picture data */ { x=0; while(!(ch >= '0' && ch <= '9')) { /* move to the beginning of number */ if(EOFBlob(image)) goto FINISH; ch = ReadBlobByte(image); if(ch=='#') {readln(image,&ch); continue;} } x = ReadInt(image,&ch); /* x */ while(ch!=',') { ch = ReadBlobByte(image); if(ch==EOF) break; } ch = 0; y = ReadInt(image,&ch); /* y */ while(ch!=':') { ch = ReadBlobByte(image); if(ch==EOF) break; } while(ch!='(') { ch = ReadBlobByte(image); if(ch==EOF) break; } ch=0; R = ReadInt(image,&ch); /* R */ while(ch!=',') { ch = ReadBlobByte(image); if(ch==EOF) break; } ch=0; G = ReadInt(image,&ch); /* G */ while(ch!=',') { ch = ReadBlobByte(image); if(ch==EOF) break; } ch=0; B = ReadInt(image,&ch); /* B */ if(status>16) { while(ch!=',') { ch = ReadBlobByte(image); if(ch==EOF) break; } ch=0; A = ReadInt(image,&ch); /* A */ if(A>max) max=A; } while(ch!=')') { ch = ReadBlobByte(image); if(ch==EOF) break; } /* a new line has been detected */ if(y!=y_curr) { q = SetImagePixels(image,x_min,y_curr,x_max-x_min+1,1); if (q == (PixelPacket *)NULL) break; if(status>16) (void)ImportImagePixelArea(image,RGBAQuantum,NumOfPlanes, BImgBuff + 4*x_min*(NumOfPlanes/8),&import_options,0); else (void)ImportImagePixelArea(image,RGBQuantum,NumOfPlanes, BImgBuff + 3*x_min*(NumOfPlanes/8),&import_options,0); if (!SyncImagePixels(image)) break; x_min = 1; x_max = 0; y_curr=y; } if(x<image->columns) { if(status>16) { switch(NumOfPlanes) { case 8: BImgBuff[0+4*x] = R; BImgBuff[1+4*x] = G; BImgBuff[2+4*x] = B; BImgBuff[3+4*x] = A; break; case 16:WImgBuff[0+4*x] = R; WImgBuff[1+4*x] = G; WImgBuff[2+4*x] = B; WImgBuff[3+4*x] = A; break; case 32:DImgBuff[0+4*x] = R; DImgBuff[1+4*x] = G; DImgBuff[2+4*x] = B; DImgBuff[3+4*x] = A; break; } } else { switch(NumOfPlanes) { case 8: BImgBuff[0+3*x] = R; BImgBuff[1+3*x] = G; BImgBuff[2+3*x] = B; break; case 16:WImgBuff[0+3*x] = R; WImgBuff[1+3*x] = G; WImgBuff[2+3*x] = B; break; case 32:DImgBuff[0+3*x] = R; DImgBuff[1+3*x] = G; DImgBuff[2+3*x] = B; break; } } if(x_min>x_max) x_max=x_min=x; else { if(x<x_min) x_min=x; if(x>x_max) x_max=x; } } readln(image,&ch); } FINISH: if(x_min<=x_max) { q = SetImagePixels(image,x_min,y_curr,x_max-x_min+1,1); if (q != (PixelPacket *)NULL) { if(status>16) (void)ImportImagePixelArea(image, RGBAQuantum, NumOfPlanes, BImgBuff + 4*x_min*(NumOfPlanes/8), &import_options, 0); else (void)ImportImagePixelArea(image, RGBQuantum, NumOfPlanes, BImgBuff + 3*x_min*(NumOfPlanes/8), &import_options, 0); if(!SyncImagePixels(image)) { if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(), " TXT failed to sync image pixels for a row %u", y_curr); } } } MagickFreeMemory(BImgBuff); goto TXT_FINISH; } /* Set the page geometry. */ dx_resolution=72.0; dy_resolution=72.0; if ((image->x_resolution == 0.0) || (image->y_resolution == 0.0)) { char density[MaxTextExtent]; (void) strcpy(density,PSDensityGeometry); count=GetMagickDimension(density,&image->x_resolution, &image->y_resolution,NULL,NULL); if (count != 2) image->y_resolution=image->x_resolution; } SetGeometry(image,&page); page.width=612; page.height=792; (void) GetGeometry("612x792+43+43",&page.x,&page.y,&page.width,&page.height); if (image_info->page != (char *) NULL) (void) GetGeometry(image_info->page,&page.x,&page.y,&page.width, &page.height); /* Initialize Image structure. */ image->columns=(unsigned long) ceil(((page.width*image->x_resolution)/dx_resolution)-0.5); image->rows=(unsigned long) ceil(((page.height*image->y_resolution)/dy_resolution)-0.5); texture=(Image *) NULL; if (image_info->texture != (char *) NULL) { ImageInfo *clone_info; clone_info=CloneImageInfo(image_info); clone_info->blob=(void *) NULL; clone_info->length=0; (void) strlcpy(clone_info->filename,image_info->texture,MaxTextExtent); texture=ReadImage(clone_info,exception); DestroyImageInfo(clone_info); } /* Annotate the text image. */ (void) SetImage(image,OpaqueOpacity); draw_info=CloneDrawInfo(image_info,(DrawInfo *) NULL); draw_info->fill=image_info->pen; (void) CloneString(&draw_info->text,image_info->filename); FormatString(geometry,"0x0%+ld%+ld",page.x,page.y); (void) CloneString(&draw_info->geometry,geometry); status=GetTypeMetrics(image,draw_info,&metrics); if (status == False) ThrowReaderException(TypeError,UnableToGetTypeMetrics,image); (void) strlcpy(filename,image_info->filename,MaxTextExtent); if (draw_info->text != '\0') *draw_info->text='\0'; for (offset=2*page.y; p != (char *) NULL; ) { /* Annotate image with text. */ (void) ConcatenateString(&draw_info->text,text); (void) ConcatenateString(&draw_info->text,"\\n"); offset+=(long) (metrics.ascent-metrics.descent); if (image->previous == (Image *) NULL) if (QuantumTick(offset,image->rows)) if (!MagickMonitorFormatted(offset,image->rows,&image->exception, LoadImageText,image->filename, image->columns,image->rows)) break; p=ReadBlobString(image,text); if ((offset < (long) image->rows) && (p != (char *) NULL)) continue; if (texture != (Image *) NULL) { MonitorHandler handler; handler=SetMonitorHandler((MonitorHandler) NULL); (void) TextureImage(image,texture); (void) SetMonitorHandler(handler); } (void) AnnotateImage(image,draw_info); if (p == (char *) NULL) break; /* Page is full-- allocate next image structure. */ *draw_info->text='\0'; offset=2*page.y; AllocateNextImage(image_info,image); if (image->next == (Image *) NULL) { DestroyImageList(image); return((Image *) NULL); } image->next->columns=image->columns; image->next->rows=image->rows; image=SyncNextImageInList(image); (void) strlcpy(image->filename,filename,MaxTextExtent); (void) SetImage(image,OpaqueOpacity); if (!MagickMonitorFormatted(TellBlob(image),GetBlobSize(image),exception, LoadImagesText,image->filename)) break; } if (texture != (Image *) NULL) { MonitorHandler handler; handler=SetMonitorHandler((MonitorHandler) NULL); (void) TextureImage(image,texture); (void) SetMonitorHandler(handler); } (void) AnnotateImage(image,draw_info); if (texture != (Image *) NULL) DestroyImage(texture); DestroyDrawInfo(draw_info); while (image->previous != (Image *) NULL) image=image->previous; TXT_FINISH: CloseBlob(image); return(image); }