caption.c revision e67f43f8af5feb0f08d04b14dce7ccc162973715
1/* 2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3% % 4% % 5% % 6% CCCC AAA PPPP TTTTT IIIII OOO N N % 7% C A A P P T I O O NN N % 8% C AAAAA PPPP T I O O N N N % 9% C A A P T I O O N NN % 10% CCCC A A P T IIIII OOO N N % 11% % 12% % 13% Read Text Caption. % 14% % 15% Software Design % 16% John Cristy % 17% February 2002 % 18% % 19% % 20% Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization % 21% dedicated to making software imaging solutions freely available. % 22% % 23% You may not use this file except in compliance with the License. You may % 24% obtain a copy of the License at % 25% % 26% http://www.imagemagick.org/script/license.php % 27% % 28% Unless required by applicable law or agreed to in writing, software % 29% distributed under the License is distributed on an "AS IS" BASIS, % 30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 31% See the License for the specific language governing permissions and % 32% limitations under the License. % 33% % 34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35% 36% 37*/ 38 39/* 40 Include declarations. 41*/ 42#include "MagickCore/studio.h" 43#include "MagickCore/annotate.h" 44#include "MagickCore/artifact.h" 45#include "MagickCore/blob.h" 46#include "MagickCore/blob-private.h" 47#include "MagickCore/composite-private.h" 48#include "MagickCore/draw.h" 49#include "MagickCore/draw-private.h" 50#include "MagickCore/exception.h" 51#include "MagickCore/exception-private.h" 52#include "MagickCore/image.h" 53#include "MagickCore/image-private.h" 54#include "MagickCore/list.h" 55#include "MagickCore/magick.h" 56#include "MagickCore/memory_.h" 57#include "MagickCore/module.h" 58#include "MagickCore/option.h" 59#include "MagickCore/property.h" 60#include "MagickCore/quantum-private.h" 61#include "MagickCore/static.h" 62#include "MagickCore/string_.h" 63#include "MagickCore/string-private.h" 64#include "MagickCore/utility.h" 65 66/* 67%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 68% % 69% % 70% % 71% R e a d C A P T I O N I m a g e % 72% % 73% % 74% % 75%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 76% 77% ReadCAPTIONImage() reads a CAPTION image file and returns it. It 78% allocates the memory necessary for the new Image structure and returns a 79% pointer to the new image. 80% 81% The format of the ReadCAPTIONImage method is: 82% 83% Image *ReadCAPTIONImage(const ImageInfo *image_info, 84% ExceptionInfo *exception) 85% 86% A description of each parameter follows: 87% 88% o image_info: the image info. 89% 90% o exception: return any errors or warnings in this structure. 91% 92*/ 93static Image *ReadCAPTIONImage(const ImageInfo *image_info, 94 ExceptionInfo *exception) 95{ 96 char 97 *caption, 98 geometry[MaxTextExtent], 99 *property, 100 *text; 101 102 const char 103 *gravity, 104 *option; 105 106 DrawInfo 107 *draw_info; 108 109 Image 110 *image; 111 112 MagickBooleanType 113 status; 114 115 register ssize_t 116 i; 117 118 size_t 119 height, 120 width; 121 122 TypeMetric 123 metrics; 124 125 /* 126 Initialize Image structure. 127 */ 128 assert(image_info != (const ImageInfo *) NULL); 129 assert(image_info->signature == MagickSignature); 130 if (image_info->debug != MagickFalse) 131 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 132 image_info->filename); 133 assert(exception != (ExceptionInfo *) NULL); 134 assert(exception->signature == MagickSignature); 135 image=AcquireImage(image_info,exception); 136 (void) ResetImagePage(image,"0x0+0+0"); 137 /* 138 Format caption. 139 */ 140 option=GetImageOption(image_info,"filename"); 141 if (option == (const char *) NULL) 142 property=InterpretImageProperties((ImageInfo *) image_info,image, 143 image_info->filename,exception); 144 else 145 if (LocaleNCompare(option,"caption:",8) == 0) 146 property=InterpretImageProperties((ImageInfo *) image_info,image,option+8, 147 exception); 148 else 149 property=InterpretImageProperties((ImageInfo *) image_info,image,option, 150 exception); 151 (void) SetImageProperty(image,"caption",property,exception); 152 property=DestroyString(property); 153 caption=ConstantString(GetImageProperty(image,"caption",exception)); 154 draw_info=CloneDrawInfo(image_info,(DrawInfo *) NULL); 155 (void) CloneString(&draw_info->text,caption); 156 gravity=GetImageOption(image_info,"gravity"); 157 if (gravity != (char *) NULL) 158 draw_info->gravity=(GravityType) ParseCommandOption(MagickGravityOptions, 159 MagickFalse,gravity); 160 if (image->columns == 0) 161 { 162 text=AcquireString(caption); 163 i=FormatMagickCaption(image,draw_info,MagickFalse,&metrics,&text, 164 exception); 165 (void) CloneString(&draw_info->text,text); 166 text=DestroyString(text); 167 (void) FormatLocaleString(geometry,MaxTextExtent,"%+g%+g", 168 -metrics.bounds.x1,metrics.ascent); 169 if (draw_info->gravity == UndefinedGravity) 170 (void) CloneString(&draw_info->geometry,geometry); 171 status=GetMultilineTypeMetrics(image,draw_info,&metrics,exception); 172 width=(size_t) floor(metrics.width+draw_info->stroke_width+0.5); 173 image->columns=width; 174 } 175 if (image->rows == 0) 176 { 177 text=AcquireString(caption); 178 i=FormatMagickCaption(image,draw_info,MagickFalse,&metrics,&text, 179 exception); 180 (void) CloneString(&draw_info->text,text); 181 text=DestroyString(text); 182 (void) FormatLocaleString(geometry,MaxTextExtent,"%+g%+g", 183 -metrics.bounds.x1,metrics.ascent); 184 if (draw_info->gravity == UndefinedGravity) 185 (void) CloneString(&draw_info->geometry,geometry); 186 status=GetMultilineTypeMetrics(image,draw_info,&metrics,exception); 187 image->rows=(size_t) ((i+1)*(metrics.ascent-metrics.descent+ 188 draw_info->interline_spacing+draw_info->stroke_width)+0.5); 189 } 190 if (fabs(image_info->pointsize) < MagickEpsilon) 191 { 192 double 193 high, 194 low; 195 196 /* 197 Auto fit text into bounding box. 198 */ 199 for ( ; ; draw_info->pointsize*=2.0) 200 { 201 text=AcquireString(caption); 202 i=FormatMagickCaption(image,draw_info,MagickFalse,&metrics,&text, 203 exception); 204 (void) CloneString(&draw_info->text,text); 205 text=DestroyString(text); 206 (void) FormatLocaleString(geometry,MaxTextExtent,"%+g%+g", 207 -metrics.bounds.x1,metrics.ascent); 208 if (draw_info->gravity == UndefinedGravity) 209 (void) CloneString(&draw_info->geometry,geometry); 210 status=GetMultilineTypeMetrics(image,draw_info,&metrics,exception); 211 width=(size_t) floor(metrics.width+draw_info->stroke_width+0.5); 212 height=(size_t) floor(metrics.height+draw_info->stroke_width+0.5); 213 if ((width >= image->columns) && (height >= image->rows)) 214 break; 215 if ((width >= (image->columns << 1)) || (height >= (image->rows << 1))) 216 break; 217 } 218 high=draw_info->pointsize; 219 for (low=1.0; (high-low) > 1.0; ) 220 { 221 draw_info->pointsize=(low+high)/2.0; 222 text=AcquireString(caption); 223 i=FormatMagickCaption(image,draw_info,MagickFalse,&metrics,&text, 224 exception); 225 (void) CloneString(&draw_info->text,text); 226 text=DestroyString(text); 227 (void) FormatLocaleString(geometry,MaxTextExtent,"%+g%+g", 228 -metrics.bounds.x1,metrics.ascent); 229 if (draw_info->gravity == UndefinedGravity) 230 (void) CloneString(&draw_info->geometry,geometry); 231 status=GetMultilineTypeMetrics(image,draw_info,&metrics,exception); 232 width=(size_t) floor(metrics.width+draw_info->stroke_width+0.5); 233 height=(size_t) floor(metrics.height+draw_info->stroke_width+0.5); 234 if ((width <= image->columns) && (height <= image->rows)) 235 low=draw_info->pointsize+1.0; 236 else 237 high=draw_info->pointsize-1.0; 238 } 239 for (draw_info->pointsize=(low+high)/2.0; (high-low) > 1.0; ) 240 { 241 text=AcquireString(caption); 242 i=FormatMagickCaption(image,draw_info,MagickFalse,&metrics,&text, 243 exception); 244 (void) CloneString(&draw_info->text,text); 245 text=DestroyString(text); 246 (void) FormatLocaleString(geometry,MaxTextExtent,"%+g%+g", 247 -metrics.bounds.x1,metrics.ascent); 248 if (draw_info->gravity == UndefinedGravity) 249 (void) CloneString(&draw_info->geometry,geometry); 250 status=GetMultilineTypeMetrics(image,draw_info,&metrics,exception); 251 width=(size_t) floor(metrics.width+draw_info->stroke_width+0.5); 252 height=(size_t) floor(metrics.height+draw_info->stroke_width+0.5); 253 if ((width <= image->columns) && (height <= image->rows)) 254 break; 255 draw_info->pointsize--; 256 } 257 draw_info->pointsize--; 258 } 259 (void) CloneString(&draw_info->text,caption); 260 i=FormatMagickCaption(image,draw_info,MagickFalse,&metrics,&caption, 261 exception); 262 if (SetImageBackgroundColor(image,exception) == MagickFalse) 263 { 264 image=DestroyImageList(image); 265 return((Image *) NULL); 266 } 267 /* 268 Draw caption. 269 */ 270 (void) CloneString(&draw_info->text,caption); 271 status=GetMultilineTypeMetrics(image,draw_info,&metrics,exception); 272 if ((draw_info->gravity != UndefinedGravity) && 273 (draw_info->direction != RightToLeftDirection)) 274 image->page.x=(ssize_t) (metrics.bounds.x1-draw_info->stroke_width/2.0); 275 else 276 { 277 (void) FormatLocaleString(geometry,MaxTextExtent,"%+g%+g", 278 -metrics.bounds.x1+draw_info->stroke_width/2.0,metrics.ascent+ 279 draw_info->stroke_width/2.0); 280 if (draw_info->direction == RightToLeftDirection) 281 (void) FormatLocaleString(geometry,MaxTextExtent,"%+g%+g", 282 image->columns-(metrics.bounds.x2+draw_info->stroke_width/2.0), 283 metrics.ascent+draw_info->stroke_width/2.0); 284 draw_info->geometry=AcquireString(geometry); 285 } 286 status=AnnotateImage(image,draw_info,exception); 287 draw_info=DestroyDrawInfo(draw_info); 288 caption=DestroyString(caption); 289 if (status == MagickFalse) 290 { 291 image=DestroyImageList(image); 292 return((Image *) NULL); 293 } 294 return(GetFirstImageInList(image)); 295} 296 297/* 298%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 299% % 300% % 301% % 302% R e g i s t e r C A P T I O N I m a g e % 303% % 304% % 305% % 306%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 307% 308% RegisterCAPTIONImage() adds attributes for the CAPTION image format to 309% the list of supported formats. The attributes include the image format 310% tag, a method to read and/or write the format, whether the format 311% supports the saving of more than one frame to the same file or blob, 312% whether the format supports native in-memory I/O, and a brief 313% description of the format. 314% 315% The format of the RegisterCAPTIONImage method is: 316% 317% size_t RegisterCAPTIONImage(void) 318% 319*/ 320ModuleExport size_t RegisterCAPTIONImage(void) 321{ 322 MagickInfo 323 *entry; 324 325 entry=SetMagickInfo("CAPTION"); 326 entry->decoder=(DecodeImageHandler *) ReadCAPTIONImage; 327 entry->description=ConstantString("Caption"); 328 entry->adjoin=MagickFalse; 329 entry->module=ConstantString("CAPTION"); 330 (void) RegisterMagickInfo(entry); 331 return(MagickImageCoderSignature); 332} 333 334/* 335%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 336% % 337% % 338% % 339% U n r e g i s t e r C A P T I O N I m a g e % 340% % 341% % 342% % 343%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 344% 345% UnregisterCAPTIONImage() removes format registrations made by the 346% CAPTION module from the list of supported formats. 347% 348% The format of the UnregisterCAPTIONImage method is: 349% 350% UnregisterCAPTIONImage(void) 351% 352*/ 353ModuleExport void UnregisterCAPTIONImage(void) 354{ 355 (void) UnregisterMagickInfo("CAPTION"); 356} 357