You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2981 lines
88 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W W M M FFFFF %
% W W MM MM F %
% W W W M M M FFF %
% WW WW M M F %
% W W M M F %
% %
% %
% Read Windows Metafile Format %
% %
% Software Design %
% Cristy %
% December 2000 %
% %
% %
% Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization %
% dedicated to making software imaging solutions freely available. %
% %
% You may not use this file except in compliance with the License. You may %
% obtain a copy of the License at %
% %
% https://imagemagick.org/script/license.php %
% %
% Unless required by applicable law or agreed to in writing, software %
% distributed under the License is distributed on an "AS IS" BASIS, %
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
% See the License for the specific language governing permissions and %
% limitations under the License. %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*/
/*
Include declarations.
*/
#include "MagickCore/studio.h"
#include "MagickCore/property.h"
#include "MagickCore/blob.h"
#include "MagickCore/blob-private.h"
#include "MagickCore/color.h"
#include "MagickCore/color-private.h"
#include "MagickCore/constitute.h"
#include "MagickCore/exception.h"
#include "MagickCore/exception-private.h"
#include "MagickCore/image.h"
#include "MagickCore/image-private.h"
#include "MagickCore/list.h"
#include "MagickCore/log.h"
#include "MagickCore/magick.h"
#include "MagickCore/memory_.h"
#include "MagickCore/monitor.h"
#include "MagickCore/monitor-private.h"
#include "MagickCore/paint.h"
#include "MagickCore/quantum-private.h"
#include "MagickCore/static.h"
#include "MagickCore/string_.h"
#include "MagickCore/module.h"
#include "MagickCore/type.h"
#include "MagickCore/module.h"
#if defined(MAGICKCORE_WMF_DELEGATE)
#include "MagickWand/MagickWand.h"
#endif
#if defined(__CYGWIN__)
#undef MAGICKCORE_SANS_DELEGATE
#endif
#if defined(MAGICKCORE_SANS_DELEGATE)
#include "libwmf/api.h"
#include "libwmf/eps.h"
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% R e a d W M F I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ReadWMFImage() reads an Windows Metafile 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 ReadWMFImage method is:
%
% Image *ReadWMFImage(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 int WMFReadBlob(void *image)
{
return(ReadBlobByte((Image *) image));
}
static int WMFSeekBlob(void *image,long offset)
{
return((int) SeekBlob((Image *) image,(MagickOffsetType) offset,SEEK_SET));
}
static long WMFTellBlob(void *image)
{
return((long) TellBlob((Image*) image));
}
static Image *ReadWMFImage(const ImageInfo *image_info,ExceptionInfo *exception)
{
char
filename[MagickPathExtent];
int
unique_file;
FILE
*file;
Image
*image;
ImageInfo
*read_info;
MagickBooleanType
status;
size_t
flags;
wmfAPI
*wmf_info;
wmfAPI_Options
options;
wmfD_Rect
bounding_box;
wmf_eps_t
*eps_info;
wmf_error_t
wmf_status;
/*
Read WMF image.
*/
image=AcquireImage(image_info,exception);
status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
if (status == MagickFalse)
{
image=DestroyImageList(image);
return((Image *) NULL);
}
wmf_info=(wmfAPI *) NULL;
flags=0;
flags|=WMF_OPT_IGNORE_NONFATAL;
flags|=WMF_OPT_FUNCTION;
options.function=wmf_eps_function;
wmf_status=wmf_api_create(&wmf_info,(unsigned long) flags,&options);
if (wmf_status != wmf_E_None)
{
if (wmf_info != (wmfAPI *) NULL)
wmf_api_destroy(wmf_info);
ThrowReaderException(DelegateError,"UnableToInitializeWMFLibrary");
}
wmf_status=wmf_bbuf_input(wmf_info,WMFReadBlob,WMFSeekBlob,WMFTellBlob,
(void *) image);
if (wmf_status != wmf_E_None)
{
ipa_device_close(wmf_info);
wmf_api_destroy(wmf_info);
ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
image->filename);
image=DestroyImageList(image);
return((Image *) NULL);
}
wmf_status=wmf_scan(wmf_info,0,&bounding_box);
if (wmf_status != wmf_E_None)
{
ipa_device_close(wmf_info);
wmf_api_destroy(wmf_info);
ThrowReaderException(DelegateError,"FailedToScanFile");
}
eps_info=WMF_EPS_GetData(wmf_info);
file=(FILE *) NULL;
unique_file=AcquireUniqueFileResource(filename);
if (unique_file != -1)
file=fdopen(unique_file,"wb");
if ((unique_file == -1) || (file == (FILE *) NULL))
{
ipa_device_close(wmf_info);
wmf_api_destroy(wmf_info);
ThrowReaderException(FileOpenError,"UnableToCreateTemporaryFile");
}
eps_info->out=wmf_stream_create(wmf_info,file);
eps_info->bbox=bounding_box;
wmf_status=wmf_play(wmf_info,0,&bounding_box);
if (wmf_status != wmf_E_None)
{
ipa_device_close(wmf_info);
wmf_api_destroy(wmf_info);
ThrowReaderException(DelegateError,"FailedToRenderFile");
}
(void) fclose(file);
wmf_api_destroy(wmf_info);
(void) CloseBlob(image);
image=DestroyImage(image);
/*
Read EPS image.
*/
read_info=CloneImageInfo(image_info);
SetImageInfoBlob(read_info,(void *) NULL,0);
(void) FormatLocaleString(read_info->filename,MagickPathExtent,"eps:%s",
filename);
image=ReadImage(read_info,exception);
read_info=DestroyImageInfo(read_info);
if (image != (Image *) NULL)
{
(void) CopyMagickString(image->filename,image_info->filename,
MagickPathExtent);
(void) CopyMagickString(image->magick_filename,image_info->filename,
MagickPathExtent);
(void) CopyMagickString(image->magick,"WMF",MagickPathExtent);
}
(void) RelinquishUniqueFileResource(filename);
return(GetFirstImageInList(image));
}
#elif defined(MAGICKCORE_WMF_DELEGATE)
#define ERR(API) ((API)->err != wmf_E_None)
#define XC(x) ((double) x)
#define YC(y) ((double) y)
#if !defined(M_PI)
# define M_PI MagickPI
#endif
#if defined(MAGICKCORE_HAVE_FT2BUILD_H)
# include <ft2build.h>
#endif
#include "libwmf/fund.h"
#include "libwmf/types.h"
#include "libwmf/api.h"
#undef SRCCOPY
#undef SRCPAINT
#undef SRCAND
#undef SRCINVERT
#undef SRCERASE
#undef NOTSRCCOPY
#undef NOTSRCERASE
#undef MERGECOPY
#undef MERGEPAINT
#undef PATCOPY
#undef PATPAINT
#undef PATINVERT
#undef DSTINVERT
#undef BLACKNESS
#undef WHITENESS
/* The following additinal undefs were required for MinGW */
#undef BS_HOLLOW
#undef PS_STYLE_MASK
#undef PS_ENDCAP_ROUND
#undef PS_ENDCAP_SQUARE
#undef PS_ENDCAP_FLAT
#undef PS_ENDCAP_MASK
#undef PS_JOIN_ROUND
#undef PS_JOIN_BEVEL
#undef PS_JOIN_MITER
#undef PS_COSMETIC
#undef PS_GEOMETRIC
#undef PS_TYPE_MASK
#undef STRETCH_ANDSCANS
#undef STRETCH_ORSCANS
#undef STRETCH_DELETESCANS
#undef STRETCH_HALFTONE
#undef ETO_OPAQUE
#undef ETO_CLIPPED
#undef ETO_GLYPH_INDEX
#undef ETO_RTLREADING
#include "libwmf/defs.h"
#include "libwmf/ipa.h"
#include "libwmf/color.h"
#include "libwmf/macro.h"
/* Unit conversions */
#define TWIPS_PER_INCH 1440
#define CENTIMETERS_PER_INCH 2.54
#define POINTS_PER_INCH 72
#if defined(MAGICKCORE_WMF_DELEGATE)
# define wmf_api_create(api,flags,options) wmf_lite_create(api,flags,options)
# define wmf_api_destroy(api) wmf_lite_destroy(api)
# undef WMF_FONT_PSNAME
# define WMF_FONT_PSNAME(F) ((F)->user_data ? ((wmf_magick_font_t*) (F)->user_data)->ps_name : 0)
typedef struct _wmf_magick_font_t wmf_magick_font_t;
struct _wmf_magick_font_t
{
char* ps_name;
double pointsize;
};
#endif
typedef struct _wmf_magick_t wmf_magick_t;
struct _wmf_magick_t
{
/* Bounding box */
wmfD_Rect
bbox;
/* Scale and translation factors */
double
scale_x,
scale_y,
translate_x,
translate_y,
rotate;
/* Vector output */
DrawingWand
*draw_wand;
ExceptionInfo
*exception;
/* ImageMagick image */
Image
*image;
/* ImageInfo */
const ImageInfo
*image_info;
/* DrawInfo */
DrawInfo
*draw_info;
/* Pattern ID */
unsigned long
pattern_id;
/* Clip path flag */
MagickBooleanType
clipping;
/* Clip path ID */
unsigned long
clip_mask_id;
/* Push depth */
long
push_depth;
};
#define WMF_MAGICK_GetData(Z) ((wmf_magick_t*)((Z)->device_data))
#define WMF_MAGICK_GetFontData(Z) \
((wmf_magick_font_t*)((wmfFontData *)Z->font_data)->user_data)
#define WmfDrawingWand (((wmf_magick_t*)((API)->device_data))->draw_wand)
/* Enum to control whether util_set_brush applies brush to fill or
stroke. */
typedef enum
{
BrushApplyFill,
BrushApplyStroke
} BrushApply;
/* Enum to specify arc type */
typedef enum
{
magick_arc_ellipse = 0,
magick_arc_open,
magick_arc_pie,
magick_arc_chord
}
magick_arc_t;
#if defined(MAGICKCORE_WMF_DELEGATE)
static void lite_font_init (wmfAPI* API, wmfAPI_Options* options);
static void lite_font_map(wmfAPI* API,wmfFont* font);
static float lite_font_stringwidth(wmfAPI* API, wmfFont* font, char* str);
#endif
static void draw_fill_color_rgb(wmfAPI* API, const wmfRGB* rgb);
static void draw_stroke_color_rgb(wmfAPI* API, const wmfRGB* rgb);
static void draw_pattern_push(wmfAPI* API, unsigned long id, unsigned long columns, unsigned long rows);
static int ipa_blob_read(void* wand);
static int ipa_blob_seek(void* wand,long position);
static long ipa_blob_tell(void* wand);
static void ipa_bmp_draw(wmfAPI * API, wmfBMP_Draw_t * bmp_draw);
static void ipa_bmp_free(wmfAPI * API, wmfBMP * bmp);
static void ipa_bmp_read(wmfAPI * API, wmfBMP_Read_t * bmp_read);
static void ipa_device_begin(wmfAPI * API);
static void ipa_device_close(wmfAPI * API);
static void ipa_device_end(wmfAPI * API);
static void ipa_device_open(wmfAPI * API);
static void ipa_draw_arc(wmfAPI * API, wmfDrawArc_t * draw_arc);
static void ipa_draw_chord(wmfAPI * API, wmfDrawArc_t * draw_arc);
static void ipa_draw_ellipse(wmfAPI * API, wmfDrawArc_t * draw_arc);
static void ipa_draw_line(wmfAPI * API, wmfDrawLine_t * draw_line);
static void ipa_draw_pie(wmfAPI * API, wmfDrawArc_t * draw_arc);
static void ipa_draw_pixel(wmfAPI * API, wmfDrawPixel_t * draw_pixel);
static void ipa_draw_polygon(wmfAPI * API, wmfPolyLine_t * poly_line);
#if defined(MAGICKCORE_WMF_DELEGATE)
static void ipa_draw_polypolygon(wmfAPI * API, wmfPolyPoly_t* polypolygon);
#endif
static void ipa_draw_rectangle(wmfAPI * API, wmfDrawRectangle_t * draw_rect);
static void ipa_draw_text(wmfAPI * API, wmfDrawText_t * draw_text);
static void ipa_flood_exterior(wmfAPI * API, wmfFlood_t * flood);
static void ipa_flood_interior(wmfAPI * API, wmfFlood_t * flood);
static void ipa_functions(wmfAPI * API);
static void ipa_poly_line(wmfAPI * API, wmfPolyLine_t * poly_line);
static void ipa_region_clip(wmfAPI * API, wmfPolyRectangle_t * poly_rect);
static void ipa_region_frame(wmfAPI * API, wmfPolyRectangle_t * poly_rect);
static void ipa_region_paint(wmfAPI * API, wmfPolyRectangle_t * poly_rect);
static void ipa_rop_draw(wmfAPI * API, wmfROP_Draw_t * rop_draw);
static void ipa_udata_copy(wmfAPI * API, wmfUserData_t * userdata);
static void ipa_udata_free(wmfAPI * API, wmfUserData_t * userdata);
static void ipa_udata_init(wmfAPI * API, wmfUserData_t * userdata);
static void ipa_udata_set(wmfAPI * API, wmfUserData_t * userdata);
static int magick_progress_callback(void* wand,float quantum);
static void util_draw_arc(wmfAPI * API, wmfDrawArc_t * draw_arc,magick_arc_t finish);
static double util_pointsize( wmfAPI* API, wmfFont* font, char* str, double font_height, ExceptionInfo *);
static void util_set_brush(wmfAPI * API, wmfDC * dc, const BrushApply brush_apply);
static void util_set_pen(wmfAPI * API, wmfDC * dc);
/* Progress callback */
int magick_progress_callback(void *context,float quantum)
{
Image
*image;
MagickBooleanType
status;
(void) quantum;
image=(Image *) context;
assert(image->signature == MagickCoreSignature);
status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
GetBlobSize(image));
return(status != MagickFalse ? 0 : 1);
}
/* Set fill color */
static void draw_fill_color_string(DrawingWand *drawing_wand,const char *color)
{
PixelWand
*fill_color;
fill_color=NewPixelWand();
PixelSetColor(fill_color,color);
DrawSetFillColor(drawing_wand,fill_color);
fill_color=DestroyPixelWand(fill_color);
}
static void draw_fill_color_rgb( wmfAPI* API, const wmfRGB* rgb )
{
PixelWand
*fill_color;
fill_color=NewPixelWand();
PixelSetRedQuantum(fill_color,ScaleCharToQuantum(rgb->r));
PixelSetGreenQuantum(fill_color,ScaleCharToQuantum(rgb->g));
PixelSetBlueQuantum(fill_color,ScaleCharToQuantum(rgb->b));
PixelSetAlphaQuantum(fill_color,OpaqueAlpha);
DrawSetFillColor(WmfDrawingWand,fill_color);
fill_color=DestroyPixelWand(fill_color);
}
/* Set stroke color */
static void draw_stroke_color_string(DrawingWand *drawing_wand,const char *color)
{
PixelWand
*stroke_color;
stroke_color=NewPixelWand();
PixelSetColor(stroke_color,color);
DrawSetStrokeColor(drawing_wand,stroke_color);
stroke_color=DestroyPixelWand(stroke_color);
}
static void draw_stroke_color_rgb( wmfAPI* API, const wmfRGB* rgb )
{
PixelWand
*stroke_color;
stroke_color=NewPixelWand();
PixelSetRedQuantum(stroke_color,ScaleCharToQuantum(rgb->r));
PixelSetGreenQuantum(stroke_color,ScaleCharToQuantum(rgb->g));
PixelSetBlueQuantum(stroke_color,ScaleCharToQuantum(rgb->b));
PixelSetAlphaQuantum(stroke_color,OpaqueAlpha);
DrawSetStrokeColor(WmfDrawingWand,stroke_color);
stroke_color=DestroyPixelWand(stroke_color);
}
/* Set under color */
static void draw_under_color_string(DrawingWand *drawing_wand,const char *color)
{
PixelWand
*under_color;
under_color=NewPixelWand();
PixelSetColor(under_color,color);
DrawSetTextUnderColor(drawing_wand,under_color);
under_color=DestroyPixelWand(under_color);
}
static void draw_pattern_push( wmfAPI* API,
unsigned long id,
unsigned long columns,
unsigned long rows )
{
char
pattern_id[MagickPathExtent];
(void) FormatLocaleString(pattern_id,MagickPathExtent,"brush_%lu",id);
(void) DrawPushPattern(WmfDrawingWand,pattern_id,0,0,columns,rows);
}
/* Pattern/Bit BLT with raster operation (ROP) support. Invoked by
META_PATBLT, which is equivalent to Windows PatBlt() call, or by
META_DIBBITBLT which is equivalent to Windows BitBlt() call. */
/* The BitBlt function transfers pixels from a rectangular area in one
device wand called the 'source', to a rectangular area of the
same size in another device wand, called the 'destination'. */
static void ipa_rop_draw(wmfAPI * API, wmfROP_Draw_t * rop_draw)
{
/* wmfBrush */
/* *brush = WMF_DC_BRUSH(rop_draw->dc); */
/* wmfBMP */
/* *brush_bmp = WMF_BRUSH_BITMAP(brush); */
if (TO_FILL(rop_draw) == 0)
return;
/* Save graphic wand */
(void) PushDrawingWand(WmfDrawingWand);
/* FIXME: finish implementing (once we know what it is supposed to do!) */
/*
struct _wmfROP_Draw_t
{ wmfDC* dc;
wmfD_Coord TL;
wmfD_Coord BR;
U32 ROP;
double pixel_width;
double pixel_height;
};
*/
/* if (brush_bmp && brush_bmp->data != 0) */
/* printf("Have an image!\n"); */
switch (rop_draw->ROP) /* Ternary raster operations */
{
case SRCCOPY: /* dest = source */
printf("ipa_rop_draw SRCCOPY ROP mode not implemented\n");
break;
case SRCPAINT: /* dest = source OR dest */
printf("ipa_rop_draw SRCPAINT ROP mode not implemented\n");
break;
case SRCAND: /* dest = source AND dest */
printf("ipa_rop_draw SRCAND ROP mode not implemented\n");
break;
case SRCINVERT: /* dest = source XOR dest */
printf("ipa_rop_draw SRCINVERT ROP mode not implemented\n");
break;
case SRCERASE: /* dest = source AND (NOT dest) */
printf("ipa_rop_draw SRCERASE ROP mode not implemented\n");
break;
case NOTSRCCOPY: /* dest = (NOT source) */
printf("ipa_rop_draw NOTSRCCOPY ROP mode not implemented\n");
break;
case NOTSRCERASE: /* dest = (NOT src) AND (NOT dest) */
printf("ipa_rop_draw NOTSRCERASE ROP mode not implemented\n");
break;
case MERGECOPY: /* dest = (source AND pattern) */
printf("ipa_rop_draw MERGECOPY ROP mode not implemented\n");
break;
case MERGEPAINT: /* dest = (NOT source) OR dest */
printf("ipa_rop_draw MERGEPAINT ROP mode not implemented\n");
break;
case PATCOPY: /* dest = pattern */
util_set_brush(API, rop_draw->dc, BrushApplyFill);
break;
case PATPAINT: /* dest = DPSnoo */
printf("ipa_rop_draw PATPAINT ROP mode not implemented\n");
break;
case PATINVERT: /* dest = pattern XOR dest */
printf("ipa_rop_draw PATINVERT ROP mode not implemented\n");
break;
case DSTINVERT: /* dest = (NOT dest) */
printf("ipa_rop_draw DSTINVERT ROP mode not implemented\n");
break;
case BLACKNESS: /* dest = BLACK */
draw_fill_color_string(WmfDrawingWand,"black");
break;
case WHITENESS: /* dest = WHITE */
draw_fill_color_string(WmfDrawingWand,"white");
break;
default:
printf("ipa_rop_draw 0x%x ROP mode not implemented\n", rop_draw->ROP);
break;
}
DrawRectangle(WmfDrawingWand,
XC(rop_draw->TL.x), YC(rop_draw->TL.y),
XC(rop_draw->BR.x), YC(rop_draw->BR.y));
/* Restore graphic wand */
(void) PopDrawingWand(WmfDrawingWand);
}
static void ipa_bmp_draw(wmfAPI *API, wmfBMP_Draw_t *bmp_draw)
{
wmf_magick_t
*ddata = WMF_MAGICK_GetData(API);
ExceptionInfo
*exception;
Image
*image;
MagickWand
*magick_wand;
double
height,
width;
PixelInfo
white;
if (bmp_draw->bmp.data == 0)
return;
image = (Image*)bmp_draw->bmp.data;
if (!image)
return;
exception=ddata->exception;
if (bmp_draw->crop.x || bmp_draw->crop.y ||
(bmp_draw->crop.w != bmp_draw->bmp.width) ||
(bmp_draw->crop.h != bmp_draw->bmp.height))
{
/* Image needs to be cropped */
Image
*crop_image;
RectangleInfo
crop_info;
crop_info.x = bmp_draw->crop.x;
crop_info.y = bmp_draw->crop.y;
crop_info.width = bmp_draw->crop.w;
crop_info.height = bmp_draw->crop.h;
crop_image = CropImage( image, &crop_info, exception );
if (crop_image)
{
image=DestroyImageList(image);
image = crop_image;
bmp_draw->bmp.data = (void*)image;
}
}
QueryColorCompliance( "white", AllCompliance, &white, exception );
if ( ddata->image_info->texture ||
!(IsPixelInfoEquivalent(&ddata->image_info->background_color,&white)) ||
ddata->image_info->background_color.alpha != OpaqueAlpha )
{
/*
Set image white background to transparent so that it may be
overlaid over non-white backgrounds.
*/
QueryColorCompliance( "white", AllCompliance, &white, exception );
TransparentPaintImage( image, &white, QuantumRange, MagickFalse, exception );
}
width = fabs(bmp_draw->pixel_width * (double) bmp_draw->crop.w);
height = fabs(bmp_draw->pixel_height * (double) bmp_draw->crop.h);
magick_wand=NewMagickWandFromImage(image);
(void) DrawComposite(WmfDrawingWand, CopyCompositeOp,
XC(bmp_draw->pt.x) * ddata->scale_x, YC(bmp_draw->pt.y) * ddata->scale_y,
width * ddata->scale_x, height * ddata->scale_y, magick_wand);
magick_wand=DestroyMagickWand(magick_wand);
#if 0
printf("bmp_draw->bmp.data = 0x%lx\n", (long)bmp_draw->bmp.data);
printf("registry id = %li\n", id);
/* printf("pixel_width = %g\n", bmp_draw->pixel_width); */
/* printf("pixel_height = %g\n", bmp_draw->pixel_height); */
printf("bmp_draw->bmp WxH = %ix%i\n", bmp_draw->bmp.width, bmp_draw->bmp.height);
printf("bmp_draw->crop WxH = %ix%i\n", bmp_draw->crop.w, bmp_draw->crop.h);
printf("bmp_draw->crop x,y = %i,%i\n", bmp_draw->crop.x, bmp_draw->crop.y);
printf("image size WxH = %lux%lu\n", image->columns, image->rows);
#endif
}
static void ipa_bmp_read(wmfAPI * API, wmfBMP_Read_t * bmp_read) {
wmf_magick_t
*ddata = WMF_MAGICK_GetData(API);
ExceptionInfo
*exception;
Image
*image;
ImageInfo
*image_info;
bmp_read->bmp.data = 0;
image_info=CloneImageInfo(ddata->image_info);
exception=ddata->exception;
(void) CopyMagickString(image_info->magick,"DIB",MagickPathExtent);
if (bmp_read->width || bmp_read->height)
{
char
size[MagickPathExtent];
(void) FormatLocaleString(size,MagickPathExtent,"%ux%u",bmp_read->width,
bmp_read->height);
CloneString(&image_info->size,size);
}
#if 0
printf("ipa_bmp_read: buffer=0x%lx length=%ld, width=%i, height=%i\n",
(long) bmp_read->buffer, bmp_read->length,
bmp_read->width, bmp_read->height);
#endif
image=BlobToImage(image_info, (const void *) bmp_read->buffer,
bmp_read->length, exception);
image_info=DestroyImageInfo(image_info);
if (image != (Image *) NULL)
{
#if 0
printf("ipa_bmp_read: rows=%ld,columns=%ld\n\n", image->rows, image->columns);
#endif
bmp_read->bmp.data = (void*)image;
bmp_read->bmp.width = (U16)image->columns;
bmp_read->bmp.height = (U16)image->rows;
}
}
static void ipa_bmp_free(wmfAPI * API, wmfBMP * bmp)
{
(void) API;
DestroyImageList((Image*)bmp->data);
bmp->data = (void*) 0;
bmp->width = (U16) 0;
bmp->height = (U16) 0;
}
/*
This called by wmf_play() the *first* time the meta file is played
*/
static void ipa_device_open(wmfAPI * API)
{
wmf_magick_t
*ddata = WMF_MAGICK_GetData (API);
ddata->pattern_id = 0;
ddata->clipping = MagickFalse;
ddata->clip_mask_id = 0;
ddata->push_depth = 0;
ddata->draw_wand = AcquireDrawingWand(ddata->draw_info,ddata->image);
}
/*
This called by wmf_api_destroy()
*/
static void ipa_device_close(wmfAPI * API)
{
wmf_magick_t
*ddata = WMF_MAGICK_GetData(API);
if (ddata->draw_wand != (DrawingWand *) NULL)
{
DestroyDrawingWand(ddata->draw_wand);
ddata->draw_wand=(DrawingWand *) NULL;
}
if (ddata->draw_info != (DrawInfo *) NULL)
{
DestroyDrawInfo(ddata->draw_info);
ddata->draw_info=(DrawInfo *)NULL;
}
if (WMF_MAGICK_GetFontData(API)->ps_name)
WMF_MAGICK_GetFontData(API)->ps_name=(char *) RelinquishMagickMemory(
WMF_MAGICK_GetFontData(API)->ps_name);
}
/*
This called from the beginning of each play for initial page setup
*/
static void ipa_device_begin(wmfAPI * API)
{
char
comment[MagickPathExtent];
wmf_magick_t
*ddata = WMF_MAGICK_GetData(API);
/* Make SVG output happy */
(void) PushDrawingWand(WmfDrawingWand);
DrawSetViewbox(WmfDrawingWand,0,0,ddata->image->columns,ddata->image->rows);
(void) FormatLocaleString(comment,MagickPathExtent,"Created by %s",
GetMagickVersion((size_t *) NULL));
DrawComment(WmfDrawingWand,comment);
/* Scale width and height to image */
DrawScale(WmfDrawingWand, ddata->scale_x, ddata->scale_y);
/* Translate to TL corner of bounding box */
DrawTranslate(WmfDrawingWand, ddata->translate_x, ddata->translate_y);
/* Apply rotation */
DrawRotate(WmfDrawingWand, ddata->rotate);
if (ddata->image_info->texture == NULL)
{
PixelWand
*background_color;
/* Draw rectangle in background color */
background_color=NewPixelWand();
PixelSetPixelColor(background_color,&ddata->image->background_color);
DrawSetFillColor(WmfDrawingWand,background_color);
background_color=DestroyPixelWand(background_color);
DrawRectangle(WmfDrawingWand,
XC(ddata->bbox.TL.x),YC(ddata->bbox.TL.y),
XC(ddata->bbox.BR.x),YC(ddata->bbox.BR.y));
}
else
{
/* Draw rectangle with texture image the SVG way */
Image
*image;
ImageInfo
*image_info;
ExceptionInfo
*exception;
exception=AcquireExceptionInfo();
image_info = CloneImageInfo((ImageInfo *) 0);
(void) CopyMagickString(image_info->filename,ddata->image_info->texture,
MagickPathExtent);
if ( ddata->image_info->size )
CloneString(&image_info->size,ddata->image_info->size);
image = ReadImage(image_info,exception);
(void) DestroyExceptionInfo(exception);
image_info=DestroyImageInfo(image_info);
if (image)
{
char
pattern_id[MagickPathExtent];
MagickWand
*magick_wand;
(void) CopyMagickString(image->magick,"MIFF",MagickPathExtent);
DrawPushDefs(WmfDrawingWand);
draw_pattern_push(API,ddata->pattern_id,image->columns,image->rows);
magick_wand=NewMagickWandFromImage(image);
(void) DrawComposite(WmfDrawingWand,CopyCompositeOp,0,0,
image->columns,image->rows,magick_wand);
magick_wand=DestroyMagickWand(magick_wand);
(void) DrawPopPattern(WmfDrawingWand);
DrawPopDefs(WmfDrawingWand);
(void) FormatLocaleString(pattern_id,MagickPathExtent,"#brush_%lu",
ddata->pattern_id);
(void) DrawSetFillPatternURL(WmfDrawingWand,pattern_id);
++ddata->pattern_id;
DrawRectangle(WmfDrawingWand,
XC(ddata->bbox.TL.x),YC(ddata->bbox.TL.y),
XC(ddata->bbox.BR.x),YC(ddata->bbox.BR.y));
image=DestroyImageList(image);
}
else
{
LogMagickEvent(CoderEvent,GetMagickModule(),
"reading texture image failed!");
}
}
DrawSetClipRule(WmfDrawingWand,EvenOddRule); /* Default for WMF is ALTERNATE polygon fill mode */
draw_fill_color_string(WmfDrawingWand,"none"); /* Default brush is WHITE_BRUSH */
draw_stroke_color_string(WmfDrawingWand,"none"); /* Default pen is BLACK_PEN */
DrawSetStrokeLineCap(WmfDrawingWand,ButtCap); /* Default linecap is PS_ENDCAP_FLAT */
DrawSetStrokeLineJoin(WmfDrawingWand,MiterJoin); /* Default linejoin is PS_JOIN_MITER */
draw_under_color_string(WmfDrawingWand,"white"); /* Default text box is white */
}
/*
This called from the end of each play for page termination
*/
static void ipa_device_end(wmfAPI * API)
{
wmf_magick_t
*ddata = WMF_MAGICK_GetData(API);
/* Reset any existing clip paths by popping wand */
if (ddata->clipping)
(void) PopDrawingWand(WmfDrawingWand);
ddata->clipping = MagickFalse;
/* Make SVG output happy */
(void) PopDrawingWand(WmfDrawingWand);
}
static void ipa_flood_interior(wmfAPI * API, wmfFlood_t * flood)
{
/* Save graphic wand */
(void) PushDrawingWand(WmfDrawingWand);
draw_fill_color_rgb(API,&(flood->color));
DrawColor(WmfDrawingWand,XC(flood->pt.x), YC(flood->pt.y),
FillToBorderMethod);
/* Restore graphic wand */
(void) PopDrawingWand(WmfDrawingWand);
}
static void ipa_flood_exterior(wmfAPI * API, wmfFlood_t * flood)
{
/* Save graphic wand */
(void) PushDrawingWand(WmfDrawingWand);
draw_fill_color_rgb(API,&(flood->color));
if (flood->type == FLOODFILLSURFACE)
DrawColor(WmfDrawingWand, XC(flood->pt.x), YC(flood->pt.y),
FloodfillMethod);
else
DrawColor(WmfDrawingWand, XC(flood->pt.x), YC(flood->pt.y),
FillToBorderMethod);
/* Restore graphic wand */
(void) PopDrawingWand(WmfDrawingWand);
}
static void ipa_draw_pixel(wmfAPI * API, wmfDrawPixel_t * draw_pixel)
{
/* Save graphic wand */
(void) PushDrawingWand(WmfDrawingWand);
draw_stroke_color_string(WmfDrawingWand,"none");
draw_fill_color_rgb(API,&(draw_pixel->color));
DrawRectangle(WmfDrawingWand,
XC(draw_pixel->pt.x),
YC(draw_pixel->pt.y),
XC(draw_pixel->pt.x + draw_pixel->pixel_width),
YC(draw_pixel->pt.y + draw_pixel->pixel_height));
/* Restore graphic wand */
(void) PopDrawingWand(WmfDrawingWand);
}
static void ipa_draw_pie(wmfAPI * API, wmfDrawArc_t * draw_arc)
{
util_draw_arc(API, draw_arc, magick_arc_pie);
}
static void ipa_draw_chord(wmfAPI * API, wmfDrawArc_t * draw_arc)
{
util_draw_arc(API, draw_arc, magick_arc_chord);
}
static void ipa_draw_arc(wmfAPI * API, wmfDrawArc_t * draw_arc)
{
util_draw_arc(API, draw_arc, magick_arc_open);
}
static void ipa_draw_ellipse(wmfAPI * API, wmfDrawArc_t * draw_arc)
{
util_draw_arc(API, draw_arc, magick_arc_ellipse);
}
static void util_draw_arc(wmfAPI * API,
wmfDrawArc_t * draw_arc, magick_arc_t finish)
{
wmfD_Coord
BR,
O,
TL,
center,
end,
start;
double
phi_e = 360,
phi_s = 0;
double
Rx,
Ry;
/* Save graphic wand */
(void) PushDrawingWand(WmfDrawingWand);
if (TO_FILL(draw_arc) || TO_DRAW(draw_arc))
{
center.x = (draw_arc->TL.x + draw_arc->BR.x) / 2;
center.y = (draw_arc->TL.y + draw_arc->BR.y) / 2;
start = center;
end = center;
if (finish != magick_arc_ellipse)
{
draw_arc->start.x += center.x;
draw_arc->start.y += center.y;
draw_arc->end.x += center.x;
draw_arc->end.y += center.y;
}
TL = draw_arc->TL;
BR = draw_arc->BR;
O = center;
if (finish != magick_arc_ellipse)
{
start = draw_arc->start;
end = draw_arc->end;
}
Rx = (BR.x - TL.x) / 2;
Ry = (BR.y - TL.y) / 2;
if (finish != magick_arc_ellipse)
{
start.x -= O.x;
start.y -= O.y;
end.x -= O.x;
end.y -= O.y;
phi_s = atan2((double) start.y, (double) start.x) * 180 / MagickPI;
phi_e = atan2((double) end.y, (double) end.x) * 180 / MagickPI;
if (phi_e <= phi_s)
phi_e += 360;
}
util_set_pen(API, draw_arc->dc);
if (finish == magick_arc_open)
draw_fill_color_string(WmfDrawingWand,"none");
else
util_set_brush(API, draw_arc->dc, BrushApplyFill);
if (finish == magick_arc_ellipse)
DrawEllipse(WmfDrawingWand, XC(O.x), YC(O.y), Rx, Ry, 0, 360);
else if (finish == magick_arc_pie)
{
DrawPathStart(WmfDrawingWand);
DrawPathMoveToAbsolute(WmfDrawingWand, XC(O.x+start.x),
YC(O.y+start.y));
DrawPathEllipticArcAbsolute(WmfDrawingWand, Rx, Ry, 0, MagickFalse,
MagickTrue, XC(O.x+end.x), YC(O.y+end.y));
DrawPathLineToAbsolute(WmfDrawingWand, XC(O.x), YC(O.y));
DrawPathClose(WmfDrawingWand);
DrawPathFinish(WmfDrawingWand);
}
else if (finish == magick_arc_chord)
{
DrawArc(WmfDrawingWand, XC(draw_arc->TL.x), YC(draw_arc->TL.y),
XC(draw_arc->BR.x), XC(draw_arc->BR.y), phi_s, phi_e);
DrawLine(WmfDrawingWand, XC(draw_arc->BR.x-start.x),
YC(draw_arc->BR.y-start.y), XC(draw_arc->BR.x-end.x),
YC(draw_arc->BR.y-end.y));
}
else /* if (finish == magick_arc_open) */
DrawArc(WmfDrawingWand, XC(draw_arc->TL.x), YC(draw_arc->TL.y),
XC(draw_arc->BR.x), XC(draw_arc->BR.y), phi_s, phi_e);
}
/* Restore graphic wand */
(void) PopDrawingWand(WmfDrawingWand);
}
static void ipa_draw_line(wmfAPI * API, wmfDrawLine_t * draw_line)
{
/* Save graphic wand */
(void) PushDrawingWand(WmfDrawingWand);
if (TO_DRAW(draw_line))
{
util_set_pen(API, draw_line->dc);
DrawLine(WmfDrawingWand,
XC(draw_line->from.x), YC(draw_line->from.y),
XC(draw_line->to.x), YC(draw_line->to.y));
}
/* Restore graphic wand */
(void) PopDrawingWand(WmfDrawingWand);
}
static void ipa_poly_line(wmfAPI * API, wmfPolyLine_t * polyline)
{
if (polyline->count <= 2)
return;
if (TO_DRAW(polyline))
{
int
point;
/* Save graphic wand */
(void) PushDrawingWand(WmfDrawingWand);
util_set_pen(API, polyline->dc);
DrawPathStart(WmfDrawingWand);
DrawPathMoveToAbsolute(WmfDrawingWand,
XC(polyline->pt[0].x),
YC(polyline->pt[0].y));
for (point = 1; point < polyline->count; point++)
{
DrawPathLineToAbsolute(WmfDrawingWand,
XC(polyline->pt[point].x),
YC(polyline->pt[point].y));
}
DrawPathFinish(WmfDrawingWand);
/* Restore graphic wand */
(void) PopDrawingWand(WmfDrawingWand);
}
}
static void ipa_draw_polygon(wmfAPI * API, wmfPolyLine_t * polyline)
{
if (polyline->count <= 2)
return;
if (TO_FILL(polyline) || TO_DRAW(polyline))
{
int
point;
/* Save graphic wand */
(void) PushDrawingWand(WmfDrawingWand);
util_set_pen(API, polyline->dc);
util_set_brush(API, polyline->dc, BrushApplyFill);
DrawPathStart(WmfDrawingWand);
DrawPathMoveToAbsolute(WmfDrawingWand,
XC(polyline->pt[0].x),
YC(polyline->pt[0].y));
for (point = 1; point < polyline->count; point++)
{
DrawPathLineToAbsolute(WmfDrawingWand,
XC(polyline->pt[point].x),
YC(polyline->pt[point].y));
}
DrawPathClose(WmfDrawingWand);
DrawPathFinish(WmfDrawingWand);
/* Restore graphic wand */
(void) PopDrawingWand(WmfDrawingWand);
}
}
/* Draw a polypolygon. A polypolygon is a list of polygons */
#if defined(MAGICKCORE_WMF_DELEGATE)
static void ipa_draw_polypolygon(wmfAPI * API, wmfPolyPoly_t* polypolygon)
{
if (TO_FILL(polypolygon) || TO_DRAW(polypolygon))
{
int
polygon,
point;
wmfPolyLine_t
polyline;
/* Save graphic wand */
(void) PushDrawingWand(WmfDrawingWand);
util_set_pen(API, polypolygon->dc);
util_set_brush(API, polypolygon->dc, BrushApplyFill);
DrawPathStart(WmfDrawingWand);
for (polygon = 0; polygon < polypolygon->npoly; polygon++)
{
polyline.dc = polypolygon->dc;
polyline.pt = polypolygon->pt[polygon];
polyline.count = polypolygon->count[polygon];
if ((polyline.count > 2) && polyline.pt)
{
DrawPathMoveToAbsolute(WmfDrawingWand,
XC(polyline.pt[0].x),
YC(polyline.pt[0].y));
for (point = 1; point < polyline.count; point++)
{
DrawPathLineToAbsolute(WmfDrawingWand,
XC(polyline.pt[point].x),
YC(polyline.pt[point].y));
}
DrawPathClose(WmfDrawingWand);
}
}
DrawPathFinish(WmfDrawingWand);
/* Restore graphic wand */
(void) PopDrawingWand(WmfDrawingWand);
}
}
#endif
static void ipa_draw_rectangle(wmfAPI * API, wmfDrawRectangle_t * draw_rect)
{
/* Save graphic wand */
(void) PushDrawingWand(WmfDrawingWand);
if (TO_FILL(draw_rect) || TO_DRAW(draw_rect))
{
util_set_pen(API, draw_rect->dc);
util_set_brush(API, draw_rect->dc, BrushApplyFill);
if ((draw_rect->width > 0) || (draw_rect->height > 0))
DrawRoundRectangle(WmfDrawingWand,
XC(draw_rect->TL.x), YC(draw_rect->TL.y),
XC(draw_rect->BR.x), YC(draw_rect->BR.y),
draw_rect->width / 2, draw_rect->height / 2);
else
DrawRectangle(WmfDrawingWand,
XC(draw_rect->TL.x), YC(draw_rect->TL.y),
XC(draw_rect->BR.x), YC(draw_rect->BR.y));
}
/* Restore graphic wand */
(void) PopDrawingWand(WmfDrawingWand);
}
/* Draw an un-filled rectangle using the current brush */
static void ipa_region_frame(wmfAPI * API, wmfPolyRectangle_t * poly_rect)
{
/* Save graphic wand */
(void) PushDrawingWand(WmfDrawingWand);
if (TO_FILL(poly_rect) || TO_DRAW(poly_rect))
{
long
i;
draw_fill_color_string(WmfDrawingWand,"none");
util_set_brush(API, poly_rect->dc, BrushApplyStroke);
for (i = 0; i < (long) poly_rect->count; i++)
{
DrawRectangle(WmfDrawingWand,
XC(poly_rect->TL[i].x), YC(poly_rect->TL[i].y),
XC(poly_rect->BR[i].x), YC(poly_rect->BR[i].y));
}
}
/* Restore graphic wand */
(void) PopDrawingWand(WmfDrawingWand);
}
static void ipa_region_paint(wmfAPI * API, wmfPolyRectangle_t * poly_rect)
{
if (poly_rect->count == 0)
return;
/* Save graphic wand */
(void) PushDrawingWand(WmfDrawingWand);
if (TO_FILL (poly_rect))
{
long
i;
draw_stroke_color_string(WmfDrawingWand,"none");
util_set_brush(API, poly_rect->dc, BrushApplyFill);
for (i = 0; i < (long) poly_rect->count; i++)
{
DrawRectangle(WmfDrawingWand,
XC(poly_rect->TL[i].x), YC(poly_rect->TL[i].y),
XC(poly_rect->BR[i].x), YC(poly_rect->BR[i].y));
}
}
/* Restore graphic wand */
(void) PopDrawingWand(WmfDrawingWand);
}
static void ipa_region_clip(wmfAPI *API, wmfPolyRectangle_t *poly_rect)
{
long
i;
wmf_magick_t
*ddata = WMF_MAGICK_GetData (API);
/* Reset any existing clip paths by popping wand */
if (ddata->clipping)
(void) PopDrawingWand(WmfDrawingWand);
ddata->clipping = MagickFalse;
if (poly_rect->count > 0)
{
char
clip_mask_id[MagickPathExtent];
/* Define clip path */
ddata->clip_mask_id++;
DrawPushDefs(WmfDrawingWand);
(void) FormatLocaleString(clip_mask_id,MagickPathExtent,"clip_%lu",
ddata->clip_mask_id);
DrawPushClipPath(WmfDrawingWand,clip_mask_id);
(void) PushDrawingWand(WmfDrawingWand);
for (i = 0; i < (long) poly_rect->count; i++)
{
DrawRectangle(WmfDrawingWand,
XC(poly_rect->TL[i].x), YC(poly_rect->TL[i].y),
XC(poly_rect->BR[i].x), YC(poly_rect->BR[i].y));
}
(void) PopDrawingWand(WmfDrawingWand);
DrawPopClipPath(WmfDrawingWand);
DrawPopDefs(WmfDrawingWand);
/* Push wand for new clip paths */
(void) PushDrawingWand(WmfDrawingWand);
(void) DrawSetClipPath(WmfDrawingWand,clip_mask_id);
ddata->clipping = MagickTrue;
}
}
static void ipa_functions(wmfAPI *API)
{
wmf_magick_t
*ddata = 0;
wmfFunctionReference
*FR = (wmfFunctionReference *) API->function_reference;
/*
IPA function reference links
*/
FR->device_open = ipa_device_open;
FR->device_close = ipa_device_close;
FR->device_begin = ipa_device_begin;
FR->device_end = ipa_device_end;
FR->flood_interior = ipa_flood_interior;
FR->flood_exterior = ipa_flood_exterior;
FR->draw_pixel = ipa_draw_pixel;
FR->draw_pie = ipa_draw_pie;
FR->draw_chord = ipa_draw_chord;
FR->draw_arc = ipa_draw_arc;
FR->draw_ellipse = ipa_draw_ellipse;
FR->draw_line = ipa_draw_line;
FR->poly_line = ipa_poly_line;
FR->draw_polygon = ipa_draw_polygon;
#if defined(MAGICKCORE_WMF_DELEGATE)
FR->draw_polypolygon = ipa_draw_polypolygon;
#endif
FR->draw_rectangle = ipa_draw_rectangle;
FR->rop_draw = ipa_rop_draw;
FR->bmp_draw = ipa_bmp_draw;
FR->bmp_read = ipa_bmp_read;
FR->bmp_free = ipa_bmp_free;
FR->draw_text = ipa_draw_text;
FR->udata_init = ipa_udata_init;
FR->udata_copy = ipa_udata_copy;
FR->udata_set = ipa_udata_set;
FR->udata_free = ipa_udata_free;
FR->region_frame = ipa_region_frame;
FR->region_paint = ipa_region_paint;
FR->region_clip = ipa_region_clip;
/*
Allocate device data structure
*/
ddata = (wmf_magick_t *) wmf_malloc(API, sizeof(wmf_magick_t));
if (ERR(API))
return;
(void) memset((void *) ddata, 0, sizeof(wmf_magick_t));
API->device_data = (void *) ddata;
/*
Device data defaults
*/
ddata->image = 0;
}
static void ipa_draw_text(wmfAPI * API, wmfDrawText_t * draw_text)
{
double
angle = 0, /* text rotation angle */
pointsize = 0; /* pointsize to output font with desired height */
ExceptionInfo
*exception;
TypeMetric
metrics;
#if !defined(MAGICKCORE_WMF_DELEGATE)
double
bbox_height, /* bounding box height */
bbox_width; /* bounding box width */
wmfD_Coord
BL, /* bottom left of bounding box */
BR, /* bottom right of bounding box */
TL, /* top left of bounding box */
TR; /* top right of bounding box */
#endif
wmfD_Coord
point; /* text placement point */
wmfFont
*font;
wmf_magick_t
* ddata = WMF_MAGICK_GetData(API);
point = draw_text->pt;
/* Choose bounding box and calculate its width and height */
#if !defined(MAGICKCORE_WMF_DELEGATE)
{
double dx,
dy;
if ( draw_text->flags)
{
TL = draw_text->TL;
BR = draw_text->BR;
TR.x = draw_text->BR.x;
TR.y = draw_text->TL.y;
BL.x = draw_text->TL.x;
BL.y = draw_text->BR.y;
}
else
{
TL = draw_text->bbox.TL;
BR = draw_text->bbox.BR;
TR = draw_text->bbox.TR;
BL = draw_text->bbox.BL;
}
dx = ((TR.x - TL.x) + (BR.x - BL.x)) / 2;
dy = ((TR.y - TL.y) + (BR.y - BL.y)) / 2;
bbox_width = hypot(dx,dy);
dx = ((BL.x - TL.x) + (BR.x - TR.x)) / 2;
dy = ((BL.y - TL.y) + (BR.y - TR.y)) / 2;
bbox_height = hypot(dx,dy);
}
#endif
font = WMF_DC_FONT(draw_text->dc);
/* Convert font_height to equivalent pointsize */
exception=ddata->exception;
pointsize = util_pointsize( API, font, draw_text->str, draw_text->font_height, exception);
/* Save graphic wand */
(void) PushDrawingWand(WmfDrawingWand);
#if 0
printf("\nipa_draw_text\n");
printf("Text = \"%s\"\n", draw_text->str);
/* printf("WMF_FONT_NAME: = \"%s\"\n", WMF_FONT_NAME(font)); */
printf("WMF_FONT_PSNAME: = \"%s\"\n", WMF_FONT_PSNAME(font));
printf("Bounding box TL=%g,%g BR=%g,%g\n",
TL.x, TL.y, BR.x, BR.y );
/* printf("Text box = %gx%g\n", bbox_width, bbox_height); */
/* printf("WMF_FONT_HEIGHT = %i\n", (int)WMF_FONT_HEIGHT(font)); */
printf("Pointsize = %g\n", pointsize);
fflush(stdout);
#endif
/*
* Obtain font metrics if required
*
*/
if ((WMF_DC_TEXTALIGN(draw_text->dc) & TA_CENTER) ||
(WMF_TEXT_UNDERLINE(font)) || (WMF_TEXT_STRIKEOUT(font)))
{
Image
*image = ddata->image;
DrawInfo
*draw_info;
draw_info=ddata->draw_info;
draw_info->font=WMF_FONT_PSNAME(font);
draw_info->pointsize = pointsize;
draw_info->text=draw_text->str;
if (GetTypeMetrics(image, draw_info, &metrics, exception) != MagickFalse)
{
/* Center the text if it is not yet centered and should be */
if ((WMF_DC_TEXTALIGN(draw_text->dc) & TA_CENTER))
{
double
text_width = metrics.width * (ddata->scale_y / ddata->scale_x);
#if defined(MAGICKCORE_WMF_DELEGATE)
point.x -= text_width / 2;
#else
point.x += bbox_width / 2 - text_width / 2;
#endif
}
}
draw_info->font=NULL;
draw_info->text=NULL;
}
/* Set text background color */
if (draw_text->flags & ETO_OPAQUE)
{
/* Draw bounding-box background color (META_EXTTEXTOUT mode) */
draw_stroke_color_string(WmfDrawingWand,"none");
draw_fill_color_rgb(API,WMF_DC_BACKGROUND(draw_text->dc));
DrawRectangle(WmfDrawingWand,
XC(draw_text->TL.x),YC(draw_text->TL.y),
XC(draw_text->BR.x),YC(draw_text->BR.y));
draw_fill_color_string(WmfDrawingWand,"none");
}
else
{
/* Set text undercolor */
if (WMF_DC_OPAQUE(draw_text->dc))
{
wmfRGB
*box = WMF_DC_BACKGROUND(draw_text->dc);
PixelWand
*under_color;
under_color=NewPixelWand();
PixelSetRedQuantum(under_color,ScaleCharToQuantum(box->r));
PixelSetGreenQuantum(under_color,ScaleCharToQuantum(box->g));
PixelSetBlueQuantum(under_color,ScaleCharToQuantum(box->b));
PixelSetAlphaQuantum(under_color,OpaqueAlpha);
DrawSetTextUnderColor(WmfDrawingWand,under_color);
under_color=DestroyPixelWand(under_color);
}
else
draw_under_color_string(WmfDrawingWand,"none");
}
/* Set text clipping (META_EXTTEXTOUT mode) */
if ( draw_text->flags & ETO_CLIPPED)
{
}
/* Set stroke color */
draw_stroke_color_string(WmfDrawingWand,"none");
/* Set fill color */
draw_fill_color_rgb(API,WMF_DC_TEXTCOLOR(draw_text->dc));
/* Output font size */
(void) DrawSetFontSize(WmfDrawingWand,pointsize);
/* Output Postscript font name */
(void) DrawSetFont(WmfDrawingWand, WMF_FONT_PSNAME(font));
/* Translate coordinates so target is 0,0 */
DrawTranslate(WmfDrawingWand, XC(point.x), YC(point.y));
/* Transform horizontal scale to draw text at 1:1 ratio */
DrawScale(WmfDrawingWand, ddata->scale_y / ddata->scale_x, 1.0);
/* Apply rotation */
/* ImageMagick's drawing rotation is clockwise from horizontal
while WMF drawing rotation is counterclockwise from horizontal */
angle = fabs(RadiansToDegrees(2 * MagickPI - WMF_TEXT_ANGLE(font)));
if (angle == 360)
angle = 0;
if (angle != 0)
DrawRotate(WmfDrawingWand, angle);
/*
* Render text
*
*/
/* Output string */
DrawAnnotation(WmfDrawingWand, 0, 0, (unsigned char*)draw_text->str);
/* Underline text the Windows way (at the bottom) */
if (WMF_TEXT_UNDERLINE(font))
{
double
line_height;
wmfD_Coord
ulBR, /* bottom right of underline rectangle */
ulTL; /* top left of underline rectangle */
line_height = ((double)1/(ddata->scale_x))*metrics.underline_thickness;
if (metrics.underline_thickness < 1.5)
line_height *= 0.55;
ulTL.x = 0;
ulTL.y = fabs(metrics.descent) - line_height;
ulBR.x = metrics.width;
ulBR.y = fabs(metrics.descent);
DrawRectangle(WmfDrawingWand,
XC(ulTL.x), YC(ulTL.y), XC(ulBR.x), YC(ulBR.y));
}
/* Strikeout text the Windows way */
if (WMF_TEXT_STRIKEOUT(font))
{
double line_height;
wmfD_Coord
ulBR, /* bottom right of strikeout rectangle */
ulTL; /* top left of strikeout rectangle */
line_height = ((double)1/(ddata->scale_x))*metrics.underline_thickness;
if (metrics.underline_thickness < 2.0)
line_height *= 0.55;
ulTL.x = 0;
ulTL.y = -(((double) metrics.ascent) / 2 + line_height / 2);
ulBR.x = metrics.width;
ulBR.y = -(((double) metrics.ascent) / 2 - line_height / 2);
DrawRectangle(WmfDrawingWand,
XC(ulTL.x), YC(ulTL.y), XC(ulBR.x), YC(ulBR.y));
}
/* Restore graphic wand */
(void) PopDrawingWand(WmfDrawingWand);
#if 0
(void) PushDrawingWand(WmfDrawingWand);
draw_stroke_color_string(WmfDrawingWand,"red");
draw_fill_color_string(WmfDrawingWand,"none");
DrawRectangle(WmfDrawingWand,
XC(TL.x), YC(TL.y),
XC(BR.x), YC(BR.y));
draw_stroke_color_string(WmfDrawingWand,"none");
(void) PopDrawingWand(WmfDrawingWand);
#endif
}
static void ipa_udata_init(wmfAPI * API, wmfUserData_t * userdata)
{
(void) API;
(void) userdata;
/* wmf_magick_t* ddata = WMF_MAGICK_GetData (API); */
}
static void ipa_udata_copy(wmfAPI * API, wmfUserData_t * userdata)
{
(void) API;
(void) userdata;
/* wmf_magick_t* ddata = WMF_MAGICK_GetData (API); */
}
static void ipa_udata_set(wmfAPI * API, wmfUserData_t * userdata)
{
(void) API;
(void) userdata;
/* wmf_magick_t* ddata = WMF_MAGICK_GetData (API); */
}
static void ipa_udata_free(wmfAPI *API, wmfUserData_t *userdata)
{
(void) API;
(void) userdata;
/* wmf_magick_t* ddata = WMF_MAGICK_GetData (API); */
}
static void util_set_brush(wmfAPI *API, wmfDC *dc,const BrushApply brush_apply)
{
wmf_magick_t
*ddata = WMF_MAGICK_GetData(API);
wmfBrush
*brush = WMF_DC_BRUSH(dc);
/* Set polygon fill rule */
switch (WMF_DC_POLYFILL(dc)) /* Is this correct ?? */
{
case WINDING:
DrawSetClipRule(WmfDrawingWand,NonZeroRule);
break;
case ALTERNATE:
default:
DrawSetClipRule(WmfDrawingWand,EvenOddRule);
break;
}
switch (WMF_BRUSH_STYLE(brush))
{
case BS_SOLID /* 0 */:
/* WMF_BRUSH_COLOR specifies brush color, WMF_BRUSH_HATCH
ignored */
{
if ( brush_apply == BrushApplyStroke )
draw_stroke_color_rgb(API,WMF_BRUSH_COLOR(brush));
else
draw_fill_color_rgb(API,WMF_BRUSH_COLOR(brush));
break;
}
case BS_HOLLOW /* 1 */: /* BS_HOLLOW & BS_NULL share enum */
/* WMF_BRUSH_COLOR and WMF_BRUSH_HATCH ignored */
{
if ( brush_apply == BrushApplyStroke )
draw_stroke_color_string(WmfDrawingWand,"none");
else
draw_fill_color_string(WmfDrawingWand,"none");
break;
}
case BS_HATCHED /* 2 */:
/* WMF_BRUSH_COLOR specifies the hatch color, WMF_BRUSH_HATCH
specifies the hatch brush style. If WMF_DC_OPAQUE, then
WMF_DC_BACKGROUND specifies hatch background color. */
{
DrawPushDefs(WmfDrawingWand);
draw_pattern_push(API, ddata->pattern_id, 8, 8);
(void) PushDrawingWand(WmfDrawingWand);
if (WMF_DC_OPAQUE(dc))
{
if ( brush_apply == BrushApplyStroke )
draw_stroke_color_rgb(API,WMF_DC_BACKGROUND(dc));
else
draw_fill_color_rgb(API,WMF_DC_BACKGROUND(dc));
DrawRectangle(WmfDrawingWand, 0, 0, 7, 7 );
}
DrawSetStrokeAntialias(WmfDrawingWand, MagickFalse);
DrawSetStrokeWidth(WmfDrawingWand, 1);
draw_stroke_color_rgb(API,WMF_BRUSH_COLOR(brush));
switch ((unsigned int) WMF_BRUSH_HATCH(brush))
{
case HS_HORIZONTAL: /* ----- */
{
DrawLine(WmfDrawingWand, 0, 3, 7,3);
break;
}
case HS_VERTICAL: /* ||||| */
{
DrawLine(WmfDrawingWand, 3, 0, 3, 7);
break;
}
case HS_FDIAGONAL: /* \\\\\ */
{
DrawLine(WmfDrawingWand, 0, 0, 7, 7);
break;
}
case HS_BDIAGONAL: /* / */
{
DrawLine(WmfDrawingWand, 0, 7, 7, 0 );
break;
}
case HS_CROSS: /* +++++ */
{
DrawLine(WmfDrawingWand, 0, 3, 7, 3 );
DrawLine(WmfDrawingWand, 3, 0, 3, 7 );
break;
}
case HS_DIAGCROSS: /* xxxxx */
{
DrawLine(WmfDrawingWand, 0, 0, 7, 7 );
DrawLine(WmfDrawingWand, 0, 7, 7, 0 );
break;
}
default:
{
printf("util_set_brush: unexpected brush hatch enumeration %u\n",
(unsigned int)WMF_BRUSH_HATCH(brush));
}
}
(void) PopDrawingWand(WmfDrawingWand);
(void) DrawPopPattern(WmfDrawingWand);
DrawPopDefs(WmfDrawingWand);
{
char
pattern_id[MagickPathExtent];
(void) FormatLocaleString(pattern_id,MagickPathExtent,"#brush_%lu",
ddata->pattern_id);
if (brush_apply == BrushApplyStroke )
(void) DrawSetStrokePatternURL(WmfDrawingWand,pattern_id);
else
(void) DrawSetFillPatternURL(WmfDrawingWand,pattern_id);
++ddata->pattern_id;
}
break;
}
case BS_PATTERN /* 3 */:
/* WMF_BRUSH_COLOR ignored, WMF_BRUSH_HATCH provides handle to
bitmap */
{
printf("util_set_brush: BS_PATTERN not supported\n");
break;
}
case BS_INDEXED /* 4 */:
{
printf("util_set_brush: BS_INDEXED not supported\n");
break;
}
case BS_DIBPATTERN /* 5 */:
{
wmfBMP
*brush_bmp = WMF_BRUSH_BITMAP(brush);
if (brush_bmp && brush_bmp->data != 0)
{
CompositeOperator
mode;
const Image
*image;
MagickWand
*magick_wand;
image = (Image*)brush_bmp->data;
mode = CopyCompositeOp; /* Default is copy */
switch (WMF_DC_ROP(dc))
{
/* Binary raster ops */
case R2_BLACK:
printf("util_set_brush: R2_BLACK ROP2 mode not supported!\n");
break;
case R2_NOTMERGEPEN:
printf("util_set_brush: R2_NOTMERGEPEN ROP2 mode not supported!\n");
break;
case R2_MASKNOTPEN:
printf("util_set_brush R2_MASKNOTPEN ROP2 mode not supported!\n");
break;
case R2_NOTCOPYPEN:
printf("util_set_brush: R2_NOTCOPYPEN ROP2 mode not supported!\n");
break;
case R2_MASKPENNOT:
printf("util_set_brush: R2_MASKPENNOT ROP2 mode not supported!\n");
break;
case R2_NOT:
printf("util_set_brush: R2_NOT ROP2 mode not supported!\n");
break;
case R2_XORPEN:
printf("util_set_brush: R2_XORPEN ROP2 mode not supported!\n");
break;
case R2_NOTMASKPEN:
printf("util_set_brush: R2_NOTMASKPEN ROP2 mode not supported!\n");
break;
case R2_MASKPEN:
printf("util_set_brush: R2_MASKPEN ROP2 mode not supported!\n");
break;
case R2_NOTXORPEN:
printf("util_set_brush: R2_NOTXORPEN ROP2 mode not supported!\n");
break;
case R2_NOP:
printf("util_set_brush: R2_NOP ROP2 mode not supported!\n");
break;
case R2_MERGENOTPEN:
printf("util_set_brush: R2_MERGENOTPEN ROP2 mode not supported!\n");
break;
case R2_COPYPEN:
mode = CopyCompositeOp;
break;
case R2_MERGEPENNOT:
printf("util_set_brush: R2_MERGEPENNOT ROP2 mode not supported!\n");
break;
case R2_MERGEPEN:
printf("util_set_brush: R2_MERGEPEN ROP2 mode not supported!\n");
break;
case R2_WHITE:
printf("util_set_brush: R2_WHITE ROP2 mode not supported!\n");
break;
default:
{
printf("util_set_brush: unexpected ROP2 enumeration %u!\n",
(unsigned int)WMF_DC_ROP(dc));
}
}
DrawPushDefs(WmfDrawingWand);
draw_pattern_push(API, ddata->pattern_id, brush_bmp->width,
brush_bmp->height);
magick_wand=NewMagickWandFromImage(image);
(void) DrawComposite(WmfDrawingWand,mode, 0, 0, brush_bmp->width,
brush_bmp->height, magick_wand);
magick_wand=DestroyMagickWand(magick_wand);
(void) DrawPopPattern(WmfDrawingWand);
DrawPopDefs(WmfDrawingWand);
{
char
pattern_id[MagickPathExtent];
(void) FormatLocaleString(pattern_id,MagickPathExtent,"#brush_%lu",
ddata->pattern_id);
if ( brush_apply == BrushApplyStroke )
(void) DrawSetStrokePatternURL(WmfDrawingWand,pattern_id);
else
(void) DrawSetFillPatternURL(WmfDrawingWand,pattern_id);
++ddata->pattern_id;
}
}
else
printf("util_set_brush: no BMP image data!\n");
break;
}
case BS_DIBPATTERNPT /* 6 */:
/* WMF_BRUSH_COLOR ignored, WMF_BRUSH_HATCH provides pointer to
DIB */
{
printf("util_set_brush: BS_DIBPATTERNPT not supported\n");
break;
}
case BS_PATTERN8X8 /* 7 */:
{
printf("util_set_brush: BS_PATTERN8X8 not supported\n");
break;
}
case BS_DIBPATTERN8X8 /* 8 */:
{
printf("util_set_brush: BS_DIBPATTERN8X8 not supported\n");
break;
}
default:
{
}
}
}
static void util_set_pen(wmfAPI * API, wmfDC * dc)
{
wmf_magick_t
*ddata = WMF_MAGICK_GetData(API);
wmfPen
*pen = 0;
double
pen_width,
pixel_width;
unsigned int
pen_style;
pen = WMF_DC_PEN(dc);
pen_width = (WMF_PEN_WIDTH(pen) + WMF_PEN_HEIGHT(pen)) / 2;
/* Pixel width is inverse of pixel scale */
pixel_width = (((double) 1 / (ddata->scale_x)) +
((double) 1 / (ddata->scale_y))) / 2;
/* Don't allow pen_width to be much less than pixel_width in order
to avoid dissapearing or spider-web lines */
pen_width = MagickMax(pen_width, pixel_width*0.8);
pen_style = (unsigned int) WMF_PEN_STYLE(pen);
/* Pen style specified? */
if (pen_style == PS_NULL)
{
draw_stroke_color_string(WmfDrawingWand,"none");
return;
}
DrawSetStrokeAntialias(WmfDrawingWand, MagickTrue );
DrawSetStrokeWidth(WmfDrawingWand, (unsigned long) MagickMax(0.0, pen_width));
{
LineCap
linecap;
switch ((unsigned int) WMF_PEN_ENDCAP(pen))
{
case PS_ENDCAP_SQUARE:
linecap = SquareCap;
break;
case PS_ENDCAP_ROUND:
linecap = RoundCap;
break;
case PS_ENDCAP_FLAT:
default:
linecap = ButtCap;
break;
}
DrawSetStrokeLineCap(WmfDrawingWand, linecap);
}
{
LineJoin
linejoin;
switch ((unsigned int) WMF_PEN_JOIN(pen))
{
case PS_JOIN_BEVEL:
linejoin = BevelJoin;
break;
case PS_JOIN_ROUND:
linejoin = RoundJoin;
break;
case PS_JOIN_MITER:
default:
linejoin = MiterJoin;
break;
}
DrawSetStrokeLineJoin(WmfDrawingWand,linejoin);
}
{
double
dasharray[7];
switch (pen_style)
{
case PS_DASH: /* ------- */
{
/* Pattern 18,7 */
dasharray[0] = pixel_width * 18;
dasharray[1] = pixel_width * 7;
dasharray[2] = 0;
DrawSetStrokeAntialias(WmfDrawingWand,MagickFalse);
(void) DrawSetStrokeDashArray(WmfDrawingWand,2,dasharray);
break;
}
case PS_ALTERNATE:
case PS_DOT: /* ....... */
{
/* Pattern 3,3 */
dasharray[0] = pixel_width * 3;
dasharray[1] = pixel_width * 3;
dasharray[2] = 0;
DrawSetStrokeAntialias(WmfDrawingWand,MagickFalse);
(void) DrawSetStrokeDashArray(WmfDrawingWand,2,dasharray);
break;
}
case PS_DASHDOT: /* _._._._ */
{
/* Pattern 9,6,3,6 */
dasharray[0] = pixel_width * 9;
dasharray[1] = pixel_width * 6;
dasharray[2] = pixel_width * 3;
dasharray[3] = pixel_width * 6;
dasharray[4] = 0;
DrawSetStrokeAntialias(WmfDrawingWand,MagickFalse);
(void) DrawSetStrokeDashArray(WmfDrawingWand,4,dasharray);
break;
}
case PS_DASHDOTDOT: /* _.._.._ */
{
/* Pattern 9,3,3,3,3,3 */
dasharray[0] = pixel_width * 9;
dasharray[1] = pixel_width * 3;
dasharray[2] = pixel_width * 3;
dasharray[3] = pixel_width * 3;
dasharray[4] = pixel_width * 3;
dasharray[5] = pixel_width * 3;
dasharray[6] = 0;
DrawSetStrokeAntialias(WmfDrawingWand,MagickFalse);
(void) DrawSetStrokeDashArray(WmfDrawingWand,6,dasharray);
break;
}
case PS_INSIDEFRAME: /* There is nothing to do in this case... */
case PS_SOLID:
default:
{
(void) DrawSetStrokeDashArray(WmfDrawingWand,0,(double *) NULL);
break;
}
}
}
draw_stroke_color_rgb(API,WMF_PEN_COLOR(pen));
}
/* Estimate font pointsize based on Windows font parameters */
static double util_pointsize( wmfAPI* API, wmfFont* font, char* str, double font_height, ExceptionInfo *exception)
{
wmf_magick_t
*ddata = WMF_MAGICK_GetData(API);
Image
*image = ddata->image;
TypeMetric
metrics;
DrawInfo
*draw_info;
double
pointsize = 0;
draw_info=ddata->draw_info;
if (draw_info == (const DrawInfo *) NULL)
return 0;
draw_info->font=WMF_FONT_PSNAME(font);
draw_info->pointsize=font_height;
draw_info->text=str;
if (GetTypeMetrics(image, draw_info, &metrics, exception) != MagickFalse)
{
if (strlen(str) == 1)
{
pointsize = (font_height *
( font_height * PerceptibleReciprocal(metrics.ascent + fabs(metrics.descent))));
draw_info->pointsize = pointsize;
if (GetTypeMetrics(image, draw_info, &metrics, exception) != MagickFalse)
pointsize *= (font_height * PerceptibleReciprocal( metrics.ascent + fabs(metrics.descent)));
}
else
{
pointsize = (font_height * (font_height * PerceptibleReciprocal(metrics.height)));
draw_info->pointsize = pointsize;
if (GetTypeMetrics(image, draw_info, &metrics, exception) != MagickFalse)
pointsize *= (font_height * PerceptibleReciprocal((double) metrics.height));
}
#if 0
draw_info.pointsize = pointsize;
if (GetTypeMetrics(image, &draw_info, &metrics, exception) != MagickFalse)
pointsize *= (font_height / (metrics.ascent + fabs(metrics.descent)));
pointsize *= 1.114286; /* Magic number computed through trial and error */
#endif
}
draw_info->font=NULL;
draw_info->text=NULL;
#if 0
printf("String = %s\n", str);
printf("Font = %s\n", WMF_FONT_PSNAME(font));
printf("lfHeight = %g\n", font_height);
printf("bounds = %g,%g %g,%g\n", metrics.bounds.x1, metrics.bounds.y1,
metrics.bounds.x2,metrics.bounds.y2);
printf("ascent = %g\n", metrics.ascent);
printf("descent = %g\n", metrics.descent);
printf("height = %g\n", metrics.height);
printf("Pointsize = %g\n", pointsize);
#endif
return floor(pointsize);
}
#if defined(MAGICKCORE_WMF_DELEGATE)
/*
* Returns width of string in points, assuming (unstretched) font size of 1pt
* (similar to wmf_ipa_font_stringwidth)
*
* This extremely odd at best, particularly since player/meta.h has access
* to the corrected font_height (as drawtext.font_height) when it invokes the
* stringwidth callback. It should be possible to compute the real stringwidth!
*/
static float lite_font_stringwidth( wmfAPI* API, wmfFont* font, char* str)
{
#if 0
wmf_magick_t
*ddata = WMF_MAGICK_GetData(API);
Image
*image = ddata->image;
DrawInfo
*draw_info;
ExceptionInfo
*exception;
TypeMetric
metrics;
float
stringwidth = 0;
double
orig_x_resolution,
orig_y_resolution;
ResolutionType
orig_resolution_units;
orig_x_resolution = image->resolution.x;
orig_y_resolution = image->resolution.y;
orig_resolution_units = image->units;
draw_info=ddata->draw_info;
if (draw_info == (const DrawInfo *) NULL)
return 0;
draw_info->font=WMF_FONT_PSNAME(font);
draw_info->pointsize=12;
draw_info->text=str;
image->resolution.x = 72;
image->resolution.y = 72;
image->units = PixelsPerInchResolution;
exception=ddata->exception;
if (GetTypeMetrics(image, draw_info, &metrics, exception) != MagickFalse)
stringwidth = ((metrics.width * 72)/(image->resolution.x * draw_info->pointsize)); /* *0.916348; */
draw_info->font=NULL;
draw_info->text=NULL;
#if 0
printf("\nlite_font_stringwidth\n");
printf("string = \"%s\"\n", str);
printf("WMF_FONT_NAME = \"%s\"\n", WMF_FONT_NAME(font));
printf("WMF_FONT_PSNAME = \"%s\"\n", WMF_FONT_PSNAME(font));
printf("stringwidth = %g\n", stringwidth);
/* printf("WMF_FONT_HEIGHT = %i\n", (int)WMF_FONT_HEIGHT(font)); */
/* printf("WMF_FONT_WIDTH = %i\n", (int)WMF_FONT_WIDTH(font)); */
fflush(stdout);
#endif
image->resolution.x = orig_x_resolution;
image->resolution.y = orig_y_resolution;
image->units = orig_resolution_units;
return stringwidth;
#else
(void) API;
(void) font;
(void) str;
return 0;
#endif
}
/* Map font (similar to wmf_ipa_font_map) */
/* Mappings to Postscript fonts: family, normal, italic, bold, bolditalic */
static wmfFontMap WMFFontMap[] = {
{ (char *) "Courier", (char *) "Courier",
(char *) "Courier-Oblique", (char *) "Courier-Bold",
(char *) "Courier-BoldOblique" },
{ (char *) "Helvetica", (char *) "Helvetica",
(char *) "Helvetica-Oblique", (char *) "Helvetica-Bold",
(char *) "Helvetica-BoldOblique" },
{ (char *) "Modern", (char *) "Courier",
(char *) "Courier-Oblique", (char *) "Courier-Bold",
(char *) "Courier-BoldOblique" },
{ (char *) "Monotype Corsiva", (char *) "Courier",
(char *) "Courier-Oblique", (char *) "Courier-Bold",
(char *) "Courier-BoldOblique" },
{ (char *) "News Gothic", (char *) "Helvetica",
(char *) "Helvetica-Oblique", (char *) "Helvetica-Bold",
(char *) "Helvetica-BoldOblique" },
{ (char *) "Symbol", (char *) "Symbol",
(char *) "Symbol", (char *) "Symbol",
(char *) "Symbol" },
{ (char *) "System", (char *) "Courier",
(char *) "Courier-Oblique", (char *) "Courier-Bold",
(char *) "Courier-BoldOblique" },
{ (char *) "Times", (char *) "Times-Roman",
(char *) "Times-Italic", (char *) "Times-Bold",
(char *) "Times-BoldItalic" },
{ (char *) NULL, (char *) NULL,
(char *) NULL, (char *) NULL,
(char *) NULL }
};
/* Mapping between base name and Ghostscript family name */
static wmfMapping SubFontMap[] =
{
{ (char *) "Arial", (char *) "Helvetica", FT_ENCODING_NONE },
{ (char *) "Courier", (char *) "Courier", FT_ENCODING_NONE },
{ (char *) "Fixed", (char *) "Courier", FT_ENCODING_NONE },
{ (char *) "Helvetica", (char *) "Helvetica", FT_ENCODING_NONE },
{ (char *) "Sans", (char *) "Helvetica", FT_ENCODING_NONE },
{ (char *) "Sym", (char *) "Symbol", FT_ENCODING_NONE },
{ (char *) "Terminal", (char *) "Courier", FT_ENCODING_NONE },
{ (char *) "Times", (char *) "Times", FT_ENCODING_NONE },
{ (char *) "Wingdings", (char *) "Symbol", FT_ENCODING_NONE },
{ (char *) NULL, (char *) NULL, FT_ENCODING_NONE }
};
static void lite_font_map( wmfAPI* API, wmfFont* font)
{
wmfFontData
*font_data;
wmf_magick_font_t
*magick_font;
wmf_magick_t
*ddata = WMF_MAGICK_GetData(API);
ExceptionInfo
*exception;
const TypeInfo
*type_info,
*type_info_base;
const char
*wmf_font_name;
if (font == 0)
return;
font_data = (wmfFontData*)API->font_data;
font->user_data = font_data->user_data;
magick_font = (wmf_magick_font_t*)font->user_data;
wmf_font_name = WMF_FONT_NAME(font);
if (magick_font->ps_name != (char *) NULL)
magick_font->ps_name=DestroyString(magick_font->ps_name);
exception=ddata->exception;
type_info_base=GetTypeInfo("*",exception);
if (type_info_base == 0)
return;
/* Certain short-hand font names are not the proper Windows names
and should be promoted to the proper names */
if (LocaleCompare(wmf_font_name,"Times") == 0)
wmf_font_name = "Times New Roman";
else if (LocaleCompare(wmf_font_name,"Courier") == 0)
wmf_font_name = "Courier New";
/* Look for a family-based best-match */
if (!magick_font->ps_name)
{
int
target_weight;
StyleType
style = AnyStyle;
if (WMF_FONT_WEIGHT(font) == 0)
target_weight = 400;
else
target_weight = WMF_FONT_WEIGHT(font);
if (WMF_FONT_ITALIC(font))
style=ItalicStyle;
type_info=GetTypeInfoByFamily(wmf_font_name,style,AnyStretch,
target_weight,exception);
if (type_info == (const TypeInfo *) NULL)
type_info=GetTypeInfoByFamily(wmf_font_name,AnyStyle,AnyStretch,0,
exception);
if (type_info != (const TypeInfo *) NULL)
CloneString(&magick_font->ps_name,type_info->name);
}
/* Look for exact full match */
if(!magick_font->ps_name)
{
type_info=GetTypeInfo(wmf_font_name,exception);
if (type_info != (const TypeInfo *) NULL)
CloneString(&magick_font->ps_name,type_info->name);
}
/* Now let's try simple substitution mappings from WMFFontMap */
if (!magick_font->ps_name)
{
char
target[MagickPathExtent];
int
target_weight = 400,
want_italic = MagickFalse,
want_bold = MagickFalse,
i;
if ( WMF_FONT_WEIGHT(font) != 0 )
target_weight = WMF_FONT_WEIGHT(font);
if ( (target_weight > 550) || ((strstr(wmf_font_name,"Bold") ||
strstr(wmf_font_name,"Heavy") ||
strstr(wmf_font_name,"Black"))) )
want_bold = MagickTrue;
if ( (WMF_FONT_ITALIC(font)) || ((strstr(wmf_font_name,"Italic") ||
strstr(wmf_font_name,"Oblique"))) )
want_italic = MagickTrue;
(void) CopyMagickString(target,"Times",MagickPathExtent);
for( i=0; SubFontMap[i].name != NULL; i++ )
{
if (LocaleCompare(wmf_font_name, SubFontMap[i].name) == 0)
{
(void) CopyMagickString(target,SubFontMap[i].mapping,
MagickPathExtent);
break;
}
}
for( i=0; WMFFontMap[i].name != NULL; i++ )
{
if (LocaleNCompare(WMFFontMap[i].name,target,strlen(WMFFontMap[i].name)) == 0)
{
if (want_bold && want_italic)
CloneString(&magick_font->ps_name,WMFFontMap[i].bolditalic);
else if (want_italic)
CloneString(&magick_font->ps_name,WMFFontMap[i].italic);
else if (want_bold)
CloneString(&magick_font->ps_name,WMFFontMap[i].bold);
else
CloneString(&magick_font->ps_name,WMFFontMap[i].normal);
}
}
}
#if 0
printf("\nlite_font_map\n");
printf("WMF_FONT_NAME = \"%s\"\n", WMF_FONT_NAME(font));
printf("WMF_FONT_WEIGHT = %i\n", WMF_FONT_WEIGHT(font));
printf("WMF_FONT_PSNAME = \"%s\"\n", WMF_FONT_PSNAME(font));
fflush(stdout);
#endif
}
/* Initialize API font structures */
static void lite_font_init( wmfAPI* API, wmfAPI_Options* options)
{
wmfFontData
*font_data;
(void) options;
API->fonts = 0;
/* Allocate wmfFontData data structure */
API->font_data = wmf_malloc(API,sizeof(wmfFontData));
if (ERR (API))
return;
font_data = (wmfFontData*)API->font_data;
/* Assign function to map font (type wmfMap) */
font_data->map = lite_font_map;
/* Assign function to return string width in points (type wmfStringWidth) */
font_data->stringwidth = lite_font_stringwidth;
/* Assign user data, not used by libwmflite (type void*) */
font_data->user_data = wmf_malloc(API,sizeof(wmf_magick_font_t));
if (ERR(API))
return;
((wmf_magick_font_t*)font_data->user_data)->ps_name = 0;
((wmf_magick_font_t*)font_data->user_data)->pointsize = 0;
}
#endif /* MAGICKCORE_WMF_DELEGATE */
/* BLOB read byte */
static int ipa_blob_read(void* wand)
{
return ReadBlobByte((Image*)wand);
}
/* BLOB seek */
static int ipa_blob_seek(void* wand,long position)
{
return (int)SeekBlob((Image*)wand,(MagickOffsetType) position,SEEK_SET);
}
/* BLOB tell */
static long ipa_blob_tell(void* wand)
{
return (long)TellBlob((Image*)wand);
}
static Image *ReadWMFImage(const ImageInfo *image_info,ExceptionInfo *exception)
{
double
bounding_height,
bounding_width,
image_height,
image_height_inch,
image_width,
image_width_inch,
resolution_y,
resolution_x,
units_per_inch;
float
wmf_width,
wmf_height;
Image
*image;
MagickBooleanType
status;
unsigned long
wmf_options_flags = 0;
wmf_error_t
wmf_error;
wmf_magick_t
*ddata = 0;
wmfAPI
*API = 0;
wmfAPI_Options
wmf_api_options;
wmfD_Rect
bbox;
image=AcquireImage(image_info,exception);
if (OpenBlob(image_info,image,ReadBinaryBlobMode,exception) == MagickFalse)
{
if (image->debug != MagickFalse)
{
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" OpenBlob failed");
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
"leave ReadWMFImage()");
}
image=DestroyImageList(image);
return((Image *) NULL);
}
/*
* Create WMF API
*
*/
/* Register callbacks */
wmf_options_flags |= WMF_OPT_FUNCTION;
(void) memset(&wmf_api_options, 0, sizeof(wmf_api_options));
wmf_api_options.function = ipa_functions;
/* Ignore non-fatal errors */
wmf_options_flags |= WMF_OPT_IGNORE_NONFATAL;
wmf_error = wmf_api_create(&API, wmf_options_flags, &wmf_api_options);
if (wmf_error != wmf_E_None)
{
if (image->debug != MagickFalse)
{
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" wmf_api_create failed");
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
"leave ReadWMFImage()");
}
if (API)
wmf_api_destroy(API);
ThrowReaderException(DelegateError,"UnableToInitializeWMFLibrary");
}
/* Register progress monitor */
wmf_status_function(API,image,magick_progress_callback);
ddata=WMF_MAGICK_GetData(API);
ddata->image=image;
ddata->image_info=image_info;
ddata->draw_info=CloneDrawInfo(image_info,(const DrawInfo *) NULL);
ddata->exception=exception;
ddata->draw_info->font=(char *)
RelinquishMagickMemory(ddata->draw_info->font);
ddata->draw_info->text=(char *)
RelinquishMagickMemory(ddata->draw_info->text);
#if defined(MAGICKCORE_WMF_DELEGATE)
/* Must initialize font subystem for WMFlite interface */
lite_font_init (API,&wmf_api_options); /* similar to wmf_ipa_font_init in src/font.c */
/* wmf_arg_fontdirs (API,options); */ /* similar to wmf_arg_fontdirs in src/wmf.c */
#endif
/*
* Open BLOB input via libwmf API
*
*/
wmf_error = wmf_bbuf_input(API,ipa_blob_read,ipa_blob_seek,
ipa_blob_tell,(void*)image);
if (wmf_error != wmf_E_None)
{
if (image->debug != MagickFalse)
{
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" wmf_bbuf_input failed");
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
"leave ReadWMFImage()");
}
wmf_api_destroy(API);
ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
image->filename);
image=DestroyImageList(image);
return((Image *) NULL);
}
/*
* Scan WMF file
*
*/
if (image->debug != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" Scanning WMF to obtain bounding box");
wmf_error=wmf_scan(API, 0, &bbox);
if (wmf_error != wmf_E_None)
{
if (image->debug != MagickFalse)
{
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" wmf_scan failed with wmf_error %d", wmf_error);
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
"leave ReadWMFImage()");
}
ipa_device_close(API);
wmf_api_destroy(API);
ThrowReaderException(DelegateError,"FailedToScanFile");
}
/*
* Compute dimensions and scale factors
*
*/
ddata->bbox=bbox;
/* User specified resolution */
resolution_y=DefaultResolution;
if (image->resolution.y != 0.0)
{
resolution_y = image->resolution.y;
if (image->units == PixelsPerCentimeterResolution)
resolution_y *= CENTIMETERS_PER_INCH;
}
resolution_x=DefaultResolution;
if (image->resolution.x != 0.0)
{
resolution_x = image->resolution.x;
if (image->units == PixelsPerCentimeterResolution)
resolution_x *= CENTIMETERS_PER_INCH;
}
/* Obtain output size expressed in metafile units */
wmf_error=wmf_size(API,&wmf_width,&wmf_height);
if (wmf_error != wmf_E_None)
{
if (image->debug != MagickFalse)
{
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" wmf_size failed with wmf_error %d", wmf_error);
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
"leave ReadWMFImage()");
}
ipa_device_close(API);
wmf_api_destroy(API);
ThrowReaderException(DelegateError,"FailedToComputeOutputSize");
}
/* Obtain (or guess) metafile units */
if ((API)->File->placeable && (API)->File->pmh->Inch)
units_per_inch=(API)->File->pmh->Inch;
else if ( (wmf_width*wmf_height) < 1024*1024)
units_per_inch=POINTS_PER_INCH; /* MM_TEXT */
else
units_per_inch=TWIPS_PER_INCH; /* MM_TWIPS */
/* Calculate image width and height based on specified DPI
resolution */
image_width_inch = (double) wmf_width / units_per_inch;
image_height_inch = (double) wmf_height / units_per_inch;
image_width = image_width_inch * resolution_x;
image_height = image_height_inch * resolution_y;
/* Compute bounding box scale factors and origin translations
*
* This all just a hack since libwmf does not currently seem to
* provide the mapping between LOGICAL coordinates and DEVICE
* coordinates. This mapping is necessary in order to know
* where to place the logical bounding box within the image.
*
*/
bounding_width = bbox.BR.x - bbox.TL.x;
bounding_height = bbox.BR.y - bbox.TL.y;
if ((bounding_width == 0) || (bounding_height == 0))
{
ipa_device_close(API);
(void) wmf_api_destroy(API);
ThrowReaderException(CorruptImageError,"ImproperImageHeader");
}
ddata->scale_x = image_width/bounding_width;
ddata->translate_x = 0-bbox.TL.x;
ddata->rotate = 0;
/* Heuristic: guess that if the vertical coordinates mostly span
negative values, then the image must be inverted. */
if ( fabs(bbox.BR.y) > fabs(bbox.TL.y) )
{
/* Normal (Origin at top left of image) */
ddata->scale_y = (image_height/bounding_height);
ddata->translate_y = 0-bbox.TL.y;
}
else
{
/* Inverted (Origin at bottom left of image) */
ddata->scale_y = (-image_height/bounding_height);
ddata->translate_y = 0-bbox.BR.y;
}
if (image->debug != MagickFalse)
{
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" Placeable metafile: %s",
(API)->File->placeable ? "Yes" : "No");
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" Size in metafile units: %gx%g",wmf_width,wmf_height);
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" Metafile units/inch: %g",units_per_inch);
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" Size in inches: %gx%g",
image_width_inch,image_height_inch);
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" Bounding Box: %g,%g %g,%g",
bbox.TL.x, bbox.TL.y, bbox.BR.x, bbox.BR.y);
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" Bounding width x height: %gx%g",bounding_width,
bounding_height);
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" Output resolution: %gx%g",resolution_x,resolution_y);
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" Image size: %gx%g",image_width,image_height);
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" Bounding box scale factor: %g,%g",ddata->scale_x,
ddata->scale_y);
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" Translation: %g,%g",
ddata->translate_x, ddata->translate_y);
}
#if 0
#if 0
{
typedef struct _wmfPlayer_t wmfPlayer_t;
struct _wmfPlayer_t
{
wmfPen default_pen;
wmfBrush default_brush;
wmfFont default_font;
wmfDC* dc; /* current dc */
};
wmfDC
*dc;
#define WMF_ELICIT_DC(API) (((wmfPlayer_t*)((API)->player_data))->dc)
dc = WMF_ELICIT_DC(API);
printf("dc->Window.Ox = %d\n", dc->Window.Ox);
printf("dc->Window.Oy = %d\n", dc->Window.Oy);
printf("dc->Window.width = %d\n", dc->Window.width);
printf("dc->Window.height = %d\n", dc->Window.height);
printf("dc->pixel_width = %g\n", dc->pixel_width);
printf("dc->pixel_height = %g\n", dc->pixel_height);
#if defined(MAGICKCORE_WMF_DELEGATE) /* Only in libwmf 0.3 */
printf("dc->Ox = %.d\n", dc->Ox);
printf("dc->Oy = %.d\n", dc->Oy);
printf("dc->width = %.d\n", dc->width);
printf("dc->height = %.d\n", dc->height);
#endif
}
#endif
#endif
/*
* Create canvas image
*
*/
image->rows=(unsigned long) ceil(image_height);
image->columns=(unsigned long) ceil(image_width);
if (image_info->ping != MagickFalse)
{
ipa_device_close(API);
wmf_api_destroy(API);
(void) CloseBlob(image);
if (image->debug != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
"leave ReadWMFImage()");
return(GetFirstImageInList(image));
}
status=SetImageExtent(image,image->columns,image->rows,exception);
if (status == MagickFalse)
return(DestroyImageList(image));
if (image->debug != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" Creating canvas image with size %lux%lu",(unsigned long) image->rows,
(unsigned long) image->columns);
/*
* Set solid background color
*/
{
image->background_color = image_info->background_color;
if (image->background_color.alpha != OpaqueAlpha)
image->alpha_trait=BlendPixelTrait;
(void) SetImageBackgroundColor(image,exception);
}
/*
* Play file to generate Vector drawing commands
*
*/
if (image->debug != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" Playing WMF to prepare vectors");
wmf_error = wmf_play(API, 0, &bbox);
if (wmf_error != wmf_E_None)
{
if (image->debug != MagickFalse)
{
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" Playing WMF failed with wmf_error %d", wmf_error);
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
"leave ReadWMFImage()");
}
ipa_device_close(API);
wmf_api_destroy(API);
ThrowReaderException(DelegateError,"FailedToRenderFile");
}
/*
* Scribble on canvas image
*
*/
if (image->debug != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" Rendering WMF vectors");
DrawRender(ddata->draw_wand);
if (image->debug != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),"leave ReadWMFImage()");
/* Cleanup allocated data */
wmf_api_destroy(API);
(void) CloseBlob(image);
/* Return image */
return image;
}
#endif
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% R e g i s t e r W M F I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% RegisterWMFImage() adds attributes for the WMF image format to
% the list of supported formats. The attributes include the image format
% tag, a method to read and/or write the format, whether the format
% supports the saving of more than one frame to the same file or blob,
% whether the format supports native in-memory I/O, and a brief
% description of the format.
%
% The format of the RegisterWMFImage method is:
%
% size_t RegisterWMFImage(void)
%
*/
ModuleExport size_t RegisterWMFImage(void)
{
MagickInfo
*entry;
entry=AcquireMagickInfo("WMF","WMZ","Compressed Windows Meta File");
#if defined(MAGICKCORE_SANS_DELEGATE) || defined(MAGICKCORE_WMF_DELEGATE)
entry->decoder=ReadWMFImage;
#endif
entry->flags|=CoderDecoderSeekableStreamFlag;
(void) RegisterMagickInfo(entry);
entry=AcquireMagickInfo("WMF","WMF","Windows Meta File");
#if defined(MAGICKCORE_SANS_DELEGATE) || defined(MAGICKCORE_WMF_DELEGATE)
entry->decoder=ReadWMFImage;
#endif
(void) RegisterMagickInfo(entry);
return(MagickImageCoderSignature);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% U n r e g i s t e r W M F I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% UnregisterWMFImage() removes format registrations made by the
% WMF module from the list of supported formats.
%
% The format of the UnregisterWMFImage method is:
%
% UnregisterWMFImage(void)
%
*/
ModuleExport void UnregisterWMFImage(void)
{
(void) UnregisterMagickInfo("WMZ");
(void) UnregisterMagickInfo("WMF");
}