00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
#include "magick/studio.h"
00046
#include "magick/annotate.h"
00047
#include "magick/client.h"
00048
#include "magick/color.h"
00049
#include "magick/composite.h"
00050
#include "magick/composite_private.h"
00051
#include "magick/constitute.h"
00052
#include "magick/draw.h"
00053
#include "magick/draw_private.h"
00054
#include "magick/error.h"
00055
#include "magick/error_private.h"
00056
#include "magick/gem.h"
00057
#include "magick/geometry.h"
00058
#include "magick/log.h"
00059
#include "magick/resource_.h"
00060
#include "magick/string_.h"
00061
#include "magick/transform.h"
00062
#include "magick/type.h"
00063
#include "magick/utility.h"
00064
#include "magick/xwindow.h"
00065
#if defined(HasTTF)
00066
#if defined(__MINGW32__)
00067
# undef interface
00068
#endif
00069
#if defined(HAVE_FT2BUILD_H)
00070
# include <ft2build.h>
00071
#endif
00072
#if defined(FT_FREETYPE_H)
00073
# include FT_FREETYPE_H
00074
#else
00075
# include <freetype/freetype.h>
00076
#endif
00077
#if defined(FT_GLYPH_H)
00078
# include FT_GLYPH_H
00079
#else
00080
# include <freetype/ftglyph.h>
00081
#endif
00082
#if defined(FT_OUTLINE_H)
00083
# include FT_OUTLINE_H
00084
#else
00085
# include <freetype/ftoutln.h>
00086
#endif
00087
#if defined(FT_BBOX_H)
00088
# include FT_BBOX_H
00089
#else
00090
# include <freetype/ftbbox.h>
00091
#endif
00092
#endif
00093
00094
00095
00096
00097
static MagickBooleanType
00098
RenderType(
Image *,
const DrawInfo *,
const PointInfo *,
TypeMetric *),
00099
RenderPostscript(
Image *,
const DrawInfo *,
const PointInfo *,
TypeMetric *),
00100
RenderFreetype(
Image *,
const DrawInfo *,
const char *,
const PointInfo *,
00101
TypeMetric *),
00102
RenderX11(
Image *,
const DrawInfo *,
const PointInfo *,
TypeMetric *);
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154 MagickExport MagickBooleanType AnnotateImage(
Image *image,
00155
const DrawInfo *draw_info)
00156 {
00157
char
00158 primitive[
MaxTextExtent],
00159 *text,
00160 **textlist;
00161
00162
DrawInfo
00163 *annotate,
00164 *annotate_info;
00165
00166
GeometryInfo
00167 geometry_info;
00168
00169
MagickBooleanType
00170 status;
00171
00172
PointInfo
00173 offset;
00174
00175
RectangleInfo
00176 geometry;
00177
00178
register long
00179 i;
00180
00181 size_t
00182 length;
00183
00184
TypeMetric
00185 metrics;
00186
00187
unsigned long
00188 height,
00189 number_lines;
00190
00191
00192
00193
00194
assert(image != (
Image *) NULL);
00195
assert(image->
signature ==
MagickSignature);
00196
if (image->
debug !=
MagickFalse)
00197 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image->
filename);
00198
assert(draw_info != (
DrawInfo *) NULL);
00199
assert(draw_info->
signature ==
MagickSignature);
00200
if (draw_info->
text == (
char *) NULL)
00201
return(
MagickFalse);
00202
if (*draw_info->
text ==
'\0')
00203
return(
MagickFalse);
00204 text=
TranslateText((
ImageInfo *) NULL,image,draw_info->
text);
00205
if (text == (
char *) NULL)
00206
ThrowBinaryException(
ResourceLimitError,
"MemoryAllocationFailed",
00207 image->
filename);
00208 textlist=
StringToList(text);
00209 text=(
char *)
RelinquishMagickMemory(text);
00210
if (textlist == (
char **) NULL)
00211
return(
MagickFalse);
00212 length=strlen(textlist[0]);
00213
for (i=1; textlist[i] != (
char *) NULL; i++)
00214
if (strlen(textlist[i]) > length)
00215 length=strlen(textlist[i]);
00216 number_lines=(
unsigned long) i;
00217 text=(
char *)
AcquireMagickMemory(length+
MaxTextExtent);
00218
if (text == (
char *) NULL)
00219
ThrowBinaryException(
ResourceLimitError,
"MemoryAllocationFailed",
00220 image->
filename);
00221 annotate=
CloneDrawInfo((
ImageInfo *) NULL,draw_info);
00222 annotate_info=
CloneDrawInfo((
ImageInfo *) NULL,draw_info);
00223
SetGeometry(image,&geometry);
00224
SetGeometryInfo(&geometry_info);
00225
if (annotate_info->
geometry != (
char *) NULL)
00226 {
00227 (
void)
ParsePageGeometry(image,annotate_info->
geometry,&geometry);
00228 (
void)
ParseGeometry(annotate_info->
geometry,&geometry_info);
00229 }
00230 image->
storage_class=
DirectClass;
00231 status=
MagickTrue;
00232
for (i=0; textlist[i] != (
char *) NULL; i++)
00233 {
00234
00235
00236
00237 annotate_info->
affine.
tx=geometry_info.
xi;
00238 annotate_info->
affine.
ty=geometry_info.
psi;
00239 (
void)
CloneString(&annotate->
text,textlist[i]);
00240 (
void)
GetTypeMetrics(image,annotate,&metrics);
00241 height=(
unsigned long) (metrics.
ascent-metrics.
descent+0.5);
00242
switch (annotate->
gravity)
00243 {
00244
case UndefinedGravity:
00245
default:
00246 {
00247 offset.
x=annotate_info->
affine.
tx+i*annotate_info->
affine.
ry*height;
00248 offset.
y=annotate_info->
affine.
ty+i*annotate_info->
affine.
sy*height;
00249
break;
00250 }
00251
case NorthWestGravity:
00252 {
00253 offset.
x=(geometry.
width == 0 ? -1.0 : 1.0)*annotate_info->
affine.
tx+i*
00254 annotate_info->
affine.
ry*height+annotate_info->
affine.
ry*
00255 (metrics.
ascent+metrics.
descent);
00256 offset.
y=(geometry.
height == 0 ? -1.0 : 1.0)*annotate_info->
affine.
ty+i*
00257 annotate_info->
affine.
sy*height+annotate_info->
affine.
sy*
00258 metrics.
ascent;
00259
break;
00260 }
00261
case NorthGravity:
00262 {
00263 offset.
x=(geometry.
width == 0 ? -1.0 : 1.0)*annotate_info->
affine.
tx+
00264 geometry.
width/2.0+i*annotate_info->
affine.
ry*height-
00265 annotate_info->
affine.
sx*metrics.
width/2+annotate_info->
affine.
ry*
00266 (metrics.
ascent+metrics.
descent);
00267 offset.
y=(geometry.
height == 0 ? -1.0 : 1.0)*annotate_info->
affine.
ty+i*
00268 annotate_info->
affine.
sy*height+annotate_info->
affine.
sy*
00269 metrics.
ascent-annotate_info->
affine.
rx*metrics.
width/2.0;
00270
break;
00271 }
00272
case NorthEastGravity:
00273 {
00274 offset.
x=(geometry.
width == 0 ? 1.0 : -1.0)*annotate_info->
affine.
tx+
00275 geometry.
width+i*annotate_info->
affine.
ry*height-
00276 annotate_info->
affine.
sx*metrics.
width+annotate_info->
affine.
ry*
00277 (metrics.
ascent+metrics.
descent);
00278 offset.
y=(geometry.
height == 0 ? -1.0 : 1.0)*annotate_info->
affine.
ty+i*
00279 annotate_info->
affine.
sy*height+annotate_info->
affine.
sy*
00280 metrics.
ascent-annotate_info->
affine.
rx*metrics.
width;
00281
break;
00282 }
00283
case WestGravity:
00284 {
00285 offset.
x=(geometry.
width == 0 ? -1.0 : 1.0)*annotate_info->
affine.
tx+i*
00286 annotate_info->
affine.
ry*height+annotate_info->
affine.
ry*
00287 (metrics.
ascent+metrics.
descent-(number_lines-1.0)*height)/2.0;
00288 offset.
y=(geometry.
height == 0 ? -1.0 : 1.0)*annotate_info->
affine.
ty+
00289 geometry.
height/2.0+i*annotate_info->
affine.
sy*height+
00290 annotate_info->
affine.
sy*(metrics.
ascent+metrics.
descent-
00291 (number_lines-1.0)*height)/2.0;
00292
break;
00293 }
00294
case StaticGravity:
00295
case CenterGravity:
00296 {
00297 offset.
x=(geometry.
width == 0 ? -1.0 : 1.0)*annotate_info->
affine.
tx+
00298 geometry.
width/2.0+i*annotate_info->
affine.
ry*height-
00299 annotate_info->
affine.
sx*metrics.
width/2.0+annotate_info->
affine.
ry*
00300 (metrics.
ascent+metrics.
descent-(number_lines-1)*height)/2.0;
00301 offset.
y=(geometry.
height == 0 ? -1.0 : 1.0)*annotate_info->
affine.
ty+
00302 geometry.
height/2.0+i*annotate_info->
affine.
sy*height-
00303 annotate_info->
affine.
rx*metrics.
width/2.0+annotate_info->
affine.
sy*
00304 (metrics.
ascent+metrics.
descent-(number_lines-1.0)*height)/2.0;
00305
break;
00306 }
00307
case EastGravity:
00308 {
00309 offset.
x=(geometry.
width == 0 ? 1.0 : -1.0)*annotate_info->
affine.
tx+
00310 geometry.
width+i*annotate_info->
affine.
ry*height-
00311 annotate_info->
affine.
sx*metrics.
width+annotate_info->
affine.
ry*
00312 (metrics.
ascent+metrics.
descent-(number_lines-1.0)*height)/2.0;
00313 offset.
y=(geometry.
height == 0 ? -1.0 : 1.0)*annotate_info->
affine.
ty+
00314 geometry.
height/2.0+i*annotate_info->
affine.
sy*height-
00315 annotate_info->
affine.
rx*metrics.
width+annotate_info->
affine.
sy*
00316 (metrics.
ascent+metrics.
descent-(number_lines-1.0)*height)/2.0;
00317
break;
00318 }
00319
case SouthWestGravity:
00320 {
00321 offset.
x=(geometry.
width == 0 ? -1.0 : 1.0)*annotate_info->
affine.
tx+i*
00322 annotate_info->
affine.
ry*height-annotate_info->
affine.
ry*
00323 (number_lines-1.0)*height;
00324 offset.
y=(geometry.
height == 0 ? 1.0 : -1.0)*annotate_info->
affine.
ty+
00325 geometry.
height+i*annotate_info->
affine.
sy*height-
00326 annotate_info->
affine.
sy*(number_lines-1.0)*height+metrics.
descent;
00327
break;
00328 }
00329
case SouthGravity:
00330 {
00331 offset.
x=(geometry.
width == 0 ? -1.0 : 1.0)*annotate_info->
affine.
tx+
00332 geometry.
width/2.0+i*annotate_info->
affine.
ry*height-
00333 annotate_info->
affine.
sx*metrics.
width/2.0-annotate_info->
affine.
ry*
00334 (number_lines-1.0)*height/2.0;
00335 offset.
y=(geometry.
height == 0 ? 1.0 : -1.0)*annotate_info->
affine.
ty+
00336 geometry.
height+i*annotate_info->
affine.
sy*height-
00337 annotate_info->
affine.
rx*metrics.
width/2.0-annotate_info->
affine.
sy*
00338 (number_lines-1.0)*height+metrics.
descent;
00339
break;
00340 }
00341
case SouthEastGravity:
00342 {
00343 offset.
x=(geometry.
width == 0 ? 1.0 : -1.0)*annotate_info->
affine.
tx+
00344 geometry.
width+i*annotate_info->
affine.
ry*height-
00345 annotate_info->
affine.
sx*metrics.
width-annotate_info->
affine.
ry*
00346 (number_lines-1.0)*height;
00347 offset.
y=(geometry.
height == 0 ? 1.0 : -1.0)*annotate_info->
affine.
ty+
00348 geometry.
height+i*annotate_info->
affine.
sy*height-
00349 annotate_info->
affine.
rx*metrics.
width-annotate_info->
affine.
sy*
00350 (number_lines-1.0)*height+metrics.
descent;
00351
break;
00352 }
00353 }
00354
switch (annotate->
align)
00355 {
00356
case LeftAlign:
00357 {
00358 offset.
x=annotate_info->
affine.
tx+i*annotate_info->
affine.
ry*height;
00359 offset.
y=annotate_info->
affine.
ty+i*annotate_info->
affine.
sy*height;
00360
break;
00361 }
00362
case CenterAlign:
00363 {
00364 offset.
x=annotate_info->
affine.
tx+i*annotate_info->
affine.
ry*height-
00365 annotate_info->
affine.
sx*metrics.
width/2.0;
00366 offset.
y=annotate_info->
affine.
ty+i*annotate_info->
affine.
sy*height-
00367 annotate_info->
affine.
rx*metrics.
width/2.0;
00368
break;
00369 }
00370
case RightAlign:
00371 {
00372 offset.
x=annotate_info->
affine.
tx+i*annotate_info->
affine.
ry*height-
00373 annotate_info->
affine.
sx*metrics.
width;
00374 offset.
y=annotate_info->
affine.
ty+i*annotate_info->
affine.
sy*height-
00375 annotate_info->
affine.
rx*metrics.
width;
00376
break;
00377 }
00378
default:
00379
break;
00380 }
00381
if (draw_info->
undercolor.
opacity !=
TransparentOpacity)
00382 {
00383
00384
00385
00386 annotate_info->
fill=draw_info->
undercolor;
00387 annotate_info->
affine.
tx=offset.
x-draw_info->
affine.
ry*metrics.
ascent;
00388 annotate_info->
affine.
ty=offset.
y-draw_info->
affine.
sy*metrics.
ascent;
00389 (
void)
FormatMagickString(primitive,
MaxTextExtent,
00390
"rectangle 0,0 %g,%ld",metrics.
width,height);
00391 (
void)
CloneString(&annotate_info->
primitive,primitive);
00392 (
void)
DrawImage(image,annotate_info);
00393 }
00394 annotate_info->
affine.
tx=offset.
x;
00395 annotate_info->
affine.
ty=offset.
y;
00396 (
void)
FormatMagickString(primitive,
MaxTextExtent,
00397
"stroke-width %g line 0,0 %g,0",metrics.
underline_thickness,
00398 metrics.
width);
00399
if (annotate->
decorate ==
OverlineDecoration)
00400 {
00401 annotate_info->
affine.
ty-=(draw_info->
affine.
sy*
00402 (metrics.
ascent+metrics.
descent-metrics.
underline_position+2));
00403 (
void)
CloneString(&annotate_info->
primitive,primitive);
00404 (
void)
DrawImage(image,annotate_info);
00405 }
00406
else
00407
if (annotate->
decorate ==
UnderlineDecoration)
00408 {
00409 annotate_info->
affine.
ty-=
00410 (draw_info->
affine.
sy*metrics.
underline_position);
00411 (
void)
CloneString(&annotate_info->
primitive,primitive);
00412 (
void)
DrawImage(image,annotate_info);
00413 }
00414
00415
00416
00417 status=
RenderType(image,annotate,&offset,&metrics);
00418
if (status ==
MagickFalse)
00419
break;
00420
if (annotate->
decorate ==
LineThroughDecoration)
00421 {
00422 annotate_info->
affine.
ty-=(draw_info->
affine.
sy*(height+
00423 metrics.
underline_position+metrics.
descent)/2.0);
00424 (
void)
CloneString(&annotate_info->
primitive,primitive);
00425 (
void)
DrawImage(image,annotate_info);
00426 }
00427 }
00428
00429
00430
00431 annotate_info=
DestroyDrawInfo(annotate_info);
00432 annotate=
DestroyDrawInfo(annotate);
00433 text=(
char *)
RelinquishMagickMemory(text);
00434
for (i=0; textlist[i] != (
char *) NULL; i++)
00435 textlist[i]=(
char *)
RelinquishMagickMemory(textlist[i]);
00436 textlist=(
char **)
RelinquishMagickMemory(textlist);
00437
return(status);
00438 }
00439
00440
#if defined(HasTTF)
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
static int GetOneCharacter(
const unsigned char *text,size_t *length)
00475 {
00476
int
00477 c;
00478
00479
if (*length < 1)
00480
return(-1);
00481 c=text[0];
00482
if ((c & 0x80) == 0)
00483 {
00484 *length=1;
00485
return((
int) c);
00486 }
00487
if (*length < 2)
00488 {
00489 *length=0;
00490
return(-1);
00491 }
00492 *length=2;
00493 c=((
int) (text[0]) << 8);
00494 c|=text[1];
00495
return((
int) c);
00496 }
00497
00498
static unsigned short *EncodeSJIS(
const Image *image,
const char *text,
00499 size_t *count)
00500 {
00501
int
00502 c;
00503
00504
register const char
00505 *p;
00506
00507
register unsigned short
00508 *q;
00509
00510 size_t
00511 length;
00512
00513
unsigned short
00514 *encoding;
00515
00516 *count=0;
00517
if ((text == (
char *) NULL) || (*text ==
'\0'))
00518
return((
unsigned short *) NULL);
00519 length=strlen(text)+
MaxTextExtent;
00520 encoding=(
unsigned short *)
AcquireMagickMemory(length*
sizeof(*encoding));
00521
if (encoding == (
unsigned short *) NULL)
00522
ThrowMagickFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed",
00523 image->
filename);
00524 q=encoding;
00525
for (p=text; *p !=
'\0'; p+=length)
00526 {
00527 length=strlen(p);
00528 c=GetOneCharacter((
const unsigned char *) p,&length);
00529
if (c < 0)
00530 {
00531 q=encoding;
00532
for (p=text; *p !=
'\0'; p++)
00533 *q++=(
unsigned char) *p;
00534
break;
00535 }
00536 *q=(
unsigned short) c;
00537 q++;
00538 }
00539 *count=q-encoding;
00540
return(encoding);
00541 }
00542
#endif
00543
00544
#if defined(HasTTF)
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
static unsigned short *EncodeText(
const Image *image,
const char *text,
00574 size_t *count)
00575 {
00576
register const char
00577 *p;
00578
00579
register unsigned short
00580 *q;
00581
00582
unsigned short
00583 *encoding;
00584
00585 *count=0;
00586
if ((text == (
char *) NULL) || (*text ==
'\0'))
00587
return((
unsigned short *) NULL);
00588 encoding=(
unsigned short *)
00589
AcquireMagickMemory((strlen(text)+MaxTextExtent)*
sizeof(*encoding));
00590
if (encoding == (
unsigned short *) NULL)
00591
ThrowMagickFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed",
00592 image->
filename);
00593 q=encoding;
00594
for (p=text; *p !=
'\0'; p++)
00595 *q++=(
unsigned char) *p;
00596 *count=q-encoding;
00597
return(encoding);
00598 }
00599
#endif
00600
00601
#if defined(HasTTF)
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
static long GetUnicodeCharacter(
const unsigned char *text,size_t *length)
00635 {
00636
unsigned long
00637 c;
00638
00639
if (*length < 1)
00640
return(-1);
00641 c=text[0];
00642
if ((c & 0x80) == 0)
00643 {
00644 *length=1;
00645
return((
long) c);
00646 }
00647
if ((*length < 2) || ((text[1] & 0xc0) != 0x80))
00648 {
00649 *length=0;
00650
return(-1);
00651 }
00652
if ((c & 0xe0) != 0xe0)
00653 {
00654 *length=2;
00655 c=(text[0] & 0x1f) << 6;
00656 c|=text[1] & 0x3f;
00657
return((
long) c);
00658 }
00659
if ((*length < 3) || ((text[2] & 0xc0) != 0x80))
00660 {
00661 *length=0;
00662
return(-1);
00663 }
00664
if ((c & 0xf0) != 0xf0)
00665 {
00666 *length=3;
00667 c=(text[0] & 0xf) << 12;
00668 c|=(text[1] & 0x3f) << 6;
00669 c|=text[2] & 0x3f;
00670
return((
long) c);
00671 }
00672
if ((*length < 4) || ((c & 0xf8) != 0xf0) || ((text[3] & 0xc0) != 0x80))
00673 {
00674 *length=0;
00675
return(-1);
00676 }
00677 *length=4;
00678 c=(text[0] & 0x7) << 18;
00679 c|=(text[1] & 0x3f) << 12;
00680 c|=(text[2] & 0x3f) << 6;
00681 c|=text[3] & 0x3f;
00682
return((
long) c);
00683 }
00684
00685
static unsigned short *EncodeUnicode(
const Image *image,
const char *text,
00686 size_t *count)
00687 {
00688
long
00689 c;
00690
00691
register const char
00692 *p;
00693
00694
register unsigned short
00695 *q;
00696
00697 size_t
00698 length;
00699
00700
unsigned short
00701 *unicode;
00702
00703 *count=0;
00704
if ((text == (
char *) NULL) || (*text ==
'\0'))
00705
return((
unsigned short *) NULL);
00706 length=strlen(text)+
MaxTextExtent;
00707 unicode=(
unsigned short *)
AcquireMagickMemory(length*
sizeof(*unicode));
00708
if (unicode == (
unsigned short *) NULL)
00709
ThrowMagickFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed",
00710 image->
filename);
00711 q=unicode;
00712
for (p=text; *p !=
'\0'; p+=length)
00713 {
00714 length=strlen(p);
00715 c=GetUnicodeCharacter((
const unsigned char *) p,&length);
00716
if (c < 0)
00717 {
00718 q=unicode;
00719
for (p=text; *p !=
'\0'; p++)
00720 *q++=(
unsigned char) *p;
00721
break;
00722 }
00723 *q=(
unsigned short) c;
00724 q++;
00725 }
00726 *count=q-unicode;
00727
return(unicode);
00728 }
00729
#endif
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770 MagickExport MagickBooleanType GetTypeMetrics(
Image *image,
00771
const DrawInfo *draw_info,
TypeMetric *metrics)
00772 {
00773
DrawInfo
00774 *annotate_info;
00775
00776
MagickBooleanType
00777 status;
00778
00779
PointInfo
00780 offset;
00781
00782
assert(image != (
Image *) NULL);
00783
assert(image->
signature ==
MagickSignature);
00784
if (image->
debug !=
MagickFalse)
00785 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image->
filename);
00786
assert(draw_info != (
DrawInfo *) NULL);
00787
assert(draw_info->
text != (
char *) NULL);
00788
assert(draw_info->
signature ==
MagickSignature);
00789 annotate_info=
CloneDrawInfo((
ImageInfo *) NULL,draw_info);
00790 annotate_info->
render=
MagickFalse;
00791 (
void)
ResetMagickMemory(metrics,0,
sizeof(*metrics));
00792 offset.
x=0.0;
00793 offset.
y=0.0;
00794 status=
RenderType(image,annotate_info,&offset,metrics);
00795 annotate_info=
DestroyDrawInfo(annotate_info);
00796
return(status);
00797 }
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830 static MagickBooleanType RenderType(
Image *image,
const DrawInfo *draw_info,
00831
const PointInfo *offset,
TypeMetric *metrics)
00832 {
00833
const TypeInfo
00834 *type_info;
00835
00836
DrawInfo
00837 *annotate_info;
00838
00839
MagickBooleanType
00840 status;
00841
00842 type_info=(
const TypeInfo *) NULL;
00843
if (draw_info->
font != (
char *) NULL)
00844 {
00845
if (*draw_info->
font ==
'@')
00846
return(
RenderFreetype(image,draw_info,(
char *) NULL,offset,metrics));
00847
if (*draw_info->
font ==
'-')
00848
return(
RenderX11(image,draw_info,offset,metrics));
00849 type_info=
GetTypeInfo(draw_info->
font,&image->
exception);
00850
if (type_info == (
const TypeInfo *) NULL)
00851
if (
IsAccessible(draw_info->
font) !=
MagickFalse)
00852
return(
RenderFreetype(image,draw_info,(
char *) NULL,offset,metrics));
00853 }
00854
if (type_info == (
const TypeInfo *) NULL)
00855 type_info=
GetTypeInfoByFamily(draw_info->
family,draw_info->
style,
00856 draw_info->
stretch,draw_info->
weight,&image->
exception);
00857
if (type_info == (
const TypeInfo *) NULL)
00858 (
void)
ThrowMagickException(&image->
exception,
GetMagickModule(),
TypeWarning,
00859
"UnableToReadFont",draw_info->
font);
00860
if (type_info == (
const TypeInfo *) NULL)
00861 type_info=
GetTypeInfoByFamily(
"Arial",draw_info->
style,draw_info->
stretch,
00862 draw_info->
weight,&image->
exception);
00863
if (type_info == (
const TypeInfo *) NULL)
00864
return(
RenderPostscript(image,draw_info,offset,metrics));
00865 annotate_info=
CloneDrawInfo((
ImageInfo *) NULL,draw_info);
00866 annotate_info->
face=type_info->
face;
00867
if (type_info->
metrics != (
char *) NULL)
00868 (
void)
CloneString(&annotate_info->
metrics,type_info->
metrics);
00869
if (type_info->
glyphs != (
char *) NULL)
00870 (
void)
CloneString(&annotate_info->
font,type_info->
glyphs);
00871 status=
RenderFreetype(image,annotate_info,type_info->
encoding,offset,metrics);
00872 annotate_info=
DestroyDrawInfo(annotate_info);
00873
return(status);
00874 }
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910
#if defined(HasTTF)
00911
static int TraceCubicBezier(FT_Vector *p,FT_Vector *q,FT_Vector *to,
00912
DrawInfo *draw_info)
00913 {
00914
AffineMatrix
00915 affine;
00916
00917
char
00918 path[
MaxTextExtent];
00919
00920 affine=draw_info->
affine;
00921 (
void)
FormatMagickString(path,MaxTextExtent,
"C%g,%g %g,%g %g,%g",
00922 affine.
tx+p->x/64.0,affine.
ty-p->y/64.0,affine.
tx+q->x/64.0,
00923 affine.
ty-q->y/64.0,affine.
tx+to->x/64.0,affine.
ty-to->y/64.0);
00924 (
void)
ConcatenateString(&draw_info->
primitive,path);
00925
return(0);
00926 }
00927
00928
static int TraceLineTo(FT_Vector *to,
DrawInfo *draw_info)
00929 {
00930
AffineMatrix
00931 affine;
00932
00933
char
00934 path[
MaxTextExtent];
00935
00936 affine=draw_info->
affine;
00937 (
void)
FormatMagickString(path,MaxTextExtent,
"L%g,%g",affine.
tx+to->x/64.0,
00938 affine.
ty-to->y/64.0);
00939 (
void)
ConcatenateString(&draw_info->
primitive,path);
00940
return(0);
00941 }
00942
00943
static int TraceMoveTo(FT_Vector *to,
DrawInfo *draw_info)
00944 {
00945
AffineMatrix
00946 affine;
00947
00948
char
00949 path[
MaxTextExtent];
00950
00951 affine=draw_info->
affine;
00952 (
void)
FormatMagickString(path,MaxTextExtent,
"M%g,%g",affine.
tx+to->x/64.0,
00953 affine.
ty-to->y/64.0);
00954 (
void)
ConcatenateString(&draw_info->
primitive,path);
00955
return(0);
00956 }
00957
00958
static int TraceQuadraticBezier(FT_Vector *control,FT_Vector *to,
00959
DrawInfo *draw_info)
00960 {
00961
AffineMatrix
00962 affine;
00963
00964
char
00965 path[
MaxTextExtent];
00966
00967 affine=draw_info->
affine;
00968 (
void)
FormatMagickString(path,MaxTextExtent,
"Q%g,%g %g,%g",
00969 affine.
tx+control->x/64.0,affine.
ty-control->y/64.0,affine.
tx+to->x/64.0,
00970 affine.
ty-to->y/64.0);
00971 (
void)
ConcatenateString(&draw_info->
primitive,path);
00972
return(0);
00973 }
00974
00975
static MagickBooleanType RenderFreetype(
Image *image,
const DrawInfo *draw_info,
00976
const char *encoding,
const PointInfo *offset,
TypeMetric *metrics)
00977 {
00978
#if !defined(FT_OPEN_PATHNAME)
00979
#define FT_OPEN_PATHNAME ft_open_pathname
00980
#endif
00981
00982
typedef struct _GlyphInfo
00983 {
00984 FT_UInt
00985
id;
00986
00987 FT_Vector
00988 origin;
00989
00990 FT_Glyph
00991 image;
00992 } GlyphInfo;
00993
00994
DrawInfo
00995 *annotate_info;
00996
00997 FT_BBox
00998 bounds;
00999
01000 FT_BitmapGlyph
01001 bitmap;
01002
01003 FT_Encoding
01004 encoding_type;
01005
01006 FT_Error
01007 status;
01008
01009 FT_Face
01010 face;
01011
01012 FT_Library
01013 library;
01014
01015 FT_Matrix
01016 affine;
01017
01018 FT_Open_Args
01019 args;
01020
01021 FT_Vector
01022 origin;
01023
01024 GlyphInfo
01025 glyph,
01026 last_glyph;
01027
01028
long
01029 y;
01030
01031
MagickBooleanType
01032 active;
01033
01034
MagickRealType
01035 fill_opacity;
01036
01037
PixelPacket
01038 fill_color;
01039
01040
PointInfo
01041 point,
01042 resolution;
01043
01044
register long
01045 i,
01046 x;
01047
01048
register PixelPacket
01049 *q;
01050
01051
register unsigned char
01052 *p;
01053
01054 size_t
01055 length;
01056
01057
static FT_Outline_Funcs
01058 OutlineMethods =
01059 {
01060 (FT_Outline_MoveTo_Func) TraceMoveTo,
01061 (FT_Outline_LineTo_Func) TraceLineTo,
01062 (FT_Outline_ConicTo_Func) TraceQuadraticBezier,
01063 (FT_Outline_CubicTo_Func) TraceCubicBezier,
01064 0, 0
01065 };
01066
01067
unsigned short
01068 *text;
01069
01070
01071
01072
01073 status=FT_Init_FreeType(&library);
01074
if (status)
01075
ThrowBinaryException(TypeError,
"UnableToInitializeFreetypeLibrary",
01076 image->filename);
01077 args.flags=FT_OPEN_PATHNAME;
01078
if (*draw_info->
font !=
'@')
01079 args.pathname=draw_info->
font;
01080
else
01081 args.pathname=draw_info->
font+1;
01082 status=FT_Open_Face(library,&args,draw_info->
face,&face);
01083
if (status != 0)
01084 {
01085 (
void) FT_Done_FreeType(library);
01086
ThrowBinaryException(TypeError,
"UnableToReadFont",draw_info->
font);
01087 }
01088
if ((draw_info->
metrics != (
char *) NULL) &&
01089 (
IsAccessible(draw_info->
metrics) !=
MagickFalse))
01090 (
void) FT_Attach_File(face,draw_info->
metrics);
01091
if (face->num_charmaps != 0)
01092 status=FT_Set_Charmap(face,face->charmaps[0]);
01093 encoding_type=ft_encoding_unicode;
01094 status=FT_Select_Charmap(face,encoding_type);
01095
if (status != 0)
01096 {
01097 encoding_type=ft_encoding_none;
01098 status=FT_Select_Charmap(face,encoding_type);
01099 }
01100
if (encoding != (
char *) NULL)
01101 {
01102
if (
LocaleCompare(encoding,
"AdobeCustom") == 0)
01103 encoding_type=ft_encoding_adobe_custom;
01104
if (
LocaleCompare(encoding,
"AdobeExpert") == 0)
01105 encoding_type=ft_encoding_adobe_expert;
01106
if (
LocaleCompare(encoding,
"AdobeStandard") == 0)
01107 encoding_type=ft_encoding_adobe_standard;
01108
if (
LocaleCompare(encoding,
"AppleRoman") == 0)
01109 encoding_type=ft_encoding_apple_roman;
01110
if (
LocaleCompare(encoding,
"BIG5") == 0)
01111 encoding_type=ft_encoding_big5;
01112
if (
LocaleCompare(encoding,
"GB2312") == 0)
01113 encoding_type=ft_encoding_gb2312;
01114
if (
LocaleCompare(encoding,
"None") == 0)
01115 encoding_type=ft_encoding_none;
01116
if (
LocaleCompare(encoding,
"SJIScode") == 0)
01117 encoding_type=ft_encoding_sjis;
01118
if (
LocaleCompare(encoding,
"Symbol") == 0)
01119 encoding_type=ft_encoding_symbol;
01120
if (
LocaleCompare(encoding,
"Unicode") == 0)
01121 encoding_type=ft_encoding_unicode;
01122
if (
LocaleCompare(encoding,
"Wansung") == 0)
01123 encoding_type=ft_encoding_wansung;
01124 status=FT_Select_Charmap(face,encoding_type);
01125
if (status != 0)
01126
ThrowBinaryException(TypeError,
"UnrecognizedFontEncoding",encoding);
01127 }
01128
01129
01130
01131 resolution.
x=72.0;
01132 resolution.
y=72.0;
01133
if (draw_info->
density != (
char *) NULL)
01134 {
01135
GeometryInfo
01136 geometry_info;
01137
01138
MagickStatusType
01139 flags;
01140
01141 flags=
ParseGeometry(draw_info->
density,&geometry_info);
01142 resolution.
x=geometry_info.
rho;
01143 resolution.
y=geometry_info.
sigma;
01144
if ((flags &
SigmaValue) == 0)
01145 resolution.
y=resolution.
x;
01146 }
01147 (
void) FT_Set_Char_Size(face,(FT_F26Dot6) (64.0*draw_info->
pointsize),
01148 (FT_F26Dot6) (64.0*draw_info->
pointsize),(FT_UInt) resolution.
x,
01149 (FT_UInt) resolution.
y);
01150 metrics->
pixels_per_em.
x=face->size->metrics.x_ppem;
01151 metrics->
pixels_per_em.
y=face->size->metrics.y_ppem;
01152 metrics->
ascent=(
double) face->size->metrics.ascender/64.0;
01153 metrics->
descent=(
double) face->size->metrics.descender/64.0;
01154 metrics->
width=0;
01155 metrics->
height=(
double) face->size->metrics.height/64.0;
01156 metrics->
max_advance=(
double) face->size->metrics.max_advance/64.0;
01157 metrics->
bounds.
x1=0.0;
01158 metrics->
bounds.
y1=metrics->
descent;
01159 metrics->
bounds.
x2=metrics->
ascent+metrics->
descent;
01160 metrics->
bounds.
y2=metrics->
ascent+metrics->
descent;
01161 metrics->
underline_position=face->underline_position/64.0;
01162 metrics->
underline_thickness=face->underline_thickness/64.0;
01163
if (*draw_info->
text ==
'\0')
01164 {
01165 (
void) FT_Done_Face(face);
01166 (
void) FT_Done_FreeType(library);
01167
return(
MagickTrue);
01168 }
01169
01170
01171
01172
switch (encoding_type)
01173 {
01174
case ft_encoding_sjis:
01175 {
01176 text=EncodeSJIS(image,draw_info->
text,&length);
01177
break;
01178 }
01179
case ft_encoding_unicode:
01180 {
01181 text=EncodeUnicode(image,draw_info->
text,&length);
01182
break;
01183 }
01184
default:
01185 {
01186
if (draw_info->
encoding != (
char *) NULL)
01187 {
01188
if (
LocaleCompare(draw_info->
encoding,
"SJIS") == 0)
01189 {
01190 text=EncodeSJIS(image,draw_info->
text,&length);
01191
break;
01192 }
01193
if ((
LocaleCompare(draw_info->
encoding,
"UTF-8") == 0) ||
01194 (encoding_type != ft_encoding_none))
01195 {
01196 text=EncodeUnicode(image,draw_info->
text,&length);
01197
break;
01198 }
01199 }
01200 text=EncodeText(image,draw_info->
text,&length);
01201
break;
01202 }
01203 }
01204
if (text == (
unsigned short *) NULL)
01205 {
01206 (
void) FT_Done_Face(face);
01207 (
void) FT_Done_FreeType(library);
01208
ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
01209 image->filename);
01210 }
01211
01212
01213
01214
if (image->debug !=
MagickFalse)
01215 (
void)
LogMagickEvent(AnnotateEvent,
GetMagickModule(),
"Font %s; "
01216
"font-encoding %s; text-encoding %s; pointsize %g",
01217 draw_info->
font != (
char *) NULL ? draw_info->
font :
"none",
01218 encoding != (
char *) NULL ? encoding :
"none",
01219 draw_info->
encoding != (
char *) NULL ? draw_info->
encoding :
"none",
01220 draw_info->
pointsize);
01221 glyph.id=0;
01222 glyph.image=NULL;
01223 last_glyph.id=0;
01224 last_glyph.image=NULL;
01225 origin.x=0;
01226 origin.y=0;
01227 affine.xx=(FT_Fixed) (65536L*draw_info->
affine.
sx+0.5);
01228 affine.yx=(FT_Fixed) (-65536L*draw_info->
affine.
rx+0.5);
01229 affine.xy=(FT_Fixed) (-65536L*draw_info->
affine.
ry+0.5);
01230 affine.yy=(FT_Fixed) (65536L*draw_info->
affine.
sy+0.5);
01231 annotate_info=
CloneDrawInfo((
ImageInfo *) NULL,draw_info);
01232 (
void)
QueryColorDatabase(
"#000000ff",&annotate_info->
fill,&image->exception);
01233 (
void)
CloneString(&annotate_info->
primitive,
"path '");
01234
if (image->matte ==
MagickFalse)
01235
SetImageOpacity(image,OpaqueOpacity);
01236
for (i=0; i < (
long) length; i++)
01237 {
01238 glyph.id=FT_Get_Char_Index(face,text[i]);
01239
if ((glyph.id != 0) && (last_glyph.id != 0) && FT_HAS_KERNING(face))
01240 {
01241 FT_Vector
01242 kerning;
01243
01244 (
void) FT_Get_Kerning(face,last_glyph.id,glyph.id,ft_kerning_default,
01245 &kerning);
01246 origin.x+=kerning.x;
01247 }
01248 glyph.origin=origin;
01249
if (draw_info->
render !=
MagickFalse)
01250 status=FT_Load_Glyph(face,glyph.id,FT_LOAD_DEFAULT);
01251
else
01252 status=FT_Load_Glyph(face,glyph.id,FT_LOAD_NO_BITMAP);
01253
if (status !=
MagickFalse)
01254
continue;
01255 status=FT_Get_Glyph(face->glyph,&glyph.image);
01256
if (status !=
MagickFalse)
01257
continue;
01258 (
void) FT_Outline_Get_BBox(&((FT_OutlineGlyph) glyph.image)->outline,
01259 &bounds);
01260
if ((i == 0) || (bounds.xMin < metrics->
bounds.
x1))
01261 metrics->
bounds.
x1=bounds.xMin;
01262
if ((i == 0) || (bounds.yMin < metrics->
bounds.
y1))
01263 metrics->
bounds.
y1=bounds.yMin;
01264
if ((i == 0) || (bounds.xMax > metrics->
bounds.
x2))
01265 metrics->
bounds.
x2=bounds.xMax;
01266
if ((i == 0) || (bounds.yMax > metrics->
bounds.
y2))
01267 metrics->
bounds.
y2=bounds.yMax;
01268
if (draw_info->
render !=
MagickFalse)
01269
if ((draw_info->
stroke.
opacity !=
TransparentOpacity) ||
01270 (draw_info->
stroke_pattern != (
Image *) NULL))
01271 {
01272
01273
01274
01275 annotate_info->
affine.
tx=glyph.origin.x/64.0;
01276 annotate_info->
affine.
ty=glyph.origin.y/64.0;
01277 (
void) FT_Outline_Decompose(&((FT_OutlineGlyph) glyph.image)->outline,
01278 &OutlineMethods,annotate_info);
01279 }
01280 FT_Vector_Transform(&glyph.origin,&affine);
01281 (
void) FT_Glyph_Transform(glyph.image,&affine,&glyph.origin);
01282
if (draw_info->
render !=
MagickFalse)
01283 {
01284
01285
01286
01287 status=FT_Glyph_To_Bitmap(&glyph.image,ft_render_mode_normal,
01288 (FT_Vector *) NULL,MagickTrue);
01289
if (status !=
MagickFalse)
01290
continue;
01291 bitmap=(FT_BitmapGlyph) glyph.image;
01292 image->storage_class=
DirectClass;
01293 point.
x=offset->
x+bitmap->left;
01294 point.
y=offset->
y-bitmap->top;
01295 p=bitmap->bitmap.buffer;
01296
for (y=0; y < (
long) bitmap->bitmap.rows; y++)
01297 {
01298
if (((
long) (point.
y+y+0.5) < 0) ||
01299 ((
long) (point.
y+y+0.5) >= (
long) image->rows))
01300 {
01301 p+=bitmap->bitmap.width;
01302
continue;
01303 }
01304 q=
GetImagePixels(image,(
long) (point.
x+0.5),(
long) (point.
y+y+0.5),
01305 bitmap->bitmap.width,1);
01306 active=q != (
PixelPacket *) NULL ? MagickTrue : MagickFalse;
01307 for (x=0; x < (long) bitmap->bitmap.width; x++)
01308 {
01309 if (((
long) (point.
x+x+0.5) < 0) || (*p == 0) ||
01310 ((
unsigned long) (point.
x+x+0.5) >= image->columns))
01311 {
01312 p++;
01313 q++;
01314
continue;
01315 }
01316
if (draw_info->
text_antialias)
01317 fill_opacity=(
MagickRealType) (*p)/255.0;
01318
else
01319 fill_opacity=(*p) > 127 ? 1.0 : 0.0;
01320
if (active ==