Home | History | Annotate | Download | only in coders
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %                     PPPP    AAA   N   N   GGGG   OOO                        %
      7 %                     P   P  A   A  NN  N  G      O   O                       %
      8 %                     PPPP   AAAAA  N N N  G GGG  O   O                       %
      9 %                     P      A   A  N  NN  G   G  O   O                       %
     10 %                     P      A   A  N   N   GGGG   OOO                        %
     11 %                                                                             %
     12 %                                                                             %
     13 %                     Read Pango Markup Language Format                       %
     14 %                                                                             %
     15 %                              Software Design                                %
     16 %                                   Cristy                                    %
     17 %                                 March 2012                                  %
     18 %                                                                             %
     19 %                                                                             %
     20 %  Copyright 1999-2016 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 /*
     41   Include declarations.
     42 */
     43 #include "MagickCore/studio.h"
     44 #include "MagickCore/annotate.h"
     45 #include "MagickCore/artifact.h"
     46 #include "MagickCore/blob.h"
     47 #include "MagickCore/blob-private.h"
     48 #include "MagickCore/composite-private.h"
     49 #include "MagickCore/draw.h"
     50 #include "MagickCore/draw-private.h"
     51 #include "MagickCore/exception.h"
     52 #include "MagickCore/exception-private.h"
     53 #include "MagickCore/image.h"
     54 #include "MagickCore/image-private.h"
     55 #include "MagickCore/list.h"
     56 #include "MagickCore/magick.h"
     57 #include "MagickCore/memory_.h"
     58 #include "MagickCore/module.h"
     59 #include "MagickCore/monitor.h"
     60 #include "MagickCore/monitor-private.h"
     61 #include "MagickCore/option.h"
     62 #include "MagickCore/pixel-accessor.h"
     63 #include "MagickCore/property.h"
     64 #include "MagickCore/quantum-private.h"
     65 #include "MagickCore/static.h"
     66 #include "MagickCore/string_.h"
     67 #include "MagickCore/string-private.h"
     68 #include "MagickCore/token.h"
     69 #include "MagickCore/utility.h"
     70 #if defined(MAGICKCORE_PANGOCAIRO_DELEGATE)
     71 #include <pango/pango.h>
     72 #include <pango/pangocairo.h>
     73 #include <pango/pango-features.h>
     74 #endif
     75 
     76 #if defined(MAGICKCORE_PANGOCAIRO_DELEGATE)
     78 /*
     79 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     80 %                                                                             %
     81 %                                                                             %
     82 %                                                                             %
     83 %   R e a d P A N G O I m a g e                                               %
     84 %                                                                             %
     85 %                                                                             %
     86 %                                                                             %
     87 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     88 %
     89 %  ReadPANGOImage() reads an image in the Pango Markup Language Format.
     90 %
     91 %  The format of the ReadPANGOImage method is:
     92 %
     93 %      Image *ReadPANGOImage(const ImageInfo *image_info,
     94 %        ExceptionInfo *exception)
     95 %
     96 %  A description of each parameter follows:
     97 %
     98 %    o image_info: the image info.
     99 %
    100 %    o exception: return any errors or warnings in this structure.
    101 %
    102 */
    103 static Image *ReadPANGOImage(const ImageInfo *image_info,
    104   ExceptionInfo *exception)
    105 {
    106   cairo_font_options_t
    107     *font_options;
    108 
    109   cairo_surface_t
    110     *surface;
    111 
    112   char
    113     *caption,
    114     *property;
    115 
    116   cairo_t
    117     *cairo_image;
    118 
    119   const char
    120     *option;
    121 
    122   DrawInfo
    123     *draw_info;
    124 
    125   Image
    126     *image;
    127 
    128   MagickBooleanType
    129     status;
    130 
    131   MemoryInfo
    132     *pixel_info;
    133 
    134   PangoAlignment
    135     align;
    136 
    137   PangoContext
    138     *context;
    139 
    140   PangoFontDescription
    141     *description;
    142 
    143   PangoFontMap
    144     *fontmap;
    145 
    146   PangoGravity
    147     gravity;
    148 
    149   PangoLayout
    150     *layout;
    151 
    152   PangoRectangle
    153     extent;
    154 
    155   PixelInfo
    156     fill_color;
    157 
    158   RectangleInfo
    159     page;
    160 
    161   register unsigned char
    162     *p;
    163 
    164   size_t
    165     stride;
    166 
    167   ssize_t
    168     y;
    169 
    170   unsigned char
    171     *pixels;
    172 
    173   /*
    174     Initialize Image structure.
    175   */
    176   assert(image_info != (const ImageInfo *) NULL);
    177   assert(image_info->signature == MagickCoreSignature);
    178   if (image_info->debug != MagickFalse)
    179     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
    180       image_info->filename);
    181   assert(exception != (ExceptionInfo *) NULL);
    182   assert(exception->signature == MagickCoreSignature);
    183   image=AcquireImage(image_info,exception);
    184   (void) ResetImagePage(image,"0x0+0+0");
    185   /*
    186     Format caption.
    187   */
    188   option=GetImageOption(image_info,"filename");
    189   if (option == (const char *) NULL)
    190     property=InterpretImageProperties((ImageInfo *) image_info,image,
    191       image_info->filename,exception);
    192   else
    193     if (LocaleNCompare(option,"pango:",6) == 0)
    194       property=InterpretImageProperties((ImageInfo *) image_info,image,option+6,
    195         exception);
    196     else
    197       property=InterpretImageProperties((ImageInfo *) image_info,image,option,
    198         exception);
    199   (void) SetImageProperty(image,"caption",property,exception);
    200   property=DestroyString(property);
    201   caption=ConstantString(GetImageProperty(image,"caption",exception));
    202   /*
    203     Get context.
    204   */
    205   fontmap=pango_cairo_font_map_new();
    206   pango_cairo_font_map_set_resolution(PANGO_CAIRO_FONT_MAP(fontmap),
    207     image->resolution.x == 0.0 ? 90.0 : image->resolution.x);
    208   font_options=cairo_font_options_create();
    209   option=GetImageOption(image_info,"pango:hinting");
    210   if (option != (const char *) NULL)
    211     {
    212       if (LocaleCompare(option,"none") != 0)
    213         cairo_font_options_set_hint_style(font_options,CAIRO_HINT_STYLE_NONE);
    214       if (LocaleCompare(option,"full") != 0)
    215         cairo_font_options_set_hint_style(font_options,CAIRO_HINT_STYLE_FULL);
    216     }
    217   context=pango_font_map_create_context(fontmap);
    218   pango_cairo_context_set_font_options(context,font_options);
    219   cairo_font_options_destroy(font_options);
    220   option=GetImageOption(image_info,"pango:language");
    221   if (option != (const char *) NULL)
    222     pango_context_set_language(context,pango_language_from_string(option));
    223   draw_info=CloneDrawInfo(image_info,(DrawInfo *) NULL);
    224   pango_context_set_base_dir(context,draw_info->direction ==
    225     RightToLeftDirection ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR);
    226   switch (draw_info->gravity)
    227   {
    228     case NorthGravity:
    229     {
    230       gravity=PANGO_GRAVITY_NORTH;
    231       break;
    232     }
    233     case NorthWestGravity:
    234     case WestGravity:
    235     case SouthWestGravity:
    236     {
    237       gravity=PANGO_GRAVITY_WEST;
    238       break;
    239     }
    240     case NorthEastGravity:
    241     case EastGravity:
    242     case SouthEastGravity:
    243     {
    244       gravity=PANGO_GRAVITY_EAST;
    245       break;
    246     }
    247     case SouthGravity:
    248     {
    249       gravity=PANGO_GRAVITY_SOUTH;
    250       break;
    251     }
    252     default:
    253     {
    254       gravity=PANGO_GRAVITY_AUTO;
    255       break;
    256     }
    257   }
    258   pango_context_set_base_gravity(context,gravity);
    259   option=GetImageOption(image_info,"pango:gravity-hint");
    260   if (option != (const char *) NULL)
    261     {
    262       if (LocaleCompare(option,"line") == 0)
    263         pango_context_set_gravity_hint(context,PANGO_GRAVITY_HINT_LINE);
    264       if (LocaleCompare(option,"natural") == 0)
    265         pango_context_set_gravity_hint(context,PANGO_GRAVITY_HINT_NATURAL);
    266       if (LocaleCompare(option,"strong") == 0)
    267         pango_context_set_gravity_hint(context,PANGO_GRAVITY_HINT_STRONG);
    268     }
    269   /*
    270     Configure layout.
    271   */
    272   layout=pango_layout_new(context);
    273   option=GetImageOption(image_info,"pango:auto-dir");
    274   if (option != (const char *) NULL)
    275     pango_layout_set_auto_dir(layout,1);
    276   option=GetImageOption(image_info,"pango:ellipsize");
    277   if (option != (const char *) NULL)
    278     {
    279       if (LocaleCompare(option,"end") == 0)
    280         pango_layout_set_ellipsize(layout,PANGO_ELLIPSIZE_END);
    281       if (LocaleCompare(option,"middle") == 0)
    282         pango_layout_set_ellipsize(layout,PANGO_ELLIPSIZE_MIDDLE);
    283       if (LocaleCompare(option,"none") == 0)
    284         pango_layout_set_ellipsize(layout,PANGO_ELLIPSIZE_NONE);
    285       if (LocaleCompare(option,"start") == 0)
    286         pango_layout_set_ellipsize(layout,PANGO_ELLIPSIZE_START);
    287     }
    288   option=GetImageOption(image_info,"pango:justify");
    289   if (IsStringTrue(option) != MagickFalse)
    290     pango_layout_set_justify(layout,1);
    291   option=GetImageOption(image_info,"pango:single-paragraph");
    292   if (IsStringTrue(option) != MagickFalse)
    293     pango_layout_set_single_paragraph_mode(layout,1);
    294   option=GetImageOption(image_info,"pango:wrap");
    295   if (option != (const char *) NULL)
    296     {
    297       if (LocaleCompare(option,"char") == 0)
    298         pango_layout_set_wrap(layout,PANGO_WRAP_CHAR);
    299       if (LocaleCompare(option,"word") == 0)
    300         pango_layout_set_wrap(layout,PANGO_WRAP_WORD);
    301       if (LocaleCompare(option,"word-char") == 0)
    302         pango_layout_set_wrap(layout,PANGO_WRAP_WORD_CHAR);
    303     }
    304   option=GetImageOption(image_info,"pango:indent");
    305   if (option != (const char *) NULL)
    306     pango_layout_set_indent(layout,(int) ((StringToLong(option)*
    307       (image->resolution.x == 0.0 ? 90.0 : image->resolution.x)*PANGO_SCALE+36)/
    308       90.0+0.5));
    309   switch (draw_info->align)
    310   {
    311     case CenterAlign: align=PANGO_ALIGN_CENTER; break;
    312     case RightAlign: align=PANGO_ALIGN_RIGHT; break;
    313     case LeftAlign: align=PANGO_ALIGN_LEFT; break;
    314     default:
    315     {
    316       if (draw_info->gravity == CenterGravity)
    317         {
    318           align=PANGO_ALIGN_CENTER;
    319           break;
    320         }
    321       align=PANGO_ALIGN_LEFT;
    322       break;
    323     }
    324   }
    325   if ((align != PANGO_ALIGN_CENTER) &&
    326       (draw_info->direction == RightToLeftDirection))
    327     align=(PangoAlignment) (PANGO_ALIGN_LEFT+PANGO_ALIGN_RIGHT-align);
    328   pango_layout_set_alignment(layout,align);
    329   if (draw_info->font == (char *) NULL)
    330     description=pango_font_description_new();
    331   else
    332     description=pango_font_description_from_string(draw_info->font);
    333   pango_font_description_set_size(description,(int) (PANGO_SCALE*
    334     draw_info->pointsize+0.5));
    335   pango_layout_set_font_description(layout,description);
    336   pango_font_description_free(description);
    337   option=GetImageOption(image_info,"pango:markup");
    338   if ((option != (const char *) NULL) && (IsStringTrue(option) == MagickFalse))
    339     pango_layout_set_text(layout,caption,-1);
    340   else
    341     {
    342       GError
    343         *error;
    344 
    345       error=(GError *) NULL;
    346       if (pango_parse_markup(caption,-1,0,NULL,NULL,NULL,&error) == 0)
    347         (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
    348           error->message,"`%s'",image_info->filename);
    349       pango_layout_set_markup(layout,caption,-1);
    350     }
    351   pango_layout_context_changed(layout);
    352   page.x=0;
    353   page.y=0;
    354   if (image_info->page != (char *) NULL)
    355     (void) ParseAbsoluteGeometry(image_info->page,&page);
    356   if (image->columns == 0)
    357     {
    358       pango_layout_get_extents(layout,NULL,&extent);
    359       image->columns=(extent.x+extent.width+PANGO_SCALE/2)/PANGO_SCALE+2*page.x;
    360     }
    361   else
    362     {
    363       image->columns-=2*page.x;
    364       pango_layout_set_width(layout,(int) ((PANGO_SCALE*image->columns*
    365         (image->resolution.x == 0.0 ? 90.0 : image->resolution.x)+45.0)/90.0+
    366         0.5));
    367     }
    368   if (image->rows == 0)
    369     {
    370       pango_layout_get_extents(layout,NULL,&extent);
    371       image->rows=(extent.y+extent.height+PANGO_SCALE/2)/PANGO_SCALE+2*page.y;
    372     }
    373   else
    374     {
    375       image->rows-=2*page.y;
    376       pango_layout_set_height(layout,(int) ((PANGO_SCALE*image->rows*
    377         (image->resolution.y == 0.0 ? 90.0 : image->resolution.y)+45.0)/90.0+
    378         0.5));
    379     }
    380   status=SetImageExtent(image,image->columns,image->rows,exception);
    381   if (status == MagickFalse)
    382     return(DestroyImageList(image));
    383   /*
    384     Render markup.
    385   */
    386   stride=(size_t) cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32,
    387     (int) image->columns);
    388   pixel_info=AcquireVirtualMemory(image->rows,stride*sizeof(*pixels));
    389   if (pixel_info == (MemoryInfo *) NULL)
    390     {
    391       draw_info=DestroyDrawInfo(draw_info);
    392       caption=DestroyString(caption);
    393       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
    394     }
    395   pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
    396   surface=cairo_image_surface_create_for_data(pixels,CAIRO_FORMAT_ARGB32,
    397     (int) image->columns,(int) image->rows,(int) stride);
    398   cairo_image=cairo_create(surface);
    399   cairo_set_operator(cairo_image,CAIRO_OPERATOR_CLEAR);
    400   cairo_paint(cairo_image);
    401   cairo_set_operator(cairo_image,CAIRO_OPERATOR_OVER);
    402   cairo_translate(cairo_image,page.x,page.y);
    403   cairo_set_source_rgba(cairo_image,QuantumScale*draw_info->fill.red,
    404     QuantumScale*draw_info->fill.green,QuantumScale*draw_info->fill.blue,
    405     QuantumScale*draw_info->fill.alpha);
    406   pango_cairo_show_layout(cairo_image,layout);
    407   cairo_destroy(cairo_image);
    408   cairo_surface_destroy(surface);
    409   g_object_unref(layout);
    410   g_object_unref(fontmap);
    411   /*
    412     Convert surface to image.
    413   */
    414   (void) SetImageBackgroundColor(image,exception);
    415   p=pixels;
    416   GetPixelInfo(image,&fill_color);
    417   for (y=0; y < (ssize_t) image->rows; y++)
    418   {
    419     register Quantum
    420       *q;
    421 
    422     register ssize_t
    423       x;
    424 
    425     q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
    426     if (q == (Quantum *) NULL)
    427       break;
    428     for (x=0; x < (ssize_t) image->columns; x++)
    429     {
    430       double
    431         gamma;
    432 
    433       fill_color.blue=(double) ScaleCharToQuantum(*p++);
    434       fill_color.green=(double) ScaleCharToQuantum(*p++);
    435       fill_color.red=(double) ScaleCharToQuantum(*p++);
    436       fill_color.alpha=(double) ScaleCharToQuantum(*p++);
    437       /*
    438         Disassociate alpha.
    439       */
    440       gamma=QuantumScale*fill_color.alpha;
    441       gamma=PerceptibleReciprocal(gamma);
    442       fill_color.blue*=gamma;
    443       fill_color.green*=gamma;
    444       fill_color.red*=gamma;
    445       CompositePixelOver(image,&fill_color,fill_color.alpha,q,(double)
    446         GetPixelAlpha(image,q),q);
    447       q+=GetPixelChannels(image);
    448     }
    449     if (SyncAuthenticPixels(image,exception) == MagickFalse)
    450       break;
    451     if (image->previous == (Image *) NULL)
    452       {
    453         status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
    454         image->rows);
    455         if (status == MagickFalse)
    456           break;
    457       }
    458   }
    459   /*
    460     Relinquish resources.
    461   */
    462   pixel_info=RelinquishVirtualMemory(pixel_info);
    463   draw_info=DestroyDrawInfo(draw_info);
    464   caption=DestroyString(caption);
    465   return(GetFirstImageInList(image));
    466 }
    467 #endif
    468 
    469 /*
    471 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    472 %                                                                             %
    473 %                                                                             %
    474 %                                                                             %
    475 %   R e g i s t e r P A N G O I m a g e                                       %
    476 %                                                                             %
    477 %                                                                             %
    478 %                                                                             %
    479 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    480 %
    481 %  RegisterPANGOImage() adds attributes for the Pango Markup Language format to
    482 %  the list of supported formats.  The attributes include the image format
    483 %  tag, a method to read and/or write the format, whether the format
    484 %  supports the saving of more than one frame to the same file or blob,
    485 %  whether the format supports native in-memory I/O, and a brief
    486 %  description of the format.
    487 %
    488 %  The format of the RegisterPANGOImage method is:
    489 %
    490 %      size_t RegisterPANGOImage(void)
    491 %
    492 */
    493 ModuleExport size_t RegisterPANGOImage(void)
    494 {
    495   char
    496     version[MagickPathExtent];
    497 
    498   MagickInfo
    499     *entry;
    500 
    501   *version='\0';
    502 #if defined(PANGO_VERSION_STRING)
    503   (void) FormatLocaleString(version,MagickPathExtent,"Pangocairo %s",
    504     PANGO_VERSION_STRING);
    505 #endif
    506   entry=AcquireMagickInfo("PANGO","PANGO","Pango Markup Language");
    507 #if defined(MAGICKCORE_PANGOCAIRO_DELEGATE)
    508   entry->decoder=(DecodeImageHandler *) ReadPANGOImage;
    509 #endif
    510   if (*version != '\0')
    511     entry->version=ConstantString(version);
    512   entry->flags^=CoderAdjoinFlag;
    513   (void) RegisterMagickInfo(entry);
    514   return(MagickImageCoderSignature);
    515 }
    516 
    517 /*
    519 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    520 %                                                                             %
    521 %                                                                             %
    522 %                                                                             %
    523 %   U n r e g i s t e r P A N G O I m a g e                                   %
    524 %                                                                             %
    525 %                                                                             %
    526 %                                                                             %
    527 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    528 %
    529 %  UnregisterPANGOImage() removes format registrations made by the Pango module
    530 %  from the list of supported formats.
    531 %
    532 %  The format of the UnregisterPANGOImage method is:
    533 %
    534 %      UnregisterPANGOImage(void)
    535 %
    536 */
    537 ModuleExport void UnregisterPANGOImage(void)
    538 {
    539   (void) UnregisterMagickInfo("PANGO");
    540 }
    541