diff options
Diffstat (limited to 'src/libuemf/upmf.c')
| -rw-r--r-- | src/libuemf/upmf.c | 8660 |
1 files changed, 0 insertions, 8660 deletions
diff --git a/src/libuemf/upmf.c b/src/libuemf/upmf.c deleted file mode 100644 index 5cb558ac6..000000000 --- a/src/libuemf/upmf.c +++ /dev/null @@ -1,8660 +0,0 @@ -/** - @file upmf.c - - @brief Functions for manipulating EMF+ files and structures. - - EMF+ is much more object based than is EMF or WMF, so the U_PMR_*_set and most U_PMF_*_set functions - return a pointer to a PseudoObject. PseudoObjects are structs that contain a data field to hold the - object in EMF+ file byte order, size information, and some type information. This is sufficient to allow - complex records to be built up from the various sorts of nested objects which they normally contain. - If something goes wrong a NULL pointer is returned and recsize is set to 0. - - EMF+ does not use a separate set of endian functions, _get and _set routines convert from/to - the EMF+ file byte order on the fly. - - WARNING: Microsoft's EMF+ documentation is little-endian for everything EXCEPT - bitfields, which are big-endian. See EMF+ manual section 1.3.2 - That documentation also uses 0 as the MOST significant bit, N-1 as the least. - This code is little-endian throughout, and 0 is the LEAST significant bit - -*/ - -/* -File: upmf.c -Version: 0.0.12 -Date: 26-JAN-2016 -Author: David Mathog, Biology Division, Caltech -email: mathog@caltech.edu -Copyright: 2016 David Mathog and California Institute of Technology (Caltech) -*/ - -#ifdef __cplusplus -extern "C" { -#endif - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <iconv.h> -#include <wchar.h> -#include <errno.h> -#include <string.h> -#include <limits.h> // for INT_MAX, INT_MIN -#include <math.h> // for sin, cos, tan2, use U_ROUND() instead of roundf() -#include <stddef.h> /* for offsetof() macro */ -#if 0 -#include <windef.h> //Not actually used, looking for collisions -#include <winnt.h> //Not actually used, looking for collisions -#include <wingdi.h> //Not actually used, looking for collisions -#endif -#include "upmf.h" // includes uemf.h -#include "uemf_endian.h" // for U_swap* functions - -//! \cond - -/// things Doxygen should not process -/* remove this after debugging is completed */ -void dumphex(uint8_t *buf,unsigned int num){ - for(; num; num--,buf++){ - printf("%2.2X",*buf); - } -} - - -/* Prototypes for functions used here and defined in uemf_endian.c, but which are not supposed -to be used in end user code. */ - -void U_swap2(void *ul, unsigned int count); -void U_swap4(void *ul, unsigned int count); -//! \endcond - -/** - \brief Utility function for writing one or more EMF+ records in a PseudoObject to the EMF output file - \return 1 on success, 0 on error. - \param po U_PSEUDO_OBJ to write, it is deleted after it is written - \param sum U_PSEUDO_OBJ to use for scratch space - \param et EMFTRACK used to write records to EMF file -*/ -int U_PMR_write(U_PSEUDO_OBJ *po, U_PSEUDO_OBJ *sum, EMFTRACK *et){ - char *rec; - int status = 0; - sum->Used = 0; /* clean it out, retaining allocated memory */ - sum = U_PO_append(sum, "EMF+", 4); /* indicates that this comment holds an EMF+ record */ - if(!sum)goto end; - sum = U_PO_append(sum, po->Data, po->Used); /* the EMF+ record itself */ - if(!sum)goto end; - U_PO_free(&po); /* delete the PseudoObject */ - rec = U_EMRCOMMENT_set(sum->Used, sum->Data); /* stuff it into the EMF comment */ - if(!emf_append((PU_ENHMETARECORD)rec, et, 1))goto end; /* write it to the EMF file, delete the record, check status */ - status = 1; -end: - return(status); -} - -/** - \brief Utility function to draw a line. - \return 1 on success, 0 on error. - \param PenID Index of U_PMF_PEN object to use in the EMF+ object table (0-63, inclusive) - \param PathID Index of U_PMF_PATH object to use in the EMF+ object table (0-63, inclusive) - \param Start U_PMF_POINTF coordinates of start of line. - \param End U_PMF_POINTF coordinates of end of line. - \param Dashed Set if the line is dashed, clear if it is not. - \param sum PseudoObject used for scratch space - \param et EMFTRACK used to write records to EMF file - -*/ -int U_PMR_drawline(uint32_t PenID, uint32_t PathID, U_PMF_POINTF Start, U_PMF_POINTF End, int Dashed, U_PSEUDO_OBJ *sum, EMFTRACK *et){ - U_DPSEUDO_OBJ *dpath; - U_PSEUDO_OBJ *poPath; - U_PSEUDO_OBJ *po; - int status=0; - int PTP_value = ( Dashed ? U_PTP_DashMode : U_PTP_None); - dpath = U_PATH_create(0, NULL, 0, 0); /* create an empty path*/ - if(dpath){ - if(U_PATH_moveto(dpath, Start, PTP_value) && U_PATH_lineto(dpath, End, PTP_value)){ - poPath = U_PMF_PATH_set2(U_PMF_GRAPHICSVERSIONOBJ_set(2), dpath); - if(poPath){ - po = U_PMR_OBJECT_PO_set(PathID, poPath); - U_PO_free(&poPath); - if(po){ - U_PMR_write(po, sum, et); - po = U_PMR_DRAWPATH_set(PathID, PenID); - if(po){ - U_PMR_write(po, sum, et); - status = 1; - } - } - } - } - U_DPO_free(&dpath); - } - return(status); -} - -/** - \brief Utility function for drawing strings onto the baseline in one call. - \return 1 on success, 0 on error. - \param string Text to draw in UTF-8 format - \param Vpos StringAlignment Enumeration. Always drawn on baseline, but using one of these three modes. - \param FontID Index of U_PMF_FONT object to use in the EMF+ object table (0-63, inclusive) - \param BrushID U_PSEUDO_OBJ containing a U_PMF_ARGB or a U_PMF_4NUM. Color or U_PMF_BRUSH object in the EMF+ object table (0-63, inclusive) - \param FormatID index of U_PMF_STRINGFORMAT object to use in the EMF+ Object Table. - \param Sfs StringFormat structure. Ignored values: StringAlignment, LineAlign, Flags - \param FontName Name of font to draw with - \param Height Height of font in pixels (positive) - \param fip U_FontInfoParams (ascent, descent, and so forth) - \param FontFlags FontStyle Flags - \param x X position in pixels of left side of EM box of first character - \param y Y position in pixels of baseline of first character - \param sum PseudoObject used for scratch space - \param et EMFTRACK used to write records to EMF file - - EMF+ manual 2.3.4.14, Microsoft name: EmfPlusDrawString Record, Index 0x1C - - For most fonts Ascent and Descent are used to adjust the bounding box to properly position the - baseline. Some fonts, like Verdana, are strange and they position the baseline on the bottom of - the bounding box if that box has the same height as the font. For those fonts specify 0.0 for - both Ascent and Descent. -*/ -int U_PMR_drawstring( const char *string, int Vpos, uint32_t FontID, const U_PSEUDO_OBJ *BrushID, uint32_t FormatID, - U_PMF_STRINGFORMAT Sfs, const char *FontName, U_FLOAT Height, U_FontInfoParams *fip, uint32_t FontFlags, - U_FLOAT x, U_FLOAT y, U_PSEUDO_OBJ *sum, EMFTRACK *et){ - U_PSEUDO_OBJ *po; - U_PSEUDO_OBJ *poSF; - U_PSEUDO_OBJ *poFont; - U_PSEUDO_OBJ *poRect; - U_FLOAT rx,ry,rw,rh,rd; - uint16_t *UFontName; - uint16_t *Text16; - int slen; - int status = 0; - double aval, dval; - - Sfs.Flags = U_SF_NoFitBlackBox + U_SF_NoClip; - - if(Vpos < U_SA_Near || Vpos > U_SA_Far)return(0); - Sfs.StringAlignment = U_SA_Near; // Horizontal - Sfs.LineAlign = Vpos; // Vertical - - UFontName = U_Utf8ToUtf16le(FontName, 0, NULL); - slen = strlen(FontName); - poFont = U_PMF_FONT_set(U_PMF_GRAPHICSVERSIONOBJ_set(2), Height, U_UT_World, FontFlags, slen, UFontName); - if(poFont){ - po = U_PMR_OBJECT_PO_set(FontID, poFont); /* font to use */ - if(po){ - U_PMR_write(po, sum, et); - - poSF = U_PMF_STRINGFORMAT_set(&Sfs, NULL); - if(poSF){ - po = U_PMR_OBJECT_PO_set(FormatID, poSF); - U_PO_free(&poSF); - if(po){ - U_PMR_write(po, sum, et); - - rw = 4*Height*slen; /* This could probably be any value */ - rh = Height; - rx = x; - if(fip->LineGap > -fip->Descent){ aval = fip->yMax; } // sylfaen, palatino - else { aval = fip->Ascent; } // others - if(fip->LineGap && (fip->LineGap < -fip->Descent)){ dval = ((double) (fip->Descent - fip->LineGap)) / ((double) fip->EmSize); } //shruti and some others - else { dval = ((double) fip->Descent ) / ((double) fip->EmSize); } - switch(Vpos){ - case U_SA_Near: - rd = Height * aval / ((double) fip->EmSize); - break; - case U_SA_Center: - rd = 0.5 * ( Height * aval / ((double) fip->EmSize) + Height * ( 1.0 + dval)); - break; - case U_SA_Far: - rd = Height * ( 1.0 + dval); - break; - } - ry = y - rd; /* draw from upper left corner, which is shifted to put baseline on y */ - poRect = U_PMF_RECTF4_set(rx, ry, rw, rh); -#if 0 -(void) U_PMR_drawline(OBJ_PEN_BLACK_1,OBJ_PATH_1, (U_PMF_POINTF){x-100, ry}, (U_PMF_POINTF){x+100, ry}, 0, sum, et); -(void) U_PMR_drawline(OBJ_PEN_BLACK_1,OBJ_PATH_1, (U_PMF_POINTF){x-100, ry+rh}, (U_PMF_POINTF){x+100, ry+rh}, 0, sum, et); -(void) U_PMR_drawline(OBJ_PEN_BLACK_1,OBJ_PATH_1, (U_PMF_POINTF){x-100, ry}, (U_PMF_POINTF){x-100, ry + Height * (double) fip->Ascent / ((double) fip->EmSize)}, 0, sum, et); -(void) U_PMR_drawline(OBJ_PEN_BLACK_1,OBJ_PATH_1, (U_PMF_POINTF){x- 90, ry}, (U_PMF_POINTF){x- 90, ry - Height * (double) fip->Descent / ((double) fip->EmSize)}, 0, sum, et); -(void) U_PMR_drawline(OBJ_PEN_BLACK_1,OBJ_PATH_1, (U_PMF_POINTF){x- 80, ry}, (U_PMF_POINTF){x- 80, ry + Height * (double) fip->yMax / ((double) fip->EmSize)}, 0, sum, et); -(void) U_PMR_drawline(OBJ_PEN_BLACK_1,OBJ_PATH_1, (U_PMF_POINTF){x- 70, ry}, (U_PMF_POINTF){x- 70, ry - Height * (double) fip->yMin / ((double) fip->EmSize)}, 0, sum, et); -(void) U_PMR_drawline(OBJ_PEN_BLACK_1,OBJ_PATH_1, (U_PMF_POINTF){x- 60, ry}, (U_PMF_POINTF){x- 60, ry + Height * (double) fip->LineGap / ((double) fip->EmSize)}, 0, sum, et); -(void) U_PMR_drawline(OBJ_PEN_BLACK_1,OBJ_PATH_1, (U_PMF_POINTF){x- 50, ry}, (U_PMF_POINTF){x- 50, ry + Height * ( 1.0 - (((double) (fip->LineGap - fip->Descent)) / ((double) fip->EmSize)) )}, 0, sum, et); -#endif - - Text16 = U_Utf8ToUtf16le(string, 0, NULL); - slen = strlen(string); - po = U_PMR_DRAWSTRING_set(FontID, BrushID, FormatID, slen, poRect, Text16); - if(po){ - U_PMR_write(po, sum, et); - status = 1; /* Success!!! */ - } - U_PO_free(&poRect); - free(Text16); - } - } - } - U_PO_free(&poFont); - } - free(UFontName); - return(status); -} - -/** - \brief Allocate and construct an array of U_POINT16 objects from a set of U_PMF_POINTF objects, endianness in and out is LE - \returns pointer to an array of U_POINT16 structures. - \param points pointer to the source U_POINT structures - \param count number of members in points - - If a coordinate is out of range it saturates at boundary. -*/ -U_PMF_POINT *POINTF_To_POINT16_LE(U_PMF_POINTF *points, int count){ - U_PMF_POINT *newpts; - U_PMF_POINTF ptfl; - int i; - newpts = (U_PMF_POINT *) malloc(count * sizeof(U_PMF_POINT)); - - for(i=0; i<count; i++){ - memcpy(&ptfl, &(points[i]), 8); - if(U_BYTE_SWAP){ U_swap4(&ptfl,2); } /* on BE platforms swap going in and coming out */ - newpts[i].X = U_MNMX(ptfl.X, INT16_MIN, INT16_MAX); - newpts[i].Y = U_MNMX(ptfl.Y, INT16_MIN, INT16_MAX); - if(U_BYTE_SWAP){ U_swap2(&(newpts[i]),2); } - } - return(newpts); -} - -/** - \brief Look up the name of the EMR+ record by type. Returns U_EMR_INVALID if out of range. - - \return name of the PMR record, "U_EMR_INVALID" if out of range. - \param idx PMR record type WITHOUT the U_PMR_RECFLAG bit. - -*/ -char *U_pmr_names(unsigned int idx){ - if(idx<U_PMR_MIN || idx > U_PMR_MAX){ idx = 0; } - static char *U_PMR_NAMES[U_PMR_MAX+1]={ - "U_PMR_INVALID", - "U_PMR_Header", - "U_PMR_EndOfFile", - "U_PMR_Comment", - "U_PMR_GetDC", - "U_PMR_MultiFormatStart", - "U_PMR_MultiFormatSection", - "U_PMR_MultiFormatEnd", - "U_PMR_Object", - "U_PMR_Clear", - "U_PMR_FillRects", - "U_PMR_DrawRects", - "U_PMR_FillPolygon", - "U_PMR_DrawLines", - "U_PMR_FillEllipse", - "U_PMR_DrawEllipse", - "U_PMR_FillPie", - "U_PMR_DrawPie", - "U_PMR_DrawArc", - "U_PMR_FillRegion", - "U_PMR_FillPath", - "U_PMR_DrawPath", - "U_PMR_FillClosedCurve", - "U_PMR_DrawClosedCurve", - "U_PMR_DrawCurve", - "U_PMR_DrawBeziers", - "U_PMR_DrawImage", - "U_PMR_DrawImagePoints", - "U_PMR_DrawString", - "U_PMR_SetRenderingOrigin", - "U_PMR_SetAntiAliasMode", - "U_PMR_SetTextRenderingHint", - "U_PMR_SetTextContrast", - "U_PMR_SetInterpolationMode", - "U_PMR_SetPixelOffsetMode", - "U_PMR_SetCompositingMode", - "U_PMR_SetCompositingQuality", - "U_PMR_Save", - "U_PMR_Restore", - "U_PMR_BeginContainer", - "U_PMR_BeginContainerNoParams", - "U_PMR_EndContainer", - "U_PMR_SetWorldTransform", - "U_PMR_ResetWorldTransform", - "U_PMR_MultiplyWorldTransform", - "U_PMR_TranslateWorldTransform", - "U_PMR_ScaleWorldTransform", - "U_PMR_RotateWorldTransform", - "U_PMR_SetPageTransform", - "U_PMR_ResetClip", - "U_PMR_SetClipRect", - "U_PMR_SetClipPath", - "U_PMR_SetClipRegion", - "U_PMR_OffsetClip", - "U_PMR_DrawDriverstring", - "U_PMR_StrokeFillPath", - "U_PMR_SerializableObject", - "U_PMR_SetTSGraphics", - "U_PMR_SetTSClip" - }; - return(U_PMR_NAMES[idx]); -} - -/** - \brief Convert from PseudoObject OID to ObjectType enumeration. - \returns OT value on success, 0 if no match - \param OID PseudoObject OID (based on EMF+ manual chapter number. ) - - Only OTs that may be stored in the EMF+ object table are supported. -*/ - -int U_OID_To_OT(uint32_t OID){ - int otype; - if( OID==U_PMF_BRUSH_OID ){ otype = U_OT_Brush; } - else if(OID==U_PMF_PEN_OID ){ otype = U_OT_Pen; } - else if(OID==U_PMF_PATH_OID ){ otype = U_OT_Path; } - else if(OID==U_PMF_REGION_OID ){ otype = U_OT_Region; } - else if(OID==U_PMF_IMAGE_OID ){ otype = U_OT_Image; } - else if(OID==U_PMF_FONT_OID ){ otype = U_OT_Font; } - else if(OID==U_PMF_STRINGFORMAT_OID ){ otype = U_OT_StringFormat; } - else if(OID==U_PMF_IMAGEATTRIBUTES_OID){ otype = U_OT_ImageAttributes; } - else if(OID==U_PMF_CUSTOMLINECAP_OID ){ otype = U_OT_CustomLineCap; } - else { otype = U_OT_Invalid; } - return(otype); -} - -/** - \brief Convert from PseudoObject OID to BrushType enumeration. - \returns BT value on success, -1 if no match - \param OID PseudoObject OID (based on EMF+ manual chapter number. ) - - Only OIDs that map to BT's are supported. -*/ - -int U_OID_To_BT(uint32_t OID){ - int otype; - if( OID==U_PMF_HATCHBRUSHDATA_OID ){ otype = U_BT_HatchFill; } - else if(OID==U_PMF_LINEARGRADIENTBRUSHDATA_OID ){ otype = U_BT_LinearGradient; } - else if(OID==U_PMF_PATHGRADIENTBRUSHDATA_OID ){ otype = U_BT_PathGradient; } - else if(OID==U_PMF_SOLIDBRUSHDATA_OID ){ otype = U_BT_SolidColor; } - else if(OID==U_PMF_TEXTUREBRUSHDATA_OID ){ otype = U_BT_TextureFill; } - else { otype = -1; } - return(otype); -} - -/** - \brief Convert from PseudoObject OID to CustomLineCapDataType Enumeration. - \returns BT value on success, -1 if no match - \param OID PseudoObject OID (based on EMF+ manual chapter number. ) - - Only OIDs that map to CLCDT's are supported. -*/ - -int U_OID_To_CLCDT(uint32_t OID){ - int otype; - if( OID==U_PMF_CUSTOMLINECAPDATA_OID ){ otype = U_CLCDT_Default; } - else if(OID==U_PMF_CUSTOMLINECAPARROWDATA_OID ){ otype = U_CLCDT_AdjustableArrow; } - else { otype = -1; } - return(otype); -} - -/** - \brief Convert from PseudoObject OID to ImageDataType Enumeration. - \returns BT value on success, -1 if no match - \param OID PseudoObject OID (based on EMF+ manual chapter number. ) - - Only OIDs that map to IDT's are supported. -*/ - -int U_OID_To_IDT(uint32_t OID){ - int otype; - if( OID==U_PMF_BITMAP_OID ){ otype = U_IDT_Bitmap; } - else if(OID==U_PMF_METAFILE_OID ){ otype = U_IDT_Metafile; } - else { otype = -1; } - return(otype); -} - -/** - \brief Convert from PseudoObject OID to RegionNodeDataType Enumeration. - \returns BT value on success, -1 if no match - \param OID PseudoObject OID (based on EMF+ manual chapter number. ) - - Only OIDs that map to RNDT's are supported. -*/ - -int U_OID_To_RNDT(uint32_t OID){ - int otype; - if( OID==U_PMF_REGIONNODECHILDNODES_OID ){ otype = U_RNDT_Kids; } /* there are 5 types, which must be specified separately */ - else if(OID==U_PMF_RECTF_OID ){ otype = U_RNDT_Rect; } - else if(OID==U_PMF_REGIONNODEPATH_OID ){ otype = U_RNDT_Path; } - else { otype = -1; } - return(otype); -} - -/** - \brief Append data to an U_OBJ_ACCUM structure. - \param oa pointer to the U_OBJ_ACCUM structure - \param data data to add - \param size bytes in data - \param Type object type - \param Id Object ID - \returns 0 on success, !0 on error. -1 on Type change, -2 on Id change - - Safe to test for Id, Type changes by calling with size=0. -*/ -int U_OA_append(U_OBJ_ACCUM *oa, const char *data, int size, int Type, int Id){ - int tail; - if(!oa)return(2); - if(oa->used){ - if(oa->Type != Type)return(-1); - if(oa->Id != Id)return(-2); - } - tail = oa->used; - if(oa->used + size >= oa->space){ - oa->space += size; - char *newaccum = (char *) realloc(oa->accum, oa->space); - if(!newaccum){ - oa->space -= size; /* put it back the way it was */ - return(1); - } - oa->accum = newaccum; - } - memcpy(oa->accum + tail,data,size); - oa->used += size; - oa->Type = Type; - oa->Id = Id; - return(0); -} - - -/** - \brief Clear an U_OBJ_ACCUM structure. Accumulated storage is retained. - \param oa pointer to the U_OBJ_ACCUM structure - \returns 0 on success, !0 on error. -*/ -int U_OA_clear(U_OBJ_ACCUM *oa){ - if(!oa)return(2); - oa->used=0; - /* Type and Id may be ignored as they are reset on the first append */ - return(0); -} - -/** - \brief Release an U_OBJ_ACCUM structure. Accumulated storage is free'd. - \param oa pointer to the U_OBJ_ACCUM structure - \returns 0 on success, !0 on error. -*/ -int U_OA_release(U_OBJ_ACCUM *oa){ - if(!oa)return(2); - oa->used=0; - oa->space = 0; - if(oa->accum)free(oa->accum); - oa->accum=NULL; - return(0); -} - -/** - \brief Create and set an U_PSEUDO_OBJ - \returns pointer to the U_PSEUDO_OBJ, NULL on error - \param Data Data to copy into the PseudoObject's data. If NULL, space is allocated, but is cleared instead of filled. - \param Size Number of bytes to allocate for Data (may be >Use if padding is present) - \param Use Number of data bytes in Data (whether or not Data is actually copied) - \param Type Type numbers are from manual section: 1.2.3.47 -> 0x01020347 - - If Data is NULL and Size is 0 an empty PseudoObject is created. One byte of storage - is allocated for Data, Size is set to 1, and Used to 0. - - If Data is NULL and Size is !0 a zero filled PseudoObject is created. - - If Data is !Null and Size is !0 a data filled PseudoObject is created. -*/ -U_PSEUDO_OBJ *U_PO_create(char *Data, size_t Size, size_t Use, uint32_t Type){ - if(Use>Size)return(NULL); - size_t tSize = (Size ? Size : 1); - U_PSEUDO_OBJ *po = (U_PSEUDO_OBJ *)malloc(sizeof(U_PSEUDO_OBJ)); - if(po){ - po->Data = malloc(tSize); - if(po->Data){ - po->Size = tSize; - po->Used = Use; - po->Type = Type; - if(Data){ memcpy(po->Data, Data, Use); } /* if Use < Size uninitialized bytes will be present! */ - else { memset(po->Data, 0, tSize); } - } - else { - free(po); - po=NULL; - } - } - return(po); -} - -/** - \brief Append data to a U_PSEUDO_OBJ object and return it - \returns pointer to the U_PSEUDO_OBJ object, NULL on error - \param po PseudoObject to append to. Cannot be NULL. - \param Data Data to copy into the PseudoObject's data. If NULL, space is allocated (if necessary) and cleared instead of filled. - \param Size Number of data bytes in Data -*/ -U_PSEUDO_OBJ *U_PO_append(U_PSEUDO_OBJ *po, const char *Data, size_t Size){ - /* po cannot be NULL,as in U_PO_po_append(), because there would be no way to determine the TYPE of the resulting PO */ - if(po){ - if(!po->Data || po->Used + Size > po->Size){ - po->Size = po->Used + Size; - char *newData = realloc(po->Data, po->Size); - if(!newData){ - po->Size -= Size; /* put it back the way it was*/ - po=NULL; /* skip the rest of the actions, does not affect po in caller */ - } - else { - po->Data = newData; - } - } - if(po){ /* po->Data ready to append new data */ - if(Data){ memcpy(po->Data + po->Used, Data, Size); } - else { memset(po->Data + po->Used, 0, Size); } - po->Used += Size; - } - } - return(po); -} - -/** - \brief Append data to a U_PSEUDO_OBJ object and return it - \returns pointer to the U_PSEUDO_OBJ object, NULL on error - \param po PseudoObject to append to. May be NULL. - \param Src PseudoObject to append. - \param StripE Set: leading Elements in Src->Data is not copied, Clear: it is copied. -*/ -U_PSEUDO_OBJ *U_PO_po_append(U_PSEUDO_OBJ *po, U_PSEUDO_OBJ *Src, int StripE){ - if(!Src){ return(NULL); } - if((StripE && (Src->Used == 4)) || !Src->Used){ return(po); } /* appending nothing is not an error */ - char *Data = Src->Data; - size_t Size = Src->Used; /* append only what is used */ - U_PSEUDO_OBJ *ipo = po; - if(StripE){ Size -= 4; } - if(!ipo){ - ipo = U_PO_create(NULL, 0, 0, Src->Type); /* create an empty pseudoobject */ - } - if(ipo){ - if(!ipo->Data || ipo->Used + Size > ipo->Size){ - ipo->Size = ipo->Used + Size; - char *newData = realloc(ipo->Data, ipo->Size); - if(!newData){ - if(ipo != po)U_PO_free(&ipo); - } - else { - ipo->Data = newData; - } - } - if(ipo){ - if(Data){ - if(StripE){ memcpy(ipo->Data + ipo->Used, Data + 4, Size); } /* Size is already 4 less, skip the leading Elements value */ - else { memcpy(ipo->Data + ipo->Used, Data, Size); } /* copy everything */ - } - else { memset(ipo->Data + ipo->Used, 0, Size); } /* set everything */ - ipo->Used += Size; - } - } - return(ipo); -} - -/** - \brief Free an U_PSEUDO_OBJ structure. All associated memory is released. - \param po Address of a pointer to the U_PSEUDO_OBJ structure, Pointer is set to NULL. - \returns 1 on success, 0 on error. -*/ -int U_PO_free(U_PSEUDO_OBJ **po){ - if(!po)return(0); - if(!*po)return(1); - if((*po)->Data)free((*po)->Data); - free(*po); - *po=NULL; - return(1); -} - -/** \brief create a PseudoObject with data in the correct byte order for an EMF+ file. - \returns The PseudoObject on success, NULL on error. - - \param Type the type of the PseudoObject that is created. Allowed values are in U_PID_Values. - \param List an array of U_SERIAL_DESC structures containing the data to store. - - The U_PMF_SERIAL_set() function should not ever be called directly by end user code. - - Each U_SERIAL_DESC element in List consists of Data fields and a description of that data. List is terminated - by the first U_SERIAL_DESC element having a TE value of U_XX. - - Data fields: an array of a basic type of Units bytes repeated Reps times with the target byte order - described in TE. - - Ptrs: Address of the first byte of the data fields. - - Units: Number of bytes of in each data field unit - - Reps: Number of repeats of the unit in data fields. - If a Ptr is NULL, and Units*Reps is not zero, then Units*Reps 0x00 bytes are stored. - If a Ptr is NULL, and Units*Reps is zero, this U_SERIAL_DESC is ignored. - if a Ptr is NOT NULL, and Units * Reps is not zero, then the data is stored in the indicated byte order. - If a Ptr is NOT NULL, and Units or Reps is zero an error is signaled. - - TE: (Target Endian) the byte order in which to store each unit of a data field as defined in U_Endian. - Byte swapping is only enabled when Units is 2 or 4. In addition to the byte order values U_XE, U_LE, - and U_BE, and the array terminator U_XX, the value may also be U_RP. U_RP means there is only a - single unit in the data fields, but it is to be copied to the target Reps times. That is, the data - was passed in with a form of run length encoding. - - Creates an empty PseudoObject if all pointers are NULL and all sizes are zero. - */ -U_PSEUDO_OBJ *U_PMF_SERIAL_set(uint32_t Type, const U_SERIAL_DESC *List){ - U_PSEUDO_OBJ *po=NULL; - size_t Total=0; - size_t FSize; - char *cptr; - char *hptr; - const U_SERIAL_DESC *lptr; - if(!List)return(NULL); - for(lptr=List; lptr->TE != U_XX; lptr++){ - if(!(lptr->Units * lptr->Reps) && lptr->Ptr)return(po); - Total += lptr->Units * lptr->Reps; - } - po = U_PO_create(NULL, Total, Total, Type); - if(po){ - cptr = po->Data; - for(lptr=List; lptr->TE != U_XX; lptr++){ - FSize = lptr->Units * lptr->Reps; - if(FSize){ /* Ptr is not NULL, that would have been detected already */ - hptr = cptr; - if(lptr->TE & U_RP){ U_PMF_REPCPY_DSTSHIFT(&cptr, lptr->Ptr, lptr->Units, lptr->Reps); } - else { U_PMF_MEMCPY_DSTSHIFT(&cptr, lptr->Ptr, FSize); } - if(((lptr->TE & U_LE) && U_IS_BE) || ((lptr->TE & U_BE) && U_IS_LE)){ - if(lptr->Units==2){ U_swap2(hptr,lptr->Reps); } - else if(lptr->Units==4){ U_swap4(hptr,lptr->Reps); } - } - } - } - } - return(po); -} - -/** - \brief Create U_DPSEUDO_OBJ's for the Points and Types of a path - \param Elements Number of elements in Points. May be zero, which creates an empty path. - \param Points Array of U_PMF_POINTF values. - \param First Apply to first point, unsigned byte, lower 4 bits hold the PathPointType flag upper 4 bits hold the PathPointType enumeration. Must have U_PPT_Start set. - \param Others Apply to all other points, unsigned byte, lower 4 bits hold the PathPointType flag upper 4 bits hold the PathPointType enumeration. Must have U_PPT_Line or U_PPT_Bezier set. - \returns pointer to the DU_PSEUDO_OBJ object, NULL on error -*/ -U_DPSEUDO_OBJ *U_PATH_create(int Elements, const U_PMF_POINTF *Points, uint8_t First, uint8_t Others){ - if(Elements){ - if(!Points){ return(NULL); } - if( (First & U_PPT_MASK) != U_PPT_Start ){ return(NULL); } - if(!(Others & U_PPT_Bezier)){ return(NULL); } /* will pass if either line or bezier is set */ - } - - U_DPSEUDO_OBJ *Path = (U_DPSEUDO_OBJ *)calloc(sizeof(U_DPSEUDO_OBJ),1); /* make poTypes and poPoints NULL */ - const U_SERIAL_DESC List[] = { {NULL,0,0,U_XX} }; - if(Path){ - Path->Elements = Elements; - Path->poPoints = U_PMF_SERIAL_set(U_PMF_RAW_OID, List); /* Empty PO to hold points as raw data */ - if(!Elements){ - Path->poTypes = U_PMF_SERIAL_set(U_PMF_RAW_OID, List); /* Empty PO to hold types as raw data */ - } - else { - Path->poPoints = U_PO_append(Path->poPoints, (char *)Points, Elements*sizeof(U_PMF_POINTF)); - if(Path->poPoints){ - U_PSEUDO_OBJ *tpo = U_PMF_PATHPOINTTYPE_set2(Elements, First | U_PPT_Start, Others); /* PO holding types, has leading Elements value */ - Path->poTypes = U_PO_po_append(NULL, tpo, U_PMF_DROP_ELEMENTS); /* remove the leading Elements value*/ - U_PO_free(&tpo); - if(!Path->poTypes){ U_PO_free(&Path->poPoints); } - } - if(!Path->poPoints){ U_DPO_free(&Path); } - } - } - return(Path); -} - -/** - \brief Free U_DPSEUDO_OBJ's - \returns 1 on success, 0 on error. -*/ -int U_DPO_free(U_DPSEUDO_OBJ **dpo){ - if(!dpo){ return(0); } - if(!*dpo){ return(1); } - U_DPSEUDO_OBJ *kpo = *dpo; - if(kpo->poPoints){ U_PO_free(&kpo->poPoints); } - if(kpo->poTypes){ U_PO_free(&kpo->poTypes); } - free(*dpo); - *dpo=NULL; - return(1); -} - -/** - \brief Clear U_DPSEUDO_OBJ's. Memory is retained, Elements and Used values are set to 0. - \returns 1 on success, 0 on error. - - It is much more efficient to clear a DPO and reuse it than to free that DPO and create another. -*/ -int U_DPO_clear(U_DPSEUDO_OBJ *dpo){ - if(!dpo){ return(0); } - if(dpo->poPoints){ dpo->poPoints->Used = 0; } - if(dpo->poTypes){ dpo->poTypes->Used = 0; } - dpo->Elements = 0; - return(1); -} - -/** - \brief Append a "moveto" point to a path - \param Path Address of a DoublePseudoObject holding the path to append to. - \param Point Point to move to. - \param Flags Flags may be (U_PTP_None, U_PTP_DashMode, U_PTP_PathMarker, U_PTP_NoBit, U_PTP_CloseSubpath) - \returns 1 on success, 0 on error. -*/ -int U_PATH_moveto(U_DPSEUDO_OBJ *Path, U_PMF_POINTF Point, uint8_t Flags){ - if(!Path){ return(0); } - U_PSEUDO_OBJ *tpo; - U_PSEUDO_OBJ *tpo2; - uint8_t Type = (Flags & U_PTP_NotClose) | U_PPT_Start; - - tpo = U_PMF_POINTF_set(1, &Point); - if(!tpo){ return(0); } - tpo2 = U_PO_po_append(Path->poPoints, tpo, U_PMF_DROP_ELEMENTS); - U_PO_free(&tpo); - if(!tpo2)return(0); - Path->poPoints = tpo2; - - - tpo = U_PMF_PATHPOINTTYPE_set(1, &Type); - if(!tpo){ return(0); } - tpo2= U_PO_po_append(Path->poTypes, tpo, U_PMF_DROP_ELEMENTS); - U_PO_free(&tpo); - if(!tpo2)return(0); - Path->poTypes = tpo2; - - Path->Elements++; - return(1); -} - -/** - \brief Append a "lineto" point to a path - \param Path Address of a DoublePseudoObject holding the path to append to. - \param Point U_PMF_POINTF point to draw to. - \param Flags Flags may be (U_PTP_None, U_PTP_DashMode, U_PTP_PathMarker, U_PTP_NoBit, U_PTP_CloseSubpath) - \returns 1 on success, 0 on error. -*/ -int U_PATH_lineto(U_DPSEUDO_OBJ *Path, U_PMF_POINTF Point, uint8_t Flags){ - if(!Path || !Path->Elements){ return(0); } /* must be at least one point to extend from */ - if(Path->poTypes->Data[Path->Elements - 1] & U_PTP_CloseSubpath){ return(0); } /* cannot extend a closed subpath */ - U_PSEUDO_OBJ *tpo; - U_PSEUDO_OBJ *tpo2; - uint8_t Type = (Flags & U_PTP_NotClose) | U_PPT_Line; - tpo = U_PMF_POINTF_set(1, &Point); - if(!tpo){ return(0); } - tpo2 = U_PO_po_append(Path->poPoints, tpo, U_PMF_DROP_ELEMENTS); - U_PO_free(&tpo); - if(!tpo2)return(0); - Path->poPoints = tpo2; - - - tpo = U_PMF_PATHPOINTTYPE_set(1, &Type); - if(!tpo){ return(0); } - tpo2 = U_PO_po_append(Path->poTypes, tpo, U_PMF_DROP_ELEMENTS); - U_PO_free(&tpo); - if(!tpo2)return(0); - Path->poTypes = tpo2; - - Path->Elements++; - return(1); -} - -/** - \brief Set the closepath bit in the last point - \param Path Address of a DoublePseudoObject holding the path to act upon. - \returns 1 on success, 0 on error. -*/ -int U_PATH_closepath(U_DPSEUDO_OBJ *Path){ - if(!Path || !Path->poTypes){ return(0); } - uint32_t Elements = Path->Elements; - uint8_t *Type = (uint8_t *)(Path->poTypes->Data) + Elements - 1; - if(*Type & U_PPT_Start){ return(0); } /* single point closed path makes no sense */ - *Type = *Type | U_PTP_CloseSubpath; - return(1); -} - -/** - \brief Append a "polylineto" set of point to a path - \param Path Address of a DoublePseudoObject holding the path to append to. - \param Elements number of Points and Flags - \param Points Line points. - \param Flags Flags (U_PTP_None, U_PTP_DashMode, U_PTP_PathMarker, U_PTP_NoBit, but NOT U_PTP_CloseSubpath) - \param StartSeg If set, use U_PPT_Start PathPointType enumeration for first point, otherwise use U_PPT_Line. - \returns 1 on success, 0 on error. -*/ -int U_PATH_polylineto(U_DPSEUDO_OBJ *Path, uint32_t Elements, const U_PMF_POINTF *Points, uint8_t Flags, uint8_t StartSeg){ - if(!Path || !Points){ return(0); } - if(!Elements){ return(1); } /* harmless - do nothing */ - U_PSEUDO_OBJ *tpo; - U_PSEUDO_OBJ *tpo2; - uint8_t First, Others; - - tpo = U_PMF_POINTF_set(Elements, Points); - tpo2 = U_PO_po_append(Path->poPoints, tpo, U_PMF_DROP_ELEMENTS); - U_PO_free(&tpo); - if(!tpo2)return(0); - Path->poPoints = tpo2; - - if(StartSeg){ First = (Flags & U_PTP_NotClose) | U_PPT_Start; } - else { First = (Flags & U_PTP_NotClose) | U_PPT_Line; } - Others = (Flags & U_PTP_NotClose) | U_PPT_Line; - tpo = U_PMF_PATHPOINTTYPE_set2(Elements, First, Others); - if(!tpo){ return(0); } - tpo2 = U_PO_po_append(Path->poTypes, tpo, U_PMF_DROP_ELEMENTS); - U_PO_free(&tpo); - if(!tpo2)return(0); - Path->poTypes = tpo2; - - Path->Elements += Elements; - return(1); -} - - -/** - \brief Append a "polybezierto" set of point to a path - \param Path Address of a DoublePseudoObject holding the path to append to. - \param Elements number of Points - \param Points Bezier points. Optional starting point, then N sets of 3, example: [P1] (Q12A Q12B P2) (Q23A Q23B P3). - \param Flags Flags (U_PTP_None, U_PTP_DashMode, U_PTP_PathMarker, U_PTP_NoBit, but NOT U_PTP_CloseSubpath) - \param StartSeg If set, use U_PPT_Start PathPointType enumeration for first point, otherwise use U_PPT_Bezier. - \returns 1 on success, 0 on error. - - If Start is set Elements must be 1 + multiple of 3. Ie, P1 Q12A Q12B P2 Q23A Q23B P3 - - If Start is clear Elements must be a multiple of 3. Ie, (P1, already in path) Q12A Q12B P2 Q23A Q23B P3 -*/ -int U_PATH_polybezierto(U_DPSEUDO_OBJ *Path, uint32_t Elements, const U_PMF_POINTF *Points, uint8_t Flags, uint8_t StartSeg){ - if(!Path || !Points){ return(0); } - if(!Elements){ - if(StartSeg){ return(0); } /* cannot have both a NEW segment and ZERO points */ - else{ return(1); } /* harmless - do nothing */ - } - if(StartSeg && ((Elements - 1) % 3)){ return(0); } /* new segment must be 1 + N*3 points */ - if(!StartSeg && (Elements % 3)){ return(0); } /* extend segment must be N*3 points */ - U_PSEUDO_OBJ *tpo; - U_PSEUDO_OBJ *tpo2; - uint8_t First, Others; - - tpo = U_PMF_POINTF_set(Elements, Points); - tpo2 = U_PO_po_append(Path->poPoints, tpo, U_PMF_DROP_ELEMENTS); - U_PO_free(&tpo); - if(!tpo2)return(0); - Path->poPoints = tpo2; - - if(StartSeg){ First = (Flags & U_PTP_NotClose) | U_PPT_Start; } - else { First = (Flags & U_PTP_NotClose) | U_PPT_Bezier; } - Others = (Flags & U_PTP_NotClose) | U_PPT_Bezier; - tpo = U_PMF_PATHPOINTTYPE_set2(Elements, First, Others); - if(!tpo){ return(0); } - tpo2 = U_PO_po_append(Path->poTypes, tpo, U_PMF_DROP_ELEMENTS); - U_PO_free(&tpo); - if(!tpo2)return(0); - Path->poTypes = tpo2; - - Path->Elements += Elements; - return(1); -} - -/** - \brief Append a "polygon" set of points to a path. - \param Path Address of a DoublePseudoObject holding the path to append to. - \param Elements number of Points and Flags - \param Points Line points. - \param Flags Flags (U_PTP_None, U_PTP_DashMode, U_PTP_PathMarker, U_PTP_NoBit, but NOT U_PTP_CloseSubpath) - \returns 1 on success, 0 on error. -*/ -int U_PATH_polygon(U_DPSEUDO_OBJ *Path, uint32_t Elements, const U_PMF_POINTF *Points, uint8_t Flags){ - int status = U_PATH_polylineto(Path, Elements, Points, Flags, U_SEG_NEW); - if(status){ - status = U_PATH_closepath(Path); - } - return(status); -} - -//! \cond -// These are not exposed in the API -/* Parameterized Ellipse coordinates */ -U_PMF_POINTF U_eparam(U_FLOAT a, U_FLOAT b, U_PMF_POINTF *center, double Ang, double Theta){ - U_PMF_POINTF point; - point.X = center->X + a*cos(Theta)*cos(Ang) - b*sin(Theta)*sin(Ang); - point.Y = center->Y + a*sin(Theta)*cos(Ang) + b*cos(Theta)*sin(Ang); - return(point); -} - -/* Parameterized Ellipse derivative */ -U_PMF_POINTF U_eparam2(U_FLOAT a, U_FLOAT b, double Ang, double Theta){ - U_PMF_POINTF point; - point.X = -a*cos(Theta)*sin(Ang) - b*sin(Theta)*cos(Ang); - point.Y = -a*sin(Theta)*sin(Ang) + b*cos(Theta)*cos(Ang); - return(point); -} - -double U_aparam(double Ang1, double Ang2){ - double Alpha; - double t2; - t2 = tan((Ang2 - Ang1)/2.0); - t2 *= t2; - Alpha = sin(Ang2 - Ang1) * (sqrt(4 + 3*t2) -1.0)/3.0; - return(Alpha); -} - -/* Parameterized Bezier point Q1 or Q2 derivative */ -U_PMF_POINTF U_qparam(double Alpha, double a, double b, U_PMF_POINTF *Point, double Ang, double Theta, int mode){ - U_PMF_POINTF Q, Prime; - Prime = U_eparam2(a,b,Ang,Theta); - if(mode==1){ /* Q1, anything else is Q2*/ - Q.X = Point->X + Alpha * Prime.X; - Q.Y = Point->Y + Alpha * Prime.Y; - } - else { - Q.X = Point->X - Alpha * Prime.X; - Q.Y = Point->Y - Alpha * Prime.Y; - } - return(Q); -} -//! \endcond - -/** - \brief Append an "arcto" set of points to a path (Bezier points are calculated, and these are appended - \param Path Address of a pointer to the U_PSEUDO_OBJ that holds points - \param Start Start angle, >=0.0, degrees clockwise from 3:00 - \param Sweep Sweep angle, -360<= angle <=360, degrees clockwise from Start - \param Rot Rotation angle to apply to coordinate system (Start and Rect), positive is degrees clockwise - \param Rect U_PMF_RECTF that defines the bounding rectangle. - \param Flags Flags (U_PTP_None, U_PTP_DashMode, U_PTP_PathMarker, U_PTP_NoBit, but NOT U_PTP_CloseSubpath) - \param StartSeg If set, the arc starts a new segment, if clear, continue the existing segment. Starting a new segment does not automatically apply U_PATH_closepath to the existing path. - \returns 1 on success, 0 on error. - - Based on Luc Maisonobe's work, http://www.spaceroots.org/documents/ellipse/ -*/ -int U_PATH_arcto(U_DPSEUDO_OBJ *Path, U_FLOAT Start, U_FLOAT Sweep, U_FLOAT Rot, U_PMF_RECTF *Rect, uint8_t Flags, int StartSeg){ - U_PMF_POINTF Bz[3]; - U_PMF_POINTF Center; - U_PMF_POINTF P1,P2; - double a, b; - int done = 0; - int fpoint = 0; - double L1, L2; /* These are degrees CounterClockwise from 3:00 */ - double Ang1, Ang2; /* These are parametric angles, derived from L1, L2*/ - double Alpha; /* Dimensionless number used for Q1, Q2 */ - double Theta; /* Rot in radians */ - double Slop; /* do not let rounding errors cause spurious end points */ - if(!Path){ return(0); } - if((Sweep > 360.0) || (Sweep < -360.0)){ return(0); } - /* Start should be between 0 and 360 degrees, but it does not really matter because sin, and cos will accept anything */ - /* the sign on Sweep and Start is correct bacause LM's derivation has y positive up, but GDI+ has y positive down. */ - a = Rect->Width/2.0; - b = Rect->Height/2.0; - if(!a || !b){ return(0); } - Center.X = Rect->X + a; - Center.Y = Rect->Y + b; - /* convert to radians */ - Start = (2.0 * U_PI * Start)/360.0; - Sweep = (2.0 * U_PI * Sweep)/360.0; - Theta = (2.0 * U_PI * Rot )/360.0; - Slop = Sweep/100000.0; - L1 = Start; - - while(!done){ - if(Sweep < 0){ - L2 = L1 - U_PI/2.0; - if(L2 <= Sweep + Start - Slop){ L2 = Sweep + Start; done = 1; } - else {done = 0; } - } - else { - L2 = L1 + U_PI/2.0; - if(L2 >= Sweep + Start + Slop){ L2 = Sweep + Start; done = 1; } - else {done = 0; } - } - Ang1 = atan2(sin(L1)/b, cos(L1)/a); - Ang2 = atan2(sin(L2)/b, cos(L2)/a); - Alpha = U_aparam(Ang1, Ang2); - P1 = U_eparam(a, b, &Center, Ang1, Theta); /* P1 */ - P2 = U_eparam(a, b, &Center, Ang2, Theta); /* P2 */ - Bz[0] = U_qparam(Alpha, a, b, &P1, Ang1, Theta, 1); /* Q1 */ - Bz[1] = U_qparam(Alpha, a, b, &P2, Ang2, Theta, 2); /* Q2 */ - Bz[2] = P2; - if(!fpoint){ - if(StartSeg){ U_PATH_moveto(Path, P1, Flags); } - else { U_PATH_lineto(Path, P1, Flags); } - fpoint = 1; - } - U_PATH_polybezierto(Path, 3, Bz, Flags, U_SEG_OLD ); - L1 = L2; - } - return(1); -} - -/** - \brief Allocate and construct an array of U_PMF_POINTF objects which have been subjected to a U_XFORM - \returns pointer to an array of U_PMF_POINTF structures. - \param points pointer to the source U_PMF_POINTF structures - \param count number of members in points - \param xform U_XFORM to apply - -*/ -U_PMF_POINTF *pointfs_transform(U_PMF_POINTF *points, int count, U_XFORM xform){ - U_PMF_POINTF *newpts=NULL;; - int i; - float X,Y; - newpts = (U_PMF_POINTF *) malloc(count * sizeof(U_PMF_POINTF)); - if(newpts){ - for(i=0; i<count; i++){ - X = points[i].X; - Y = points[i].Y; - newpts[i].X = U_ROUND(X * xform.eM11 + Y * xform.eM21 + xform.eDx); - newpts[i].Y = U_ROUND(X * xform.eM12 + Y * xform.eM22 + xform.eDy); - } - } - return(newpts); -} - -/** - \brief Allocate and construct an array of U_PMF_RECTF objects which have been subjected to a U_XFORM - \returns pointer to an array of U_PMF_RECTF structures. - \param Rects pointer to the source U_PMF_RECTF structures - \param Count number of members in Rects - \param Xform U_XFORM to apply. Rotation is ignored, only translation is applied. - -*/ -U_PMF_RECTF *rectfs_transform(U_PMF_RECTF *Rects, int Count, U_XFORM Xform){ - U_PMF_RECTF *newRects; - int i; - newRects = (U_PMF_RECTF *) malloc(Count * sizeof(U_PMF_RECTF)); - if(newRects){ - for(i=0; i<Count; i++){ - newRects[i].X = U_ROUND(Rects[i].X + Xform.eDx); - newRects[i].Y = U_ROUND(Rects[i].Y + Xform.eDy); - newRects[i].Width = U_ROUND(Rects[i].Width); - newRects[i].Height = U_ROUND(Rects[i].Height); - } - } - return(newRects); -} - -/** - \brief Utility function calculate the transformation matrix needed to make a gradient run precisely corner to corner of a rectangle - \param Angle Rotation in degrees clockwise of the gradient. 0 is horizontal gradient. - \param w Width of the rectangle - \param h Height of the rectangle - \param x X coordinate of upper left corner of rectangle - \param y Y coordinate of upper left corner of rectangle - \param Periods Periods of gradient corner to corner. 1.0 is one, corner to corner. - \return Transformation matrix. All values are zero if Periods, w, or h are less than or equal to zero. -*/ -U_PMF_TRANSFORMMATRIX tm_for_gradrect(U_FLOAT Angle, U_FLOAT w, U_FLOAT h, U_FLOAT x, U_FLOAT y, U_FLOAT Periods){ -//! \cond -#define CLOSE_TO_IS_REALLY_ZERO(A) ((A) > 1.0e-10 || (A) < -1.0e-10 ? (A) : 0.0) //! \hideinitializer -//! \endcond - U_PMF_TRANSFORMMATRIX tm; - double dang = Angle * 2*U_PI /360.0; - double scale; - double cd,sd; - if((Periods <=0.0) || (w <= 0.0) || (h <= 0.0)){ - tm.m11 = tm.m12 = tm.m21 = tm.m22 = tm.dX = tm.dY = 0.0; - } - else { - /* - scale is gradient period divided by w - The scale value sets the gradient period to match exactly with the inscribed (w,h) rectangle - in the direction specified by the angle. - The numberator of scale is the max of the four dot product values of the rotated X basis unit vector with (w,h), - with each of the vectors {w,h}, {-w,h}, {-w,-h}, {w,h}. Those vectors run from each corner in turn - to the opposite corner. The one most parallel to the rotated unit vector will have both terms positive. - - Trig results like cos(pi/2) are not stable between platforms due to minor differences in the - implementation. Detect these and make them zero, which then allows binary comparison of output files. - Otherwise the binary comparisons between platforms would fail because of a bunch of insignificant digits. - */ - cd = CLOSE_TO_IS_REALLY_ZERO(cos(dang)); - sd = CLOSE_TO_IS_REALLY_ZERO(sin(dang)); - scale = (w*fabs(cd) + h*fabs(sd))/(w*Periods); - tm.m11 = scale * cd; - tm.m12 = -scale * sd; - tm.m21 = scale * sd; - tm.m22 = scale * cd; - /* offset is to one corner of the square, depending on which quadrant the rotation selects. */ - if(cos(dang)>=0){ - tm.dX = x; - if(sin(dang)>=0){tm.dY = y + h; } // LL corner - else { tm.dY = y; } // UL corner - } - else { - tm.dX = x + w; - if(sin(dang)>=0){ tm.dY = y + h; } // LR corner - else { tm.dY = y; } // UR corner - } - } - return tm; -#undef CLOSE_TO_IS_REALLY_ZERO -} -/** - \brief Create a U_PSEUDO_OBJ containing a U_PMR_FILLPATH and U_PMR_DRAWPATH records. - \returns pointer to U_PSEUDO_OBJ or NULL on error. - \param PathID U_PMF_PATH object in the EMF+ object table (0-63, inclusive) - \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive) - \param BrushID U_PSEUDO_OBJ containing a U_PMF_ARGB or a U_PMF_4NUM. Color or U_PMF_BRUSH object in the EMF+ object table (0-63, inclusive) -*/ -U_PSEUDO_OBJ *U_PMR_drawfill(uint32_t PathID, uint32_t PenID, const U_PSEUDO_OBJ *BrushID){ - U_PSEUDO_OBJ *po = U_PMR_FILLPATH_set(PathID, BrushID); - if(po){ - U_PSEUDO_OBJ *tpo = U_PMR_DRAWPATH_set(PathID, PenID); - po = U_PO_po_append(po, tpo, U_PMF_KEEP_ELEMENTS); - U_PO_free(&tpo); - } - return(po); -} - - - -/** - \brief Extract a single data field from a source. - \returns 1 on success, 0 on error. - \param Src where the data is coming from. It is incremented by the number of bytes retrieved. - \param Dst where the data will be stored. This must either be NULL (in which case the Src - is advanced and nothing is stored, or it must be allocated to Reps * Units bytes!!!! - \param Units number of bytes in each unit of the data field - \param Reps number of repeats of units in the data field. - If a Ptr is NULL, then Units*Reps 0 bytes are stored. - If a Ptr is NOT NULL, and Units or Reps, is zero an error is signaled. - If a Ptr is NULL and Units*Reps is 0, nothing happens. - \param SE logical (Source Endian). Only relevant for Sizes of 2 or 4 - Indicates when Bytes may need to be rearranged when they are retrieved. - U_XE no change (this is used when the data has already been set to the proper orientation or it is not known) - U_LE source is Little Endian - U_BE source is Big Endian. - U_XX error - -*/ -int U_PMF_SERIAL_get(const char **Src, void *Dst, size_t Units, size_t Reps, int SE){ - if(!Src || !*Src || SE == U_XX){ return(0); } - U_PMF_MEMCPY_SRCSHIFT(Dst, Src, Units * Reps); - if(!Dst){ return(1); } /* "fake" get, no data was retrieved, so we are done */ - if(SE == U_XE){ return(1); } - if(SE == U_LE && U_IS_LE){ return(1); } - if(SE == U_BE && U_IS_BE){ return(1); } - /* need to swap */ - if( Units==2){ U_swap2(Dst,Reps); } - else if(Units==4){ U_swap4(Dst,Reps); } - return(1); -} - -/** - \brief Conditionally extract an array of data from a source, allocating space to hold it. - \returns 1 on success, 0 on error. - \param Src where the data is coming from. It is incremented by the number of bytes retrieved. - \param Dst Caller must free. Where the pointer to the data will be stored. Reps * Units bytes will be allocated, - \param Units number of bytes in each unit of the data field - \param Reps number of repeats of units in the data field. - If a Ptr is NULL, then Units*Reps 0 bytes are stored. - If a Ptr is NOT NULL, and Units or Reps, is zero an error is signaled. - If a Ptr is NULL and Units*Reps is 0, nothing happens. - \param SE logical (Source Endian). Only relevant for Sizes of 2 or 4 - Indicates when Bytes may need to be rearranged when they are retrieved. - U_XE no change (this is used when the data has already been set to the proper orientation or it is not known) - U_LE source is Little Endian - U_BE source is Big Endian. - U_XX error - \param Cond Store the data into *Dst if true, set *Dst to NULL otherwise. - -*/ -int U_PMF_SERIAL_array_copy_get(const char **Src, void **Dst, size_t Units, size_t Reps, int SE, int Cond){ - if(!Src || !*Src || !Dst || SE == U_XX){ return(0); } - if(!Cond){ - *Src += Units * Reps; - *Dst = NULL; - return(1); - } - *Dst = malloc(Units * Reps); - if(!*Dst){ return(1); } /* "fake" get, no data was retrieved, so we are done */ - U_PMF_MEMCPY_SRCSHIFT(*Dst, Src, Units * Reps); - if(SE == U_XE){ return(1); } - if(SE == U_LE && U_IS_LE){ return(1); } - if(SE == U_BE && U_IS_BE){ return(1); } - /* need to swap */ - if( Units==2){ U_swap2(*Dst,Reps); } - else if(Units==4){ U_swap4(*Dst,Reps); } - return(1); -} - - - -/** - \brief Calculate the length in bytes of a relative path object composed of U_PMF_INTEGER7 and U_PMF_INTER15 values - \return >=0 length == success, <0 error - \param contents Start of a relative path consisting of int7 and int15 X,Y pairs. - \param Elements number of relative X,Y pairs in the object -*/ -int U_PMF_LEN_REL715(const char *contents, int Elements){ - int length=0; - Elements *= 2; /* N pairs = 2N values */ - for( ; Elements; Elements--){ - /* X or Y value */ - if(*contents & U_TEST_INT7){ contents +=2; length +=2; } //int15 - else { contents +=1; length +=1; } //int7 - } - return(length); -} - -/** - \brief Calculate the length in bytes of objects which are a 4 byte Count followed by Count * float bytes - \return >=0 length == success, <0 error - Object types whose size may be derived with this function are: - U_PMF_COMPOUNDLINEDATA - U_PMF_DASHEDLINEDATA -*/ -int U_PMF_LEN_FLOATDATA(const char *contents){ - int Size; - U_PMF_SERIAL_get(&contents, &Size, 4, 1, U_LE); - Size = 4*Size + 4; - return(Size); -} - -/** - \brief Calculate the length in bytes of objects which are a 4 byte count followed by count bytes - \return >=0 length == success, <0 error - Object types whose size may be derived with this function are: - U_PMF_BOUNDARYPATHDATA - U_PMF_BOUNDARYPOINTDATA - U_PMF_CUSTOMSTARTCAPDATA - U_PMF_PATH - U_PMF_LINEPATH - U_PMF_REGIONNODEPATH -*/ -int U_PMF_LEN_BYTEDATA(const char *contents){ - int Size; - U_PMF_SERIAL_get(&contents, &Size, 4, 1, U_LE); - Size += 4; - return(Size); -} - -/** - \brief Create a string containing the curly bracket form of the 16 byte GUID value - \return number of bytes in record, 0 on error - \param GUID pointer to the 16 unsigned bytes - \return string in curly bracket form. - http://msdn.microsoft.com/en-us/library/cc230316.aspx - - Text form is Data1-Data2-Data3-Data4, the first 3 are stored as little endian integers, the last as a string (big endian). -*/ -char *U_PMF_CURLYGUID_set(uint8_t *GUID){ - char *string=malloc(64); - if(string){ - sprintf(string,"{%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X}", - GUID[3],GUID[2],GUID[1],GUID[0], - GUID[5],GUID[4], - GUID[7],GUID[6], - GUID[8],GUID[9], - GUID[10],GUID[11],GUID[12],GUID[13],GUID[14],GUID[15] - ); - } - return(string); -} - -/** - \brief Identify a known curly GUID - \param string Curly GUID form. - \return EmageEffects Enumerator - - EMF+ manual 2.1.3.1, Microsoft name: ImageEffects Identifier -*/ -int U_PMF_KNOWNCURLYGUID_set(const char *string){ - int status; - if( !strcmp(string,"{633C80A4-1843-482B-9EF2-BE2834C5FDD4}")){ status = U_IEE_BlurEffectGuid; } - else if(!strcmp(string,"{D3A1DBE1-8EC4-4C17-9F4C-EA97AD1C343D}")){ status = U_IEE_BrightnessContrastEffectGuid; } - else if(!strcmp(string,"{537E597D-251E-48DA-9664-29CA496B70F8}")){ status = U_IEE_ColorBalanceEffectGuid; } - else if(!strcmp(string,"{DD6A0022-58E4-4A67-9D9B-D48EB881A53D}")){ status = U_IEE_ColorCurveEffectGuid; } - else if(!strcmp(string,"{A7CE72A9-0F7F-40D7-B3CC-D0C02D5C3212}")){ status = U_IEE_ColorLookupTableEffectGuid; } - else if(!strcmp(string,"{718F2615-7933-40E3-A511-5F68FE14DD74}")){ status = U_IEE_ColorMatrixEffectGuid; } - else if(!strcmp(string,"{8B2DD6C3-EB07-4D87-A5F0-7108E26A9C5F}")){ status = U_IEE_HueSaturationLightnessEffectGuid;} - else if(!strcmp(string,"{99C354EC-2A31-4F3A-8C34-17A803B33A25}")){ status = U_IEE_LevelsEffectGuid; } - else if(!strcmp(string,"{74D29D05-69A4-4266-9549-3CC52836B632}")){ status = U_IEE_RedEyeCorrectionEffectGuid; } - else if(!strcmp(string,"{63CBF3EE-C526-402C-8F71-62C540BF5142}")){ status = U_IEE_SharpenEffectGuid; } - else if(!strcmp(string,"{1077AF00-2848-4441-9489-44AD4C2D7A2C}")){ status = U_IEE_TintEffectGuid; } - else { status = U_IEE_Unknown; } - return(status); -} - -/** \brief Load a GUID from text format into EMF+ file binary format. - \param string Curly GUID as text, minus the barckets and dashes. - \return GUID in EMF+ file binary format. - - -This accepts a string that is 16 bytes long = 32 characters hex (no dash spaces or brackets) as text. -Text form is; Data1|Data2|Data3|Data4, first three are stored as little endian integers of 4,2,2 bytes, respectively, -last is stored like a string (big endian), after conversion from text hex to binary. - -This function is not normally called by end user code. -*/ -uint8_t *U_LOAD_GUID(char *string){ - uint32_t Data1,tData2,tData3,tByte; - uint16_t Data2,Data3; - char *Data4 = string + 16; - uint8_t *hold = malloc(16); - char *lf = (char *) hold; - int i; - if(hold){ - Data1=tData2=tData3=0; - if(3 != sscanf(string + 0,"%8X",&Data1) + - sscanf(string + 8,"%4X",&tData2) + - sscanf(string + 12,"%4X",&tData3)){ - free(hold); - hold = NULL; - goto bye; - } - Data2=tData2; - Data3=tData3; - U_PMF_MEMCPY_DSTSHIFT(&lf, &Data1, 4); - U_PMF_MEMCPY_DSTSHIFT(&lf, &Data2, 2); - U_PMF_MEMCPY_DSTSHIFT(&lf, &Data3, 2); - if(U_IS_BE){ /* these fields are stored little endian */ - U_swap4(hold,1); - U_swap2(hold+4,2); - } - /* remainder is converted byte by byte and stored in that order */ - for(i=0;i<8;i++,Data4+=2,lf++){ - if(1 != sscanf(Data4,"%2X",&tByte)){ - free(hold); - hold = NULL; - goto bye; - } - *lf=tByte; - } - } -bye: - return(hold); -} - -/** - \brief Generate the 16 byte form from OID of the ImageEffects Identifier - \param OID OID of the ImageEffects Identifier - \return pointer to 16 byte buffer holding the long GUID binary form, or NULL on error. - - EMF+ manual 2.1.3.1, Microsoft name: ImageEffects Identifier -*/ -uint8_t *U_OID_To_GUID(uint32_t OID){ - uint8_t *lf = NULL; - if( OID == U_PMF_IE_BLUR_OID ){ lf = U_LOAD_GUID("633C80A41843482B9EF2BE2834C5FDD4"); } - else if(OID == U_PMF_IE_BRIGHTNESSCONTRAST_OID ){ lf = U_LOAD_GUID("D3A1DBE18EC44C179F4CEA97AD1C343D"); } - else if(OID == U_PMF_IE_COLORBALANCE_OID ){ lf = U_LOAD_GUID("537E597D251E48DA966429CA496B70F8"); } - else if(OID == U_PMF_IE_COLORCURVE_OID ){ lf = U_LOAD_GUID("DD6A002258E44A679D9BD48EB881A53D"); } - else if(OID == U_PMF_IE_COLORLOOKUPTABLE_OID ){ lf = U_LOAD_GUID("A7CE72A90F7F40D7B3CCD0C02D5C3212"); } - else if(OID == U_PMF_IE_COLORMATRIX_OID ){ lf = U_LOAD_GUID("718F2615793340E3A5115F68FE14DD74"); } - else if(OID == U_PMF_IE_HUESATURATIONLIGHTNESS_OID){ lf = U_LOAD_GUID("8B2DD6C3EB074D87A5F07108E26A9C5F"); } - else if(OID == U_PMF_IE_LEVELS_OID ){ lf = U_LOAD_GUID("99C354EC2A314F3A8C3417A803B33A25"); } - else if(OID == U_PMF_IE_REDEYECORRECTION_OID ){ lf = U_LOAD_GUID("74D29D0569A4426695493CC52836B632"); } - else if(OID == U_PMF_IE_SHARPEN_OID ){ lf = U_LOAD_GUID("63CBF3EEC526402C8F7162C540BF5142"); } - else if(OID == U_PMF_IE_TINT_OID ){ lf = U_LOAD_GUID("1077AF0028484441948944AD4C2D7A2C"); } - return(lf); -} - -/** - \brief copy data and shift source pointer by the amount of data moved - \param Dst Destination in memory - \param Src Source in memory - \param Size Number of bytes to move -*/ -void U_PMF_MEMCPY_SRCSHIFT(void *Dst, const char **Src, size_t Size){ - if(Dst)memcpy(Dst, *Src, Size); - *Src += Size; -} - -/** - \brief copy data and shift destination pointer by the amount of data moved - \param Dst Destination in memory (this must not be NULL) - \param Src Source in memory (if this is NULL, fill with that many zero bytes instead) - \param Size Number of bytes to move -*/ -void U_PMF_MEMCPY_DSTSHIFT(char **Dst, const void *Src, size_t Size){ - if(Src){ memcpy(*Dst, Src, Size); } - else { memset(*Dst, 0, Size); } - *Dst += Size; -} - -/** - \brief Copy the single instance at Src repeatedly to Dst. - \param Dst Destination in memory - \param Src Source in memory (if this is NULL, fill with that many zero bytes instead) - \param Size number of bytes in single instance that is template. - \param Reps Number of instances of the template to opy -*/ -void U_PMF_REPCPY_DSTSHIFT(char **Dst, const void *Src, size_t Size, size_t Reps){ - for(;Reps;Reps--){ - if(Src){ memcpy(*Dst, Src, Size); } - else { memset(*Dst, 0, Size); } - *Dst += Size; - } -} - -/** - \brief save pointer to data and shift source pointer by the amount of data moved - \param Dst Destination in memory - \param Src Source in memory or NULL. If NULL Dst is set to NULL. - \param Size Number of bytes to move -*/ -void U_PMF_PTRSAV_SHIFT(const char **Dst, const char **Src, size_t Size){ - if(*Src){ - if(Dst)*Dst = *Src; - *Src += Size; - } - else { - if(Dst)*Dst = NULL; - } -} - -/** - \brief save pointer to data and shift source pointer by the amount of data moved - \return 1 on sucess, 0 on error - \param Dst Destination in memory - \param Src Source in memory or NULL. If NULL Dst is set to NULL. - \param Doit Assign if true, otherwise, set to NULL -*/ -int U_PMF_PTRSAV_COND(const char **Dst, const char *Src, int Doit){ - if(!Dst){ return(0); } - if(Src && Doit){ *Dst = Src; } - else { *Dst = NULL; } - return(1); -} -/* - - ===================================================================================== - start of U_PMF_*_get() functions - -*/ - -/** - \brief Get the 16 bit unsigned Flags field from a header. - \param contents Record from which to extract data, will be incremented by header size. - \return Flags field - - In many records the only value needed from the header is Flags. Rather than mapping - the entire Header and returning it, in these instances this function may be called to - just get this one value. -*/ -uint16_t U_PMF_HEADERFLAGS_get(const char *contents){ - uint16_t Flags; - const char *cptr = contents + offsetof(U_PMF_CMN_HDR,Flags); - U_PMF_SERIAL_get(&cptr, &Flags, 2, 1, U_LE); /* EMF+ manual documents it as BE, but this code implements it as LE*/ - return(Flags); -} - -/** - \brief Retrieve whichever header fields are requested. NULL pointers do not retrieve. - \param contents Record from which to extract data, will be incremented by header size. - \param Type Record type - \param Flags Record flags - \param Size Records size - \param Datasize Data size - \return 1 on success, 0 on failure. -*/ -int U_PMF_HEADERFIELDS_get(const char *contents, - uint16_t *Type, uint16_t *Flags, uint32_t *Size, uint32_t *Datasize){ - if(!contents){ return(0); } - U_PMF_SERIAL_get(&contents, Type, 2, 1, U_LE); - U_PMF_SERIAL_get(&contents, Flags, 2, 1, U_LE); /* EMF+ manual documents it as BE, but this code implements it as LE*/ - U_PMF_SERIAL_get(&contents, Size, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Datasize, 4, 1, U_LE); - return(1); -} - -/** - \brief Get the entire EMF+ record header. - \param contents Record from which to extract data, will be offset by header size. - \param Header Location to store data (may be NULL) - \returns 1 - If Header is Null, nothing is stored but contents is still offset. -*/ -int U_PMF_CMN_HDR_get(const char **contents, U_PMF_CMN_HDR *Header){ - if(!contents || !*contents){ return(0); } - if(Header){ - U_PMF_SERIAL_get(contents, &(Header->Type), 2, 1, U_LE); - U_PMF_SERIAL_get(contents, &(Header->Flags), 2, 1, U_LE); /* EMF+ manual documents it as BE, but this code implements it as LE*/ - U_PMF_SERIAL_get(contents, &(Header->Size), 4, 1, U_LE); - U_PMF_SERIAL_get(contents, &(Header->DataSize), 4, 1, U_LE); - } - else { - *contents += sizeof(U_PMF_CMN_HDR); - } - return(1); -} - -/** - \brief return the size in bytes of the EMF+ record - \param contents Record from which to extract data, will not be modified. - \returns size, or 0 if contents is Null -*/ -int U_PMF_RECORD_SIZE_get(const char *contents){ - if(!contents){ return(0); } - int Size; - const char *from = contents + 4; - U_PMF_SERIAL_get(&from, &Size, 4, 1, U_LE); - return(Size); -} - -/** - \brief Return the size of a PenData object from an EMF+ record. - \param PenData Address in memory where the PenData object starts. - \returns size of the object in bytes -*/ -int U_PMF_LEN_PENDATA(const char *PenData){ - uint32_t Flags; - int length=12; /* Flags, Unit, Width */ - U_PMF_SERIAL_get(&PenData, &Flags, 4, 1, U_LE); - PenData += 8; /* skip Unit and Width */ - length += U_PMF_LEN_OPTPENDATA(PenData, Flags); - return(length); -} - -/** - \brief Return the size of an OptPenData object from an EMF+ record. - \param PenData Address in memory where the PenData object starts. - \param Flags PenData Flags that indicate which fields are present. - \returns size of the object in bytes -*/ -int U_PMF_LEN_OPTPENDATA(const char *PenData, uint32_t Flags){ - int length=0; - if(Flags & U_PD_Transform){ length += sizeof(U_PMF_TRANSFORMMATRIX); } - if(Flags & U_PD_StartCap){ length += sizeof(int32_t); } - if(Flags & U_PD_EndCap){ length += sizeof(int32_t); } - if(Flags & U_PD_Join){ length += sizeof(uint32_t); } - if(Flags & U_PD_MiterLimit){ length += sizeof(U_FLOAT); } - if(Flags & U_PD_LineStyle){ length += sizeof(int32_t); } - if(Flags & U_PD_DLCap){ length += sizeof(int32_t); } - if(Flags & U_PD_DLOffset){ length += sizeof(int32_t); } - if(Flags & U_PD_DLData){ length += U_PMF_LEN_FLOATDATA(PenData + length); } - if(Flags & U_PD_NonCenter){ length += sizeof(int32_t); } - if(Flags & U_PD_CLData){ length += U_PMF_LEN_FLOATDATA(PenData + length); } - if(Flags & U_PD_CustomStartCap){ length += U_PMF_LEN_BYTEDATA(PenData + length); } - if(Flags & U_PD_CustomEndCap){ length += U_PMF_LEN_BYTEDATA(PenData + length); } - return(length); -} - -/** - \brief Create and set a U_PMF_BRUSH PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Version EmfPlusGraphicsVersion object - \param Bd U_PSEUDO_OBJ containing one of the 5 types of Brush data - - EMF+ manual 2.2.1.1, Microsoft name: EmfPlusBrush Object -*/ -U_PSEUDO_OBJ *U_PMF_BRUSH_set(uint32_t Version, const U_PSEUDO_OBJ *Bd){ - if(!Bd){ return(NULL); } - int32_t Type = U_OID_To_BT(Bd->Type); - if(Type < 0){ return(NULL); } - const U_SERIAL_DESC List[] = { - {&Version, 4, 1, U_LE}, - {&Type, 4, 1, U_LE}, - {Bd->Data, Bd->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_BRUSH_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_CUSTOMLINECAP PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Version EmfPlusGraphicsVersion object - \param Ld U_PSEUDO_OBJ containing one of the 2 types of Linecap data - - EMF+ manual 2.2.1.2, Microsoft name: EmfPlusCustomLineCap Object -*/ -U_PSEUDO_OBJ *U_PMF_CUSTOMLINECAP_set(uint32_t Version, const U_PSEUDO_OBJ *Ld){ - if(!Ld){ return(NULL); } - int32_t Type = U_OID_To_CLCDT(Ld->Type); - if(Type<0){ return(NULL); } - const U_SERIAL_DESC List[] = { - {&Version, 4, 1, U_LE}, - {&Type, 4, 1, U_LE}, - {Ld->Data, Ld->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_CUSTOMLINECAP_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_FONT PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Version EmfPlusGraphicsVersion object - \param EmSize em size in units of SizeUnit - \param SizeUnit UnitType enumeration - \param FSFlags FontStyle flags - \param Length Number of Unicode Characters in FamilyName - \param Font Unicode (UTF-16LE) fontname - - EMF+ manual 2.2.1.3, Microsoft name: EmfPlusFont Object -*/ -U_PSEUDO_OBJ *U_PMF_FONT_set(uint32_t Version, U_FLOAT EmSize, uint32_t SizeUnit, - int32_t FSFlags, uint32_t Length, const uint16_t *Font){ - uint32_t cbFont = 2 * wchar16len(Font); /* this need not be 2*Length parameter */ - uint32_t pad = (0x3 & cbFont ? 2 : 0); - const U_SERIAL_DESC List[] = { - {&Version, 4, 1, U_LE}, - {&EmSize, 4, 1, U_LE}, - {&SizeUnit,4, 1, U_LE}, - {&FSFlags, 4, 1, U_LE}, - {NULL, 4, 1, U_LE}, /* NULL is for Reserved field */ - {&Length, 4, 1, U_LE}, - {Font, cbFont, 1, U_LE}, - {NULL, pad, (pad ? 1 : 0), (pad ? U_XE : U_XX)}, /* Entire record must be a multiple of 4 */ - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_FONT_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_IMAGE PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Version EmfPlusGraphicsVersion object - \param Id U_PSEUDO_OBJ containing one of the 2 types of image data - - EMF+ manual 2.2.1.4, Microsoft name: EmfPlusImage Object -*/ -U_PSEUDO_OBJ *U_PMF_IMAGE_set(uint32_t Version, const U_PSEUDO_OBJ *Id){ - if(!Id){ return(NULL); } - int32_t Type = U_OID_To_IDT(Id->Type); - if(Type<0){ return(NULL);} - const U_SERIAL_DESC List[] = { - {&Version, 4, 1, U_LE}, - {&Type, 4, 1, U_LE}, - {Id->Data, Id->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_IMAGE_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_IMAGEATTRIBUTES PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Version EmfPlusGraphicsVersion object - \param WrapMode WrapMode object - \param ClampColor EmfPlusARGB object - \param ObjectClamp ObjectClamp Identifiers - - EMF+ manual 2.2.1.5, Microsoft name: EmfPlusImageAttributes Object -*/ -U_PSEUDO_OBJ *U_PMF_IMAGEATTRIBUTES_set(uint32_t Version, uint32_t WrapMode, uint32_t ClampColor, uint32_t ObjectClamp){ - uint32_t Reserved=0; - const U_SERIAL_DESC List[] = { - {&Version, 4, 1, U_LE}, - {&Reserved, 4, 1, U_LE}, - {&WrapMode, 4, 1, U_LE}, - {&ClampColor, 4, 1, U_LE}, - {&ObjectClamp, 4, 1, U_LE}, - {&Reserved, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_IMAGEATTRIBUTES_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_PATH PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Version EmfPlusGraphicsVersion object - \param Points U_PSEUDO_OBJ containing array of points (of type PMFPointR, PMFPoint, or PMFPointF, determined by U_PPF_P and U_PPF_C bits in Flags) - \param Types U_PSEUDO_OBJ containing array of types (U_PMF_PATHPOINTTYPE or U_PMF_PATHPOINTTYPERLE, determined by U_PPF_R big in Flags) - - EMF+ manual 2.2.1.6, Microsoft name: EmfPlusPath Object -*/ -U_PSEUDO_OBJ *U_PMF_PATH_set(uint32_t Version, const U_PSEUDO_OBJ *Points, const U_PSEUDO_OBJ *Types){ - int ctype, RelAbs, rtype; - int pad; - if(Points){ - if( Points->Type == U_PMF_POINTR_OID){ RelAbs = 1; ctype = 0; } - else if(Points->Type == (U_PMF_POINT_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 1; } - else if(Points->Type == (U_PMF_POINTF_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 0; } - else { return(NULL); } - } - else { return(NULL); } - if(Types){ - if( Types->Type == (U_PMF_PATHPOINTTYPERLE_OID | U_PMF_ARRAY_OID)){ rtype = 1; } - else if(Types->Type == (U_PMF_PATHPOINTTYPE_OID | U_PMF_ARRAY_OID)){ rtype = 0; } - else { return(NULL); } - } - else { return(NULL); } - uint16_t Flags = (rtype ? U_PPF_R : 0) | (ctype ? U_PPF_C : 0)| (RelAbs ? U_PPF_P : 0); - pad = (0x3 & (Points->Used + Types->Used)); - if(pad){ pad = 4 - pad; } - const U_SERIAL_DESC List[] = { - {&Version, 4, 1, U_LE }, - {Points->Data, 4, 1, U_XE }, /* Elements from Points */ - {&Flags, 2, 1, U_LE }, - {NULL, 2, 1, U_LE }, /* Reserved field */ - {Points->Data + 4, Points->Used - 4, 1, U_XE }, /* omit Points Elements */ - {Types->Data +4, Types->Used - 4, 1, U_XE }, /* omit Types Elements */ - {NULL, pad, (pad ? 1 : 0), (pad ? U_XE : U_XX)}, /* if no padding is needed the Units will be zero and nothing will happen */ - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_PATH_OID, List); - return(po); -} - - -/** - \brief Create and set a U_PMF_PATH PseudoObject that uses U_PMF_POINTF coordinates - \return Pointer to PseudoObject, NULL on error - \param Version EmfPlusGraphicsVersion object - \param Path U_DPSEUDO_OBJ containing a path. - - EMF+ manual 2.2.1.6, Microsoft name: EmfPlusPath Object -*/ -U_PSEUDO_OBJ *U_PMF_PATH_set2(uint32_t Version, const U_DPSEUDO_OBJ *Path){ - if(!Path || !Path->Elements){ return(NULL); } - uint16_t Flags = 0; - int pad = (0x3 & Path->Elements); - if(pad){ pad = 4 - pad; } - const U_SERIAL_DESC List[] = { - {&Version, 4, 1, U_LE }, - {&Path->Elements, 4, 1, U_LE }, - {&Flags, 2, 1, U_LE }, - {NULL, 2, 1, U_LE }, /* Reserved field */ - {Path->poPoints->Data, 4, 2*Path->Elements,U_XE }, /* raw OID, so no leading Elements to omit */ - {Path->poTypes->Data, 1, Path->Elements, U_XE }, /* raw OID, so no leading Elements to omit */ - {NULL, pad, (pad ? 1 : 0), (pad ? U_XE : U_XX)}, /* if no padding is needed the Units will be zero and nothing will happen */ - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_PATH_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_PATH PseudoObject that uses U_PMF_POINT (int 16) coordinates - \return Pointer to PseudoObject, NULL on error - \param Version EmfPlusGraphicsVersion object - \param Path U_DPSEUDO_OBJ containing a path. - - EMF+ manual 2.2.1.6, Microsoft name: EmfPlusPath Object -*/ -U_PSEUDO_OBJ *U_PMF_PATH_set3(uint32_t Version, const U_DPSEUDO_OBJ *Path){ - if(!Path || !Path->Elements){return(NULL); } - uint16_t Flags = U_PPF_C; - int pad = (0x3 & Path->Elements); - if(pad){ pad = 4 - pad; } - U_PMF_POINT *Points16 = POINTF_To_POINT16_LE((U_PMF_POINTF *)Path->poPoints->Data, Path->Elements); - if(!Points16){ return(NULL); } - const U_SERIAL_DESC List[] = { - {&Version, 4, 1, U_LE }, - {&Path->Elements, 4, 1, U_LE }, - {&Flags, 2, 1, U_LE }, - {NULL, 2, 1, U_LE }, /* Reserved field */ - {Points16, 2, 2*Path->Elements,U_XE }, /* raw data, so no leading Elements to omit */ - {Path->poTypes->Data, 1, Path->Elements, U_XE }, /* raw data, so no leading Elements to omit */ - {NULL, pad, (pad ? 1 : 0), (pad ? U_XE : U_XX)}, /* if no padding is needed the Units will be zero and nothing will happen */ - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_PATH_OID, List); - free(Points16); - return(po); -} - -/** - \brief Create and set a U_PMF_PEN PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Version EmfPlusGraphicsVersion object - \param PenData U_PSEUDO_OBJ containing U_PMF_PENDATA object - \param Brush U_PSEUDO_OBJ containing U_PMF_BRUSH object - - EMF+ manual 2.2.1.7, Microsoft name: EmfPlusPen Object -*/ -U_PSEUDO_OBJ *U_PMF_PEN_set(uint32_t Version, const U_PSEUDO_OBJ *PenData, const U_PSEUDO_OBJ *Brush){ - if(!PenData || (PenData->Type != U_PMF_PENDATA_OID)){ return(NULL); } - if(!Brush || (Brush->Type != U_PMF_BRUSH_OID) ){ return(NULL); } - const U_SERIAL_DESC List[] = { - {&Version, 4, 1, U_LE}, - {NULL, 4, 1, U_LE}, - {PenData->Data, PenData->Used, 1, U_XE}, - {Brush->Data, Brush->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_PEN_OID, List); - return(po); -} - - -/** - \brief Create and set a U_PMF_REGION PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Version EmfPlusGraphicsVersion object - \param Count Number of CHILD nodes. This is one less than the total number of U_PMF_REGIONNODE objects in Nodes. - \param Nodes U_PSEUDO_OBJ containing U_PMF_REGIONNODE object (Nodes defining region, may be a single element or a binary tree) - - EMF+ manual 2.2.1.8, Microsoft name: EmfPlusRegion Object -*/ -U_PSEUDO_OBJ *U_PMF_REGION_set(uint32_t Version, uint32_t Count, const U_PSEUDO_OBJ *Nodes){ - if(!Nodes || Nodes->Type != U_PMF_REGIONNODE_OID)return(NULL); - const U_SERIAL_DESC List[] = { - {&Version, 4, 1, U_LE}, - {&Count, 4, 1, U_LE}, - {Nodes->Data, Nodes->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_REGION_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_STRINGFORMAT PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Sfs pointer to U_PMF_STRINGFORMAT structure, with no variable part - \param Sfd (optional) U_PSEUDO_OBJ containing U_PMF_STRINGFORMATDATA object - - EMF+ manual 2.2.1.9, Microsoft name: EmfPlusStringFormat Object -*/ -U_PSEUDO_OBJ *U_PMF_STRINGFORMAT_set(U_PMF_STRINGFORMAT *Sfs, const U_PSEUDO_OBJ *Sfd){ - if(!Sfs){ return(NULL); } - if(Sfd){ - if((!Sfs->TabStopCount && !Sfs->RangeCount) || (Sfd->Type != U_PMF_STRINGFORMATDATA_OID))return(NULL); - } - else { - if(Sfs->TabStopCount || Sfs->RangeCount)return(NULL); - } - const U_SERIAL_DESC List[] = { - {&Sfs->Version, 4, 1, U_LE}, - {&Sfs->Flags, 4, 1, U_LE}, - {&Sfs->Language, 4, 1, U_LE}, - {&Sfs->StringAlignment, 4, 1, U_LE}, - {&Sfs->LineAlign, 4, 1, U_LE}, - {&Sfs->DigitSubstitution, 4, 1, U_LE}, - {&Sfs->DigitLanguage, 4, 1, U_LE}, - {&Sfs->FirstTabOffset, 4, 1, U_LE}, - {&Sfs->HotkeyPrefix, 4, 1, U_LE}, - {&Sfs->LeadingMargin, 4, 1, U_LE}, - {&Sfs->TrailingMargin, 4, 1, U_LE}, - {&Sfs->Tracking, 4, 1, U_LE}, - {&Sfs->Trimming, 4, 1, U_LE}, - {&Sfs->TabStopCount, 4, 1, U_LE}, - {&Sfs->RangeCount, 4, 1, U_LE}, - {(Sfd ? Sfd->Data : NULL), (Sfd ? Sfd->Used : 0), 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_STRINGFORMAT_OID, List); - return(po); -} - -/** - \brief Create and set a PMF_4NUM PseudoObject (used for BrushID's) - \return Pointer to PseudoObject, NULL on error - \param BrushID U_PMF_BRUSH object in the EMF+ object table (0-63, inclusive) - -*/ -U_PSEUDO_OBJ *U_PMF_4NUM_set(uint32_t BrushID){ - if(BrushID>63){ return(NULL); } - const U_SERIAL_DESC List[] = { - {&BrushID, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_4NUM_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_ARGB PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Alpha Alpha (0-255) - \param Red Red color (0-255) - \param Green Green color (0-255) - \param Blue Blue color (0-255) - - EMF+ manual 2.2.2.1, Microsoft name: EmfPlusARGB Object -*/ -U_PSEUDO_OBJ *U_PMF_ARGB_set(uint8_t Alpha, uint8_t Red, uint8_t Green, uint8_t Blue){ - const U_SERIAL_DESC List[] = { - {&Blue, 1, 1, U_XE}, - {&Green, 1, 1, U_XE}, - {&Red, 1, 1, U_XE}, - {&Alpha, 1, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_ARGB_OID, List); - return(po); -} - -/** - \brief Create and set an Array of U_PMF_ARGB valus in a PseudoObject - \return Pointer to PseudoObject containing the count, followed by the array of colors, NULL on error - \param Count Number of entries in Colors - \param Colors Array of ARGB values - - EMF+ manual 2.2.2.1, Microsoft name: EmfPlusARGB Object -*/ -U_PSEUDO_OBJ *U_PMF_ARGBN_set(uint32_t Count, U_PMF_ARGB *Colors){ - const U_SERIAL_DESC List[] = { - {&Count, 4, 1, U_LE}, - {Colors, 4, Count, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_ARGB_OID | U_PMF_ARRAY_OID, List); - return(po); -} - -/** - \brief Set a U_PMF_ARGB object - \return Object - \param Alpha Alpha (0-255) - \param Red Red color (0-255) - \param Green Green color (0-255) - \param Blue Blue color (0-255) - - EMF+ manual 2.2.2.1, Microsoft name: EmfPlusARGB Object -*/ -U_PMF_ARGB U_PMF_ARGBOBJ_set(uint8_t Alpha, uint8_t Red, uint8_t Green, uint8_t Blue){ - U_PMF_ARGB argb; - char *ptr = (char *) &argb; - U_PMF_MEMCPY_DSTSHIFT(&ptr, &Blue, 1); - U_PMF_MEMCPY_DSTSHIFT(&ptr, &Green, 1); - U_PMF_MEMCPY_DSTSHIFT(&ptr, &Red, 1); - U_PMF_MEMCPY_DSTSHIFT(&ptr, &Alpha, 1); - return(argb); -} - -/** - \brief Create and set a U_PMF_BITMAP PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Bs pointer to U_PMF_BITMAP structure, with no variable part - \param Bm U_PSEUDO_OBJ containing an U_PMF_BITMAPDATA or U_PMF_COMPRESSEDIMAGE object - - EMF+ manual 2.2.2.2, Microsoft name: EmfPlusBitmap Object -*/ -U_PSEUDO_OBJ *U_PMF_BITMAP_set(const U_PMF_BITMAP *Bs, const U_PSEUDO_OBJ *Bm){ - if(!Bs)return(NULL); - if(Bm->Type != U_PMF_BITMAPDATA_OID && - Bm->Type != U_PMF_COMPRESSEDIMAGE_OID )return(NULL); - uint32_t Pad = UP4(Bm->Used) - Bm->Used; /* undocumented padding, must be present for at least PNG */ - const U_SERIAL_DESC List[] = { - {Bs, 4, 5, U_LE}, - {Bm->Data, Bm->Used, 1, U_XE}, - {NULL, (Pad ? Pad : 0), (Pad ? 1 : 0), U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_BITMAP_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_BITMAPDATA PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Ps (optional) U_PSEUDO_OBJ containing a U_PMF_PALETTE structure - \param cbBm Bytes in Bm - \param Bm An array of bytes, meaning depends on fields in U_PMF_BITMAP object and the PixelFormat enumeration. - - EMF+ manual 2.2.2.3, Microsoft name: EmfPlusBitmapData Object -*/ -U_PSEUDO_OBJ *U_PMF_BITMAPDATA_set( const U_PSEUDO_OBJ *Ps, int cbBm, const char *Bm){ - if(Ps && (Ps->Type != U_PMF_PALETTE_OID))return(NULL); - if(!Bm && cbBm)return(NULL); - const U_SERIAL_DESC List[] = { - {(Ps ? Ps->Data : NULL), (Ps ? Ps->Used : 0), (Ps ? 1 : 0), U_LE}, - {Bm, cbBm, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_BITMAPDATA_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_BLENDCOLORS PseudoObject - \return Pointer to PseudoObject, NULL on Positions and Colors - \param Elements number of elements in Positions, must agree with the number of Colors. - \param Positions positions along gradient line. The first position MUST be 0.0 and the last MUST be 1.0. - \param Colors U_PSEUDO_OBJ containing an array of U_PMF_ARGB objects: object colors at positions on gradient line - - EMF+ manual 2.2.2.4, Microsoft name: EmfPlusBlendColors Object -*/ -U_PSEUDO_OBJ *U_PMF_BLENDCOLORS_set(uint32_t Elements, const U_FLOAT *Positions, const U_PSEUDO_OBJ *Colors){ - if(!Colors || !Positions || Colors->Type != (U_PMF_ARGB_OID | U_PMF_ARRAY_OID)){ return(NULL); } - uint32_t CElements = (Colors->Used - 4)/4; - if(CElements != Elements){ return(NULL); } - const U_SERIAL_DESC List[] = { - {&CElements, 4, 1, U_LE}, - {Positions, 4, CElements, U_LE}, - {Colors->Data + 4, Colors->Used - 4, 1, U_XE}, /* omit Elements part of this PseudoObject */ - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_BLENDCOLORS_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_BLENDCOLORS PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Elements members in osition, inluding Start and End (0.0 - 1.0) - \param StartColor Start Color (U_PMF_ARGB) - \param EndColor End Color (U_PMF_ARGB) - - EMF+ manual 2.2.2.5, Microsoft name: EmfPlusBlendFactors Object - - - Positions always start at 0.0 and always end at 1.0. It is not well documented but other - start and end values generally do not work. -*/ -U_PSEUDO_OBJ *U_PMF_BLENDCOLORS_linear_set(uint32_t Elements, U_PMF_ARGB StartColor, U_PMF_ARGB EndColor){ - double dP,dR,dG,dB,dA,P,R,G,B,A; - U_FLOAT StartPos = 0.0; - U_FLOAT EndPos = 1.0; - U_FLOAT *Positions; - U_FLOAT *pP; - U_PMF_ARGB *Colors; - U_PMF_ARGB *pC; - unsigned int i; - if(Elements <= 2 ){ return(NULL); } - pP = Positions = (U_FLOAT *)malloc(Elements *sizeof(U_FLOAT)); - if(!Positions){ return(NULL); } - pC = Colors = (U_PMF_ARGB *)malloc(Elements *sizeof(U_PMF_ARGB)); - if(!Colors){ - free(Positions); - return(NULL); - } - dP = (EndPos - StartPos )/(float)(Elements - 1); - dB = ((double)EndColor.Blue - (double)StartColor.Blue )/(double)(Elements - 1); - dG = ((double)EndColor.Green - (double)StartColor.Green)/(double)(Elements - 1); - dR = ((double)EndColor.Red - (double)StartColor.Red )/(double)(Elements - 1); - dA = ((double)EndColor.Alpha - (double)StartColor.Alpha)/(double)(Elements - 1); - P = StartPos; - B = StartColor.Blue; - G = StartColor.Green; - R = StartColor.Red; - A = StartColor.Alpha; - for(i=0;i<Elements;i++,pC++,pP++){ /* hopefully the rounding errors are not a problem, used doubles to minimize that */ - *pP = P; - P += dP; - *pC = (U_PMF_ARGB){B,G,R,A}; - B += dB; - G += dG; - R += dR; - A += dA; - } - U_PSEUDO_OBJ *poColors = U_PMF_ARGBN_set(Elements, Colors); - U_PSEUDO_OBJ *po = U_PMF_BLENDCOLORS_set(Elements, Positions, poColors); - U_PO_free(&poColors); - free(Positions); - free(Colors); - return(po); -} - - -/** - \brief Create and set a U_PMF_BLENDFACTORS PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Elements members in each array - \param Positions positions along gradient line. The first position MUST be 0.0 and the last MUST be 1.0. - \param Factors blending factors, 0.0->1.0 values, inclusive - - EMF+ manual 2.2.2.5, Microsoft name: EmfPlusBlendFactors Object -*/ -U_PSEUDO_OBJ *U_PMF_BLENDFACTORS_set(uint32_t Elements, const U_FLOAT *Positions, const U_FLOAT *Factors){ - if(!Positions || !Factors)return(NULL); - const U_SERIAL_DESC List[] = { - {&Elements, 4, 1, U_LE}, - {Positions, 4, Elements, U_LE}, - {Factors, 4, Elements, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_BLENDFACTORS_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_BLENDFACTORS PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Elements members in osition, inluding Start and End (0.0 - 1.0) - \param StartFactor Start Factor (0.0 - 1.0) - \param EndFactor End Factor (0.0 - 1.0) - - EMF+ manual 2.2.2.5, Microsoft name: EmfPlusBlendFactors Object - - - Positions always start at 0.0 and always end at 1.0. It is not well documented but other - start and end values generally do not work. -*/ -U_PSEUDO_OBJ *U_PMF_BLENDFACTORS_linear_set(uint32_t Elements, U_FLOAT StartFactor, U_FLOAT EndFactor){ - double dP,dF,P,F; - U_FLOAT StartPos = 0.0; - U_FLOAT EndPos = 1.0; - U_FLOAT *Positions; - U_FLOAT *Factors; - U_FLOAT *pP; - U_FLOAT *pF; - unsigned int i; - if(Elements <= 2 ){ return(NULL); } - pP = Positions = (U_FLOAT *)malloc(Elements *sizeof(U_FLOAT)); - if(!Positions){ return(NULL); } - pF = Factors = (U_FLOAT *)malloc(Elements *sizeof(U_FLOAT)); - if(!Factors){ - free(Positions); - return(NULL); - } - dP = (EndPos - StartPos )/(float)(Elements - 1); - dF = (EndFactor - StartFactor)/(float)(Elements - 1); - P = StartPos; - F = StartFactor; - for(i=0;i<Elements;i++){ /* hopefully the rounding errors are not a problem, used doubles to minimize that */ - *pP++ = P; P += dP; - *pF++ = F; F += dF; - } - U_PSEUDO_OBJ *po = U_PMF_BLENDFACTORS_set(Elements, Positions, Factors); - free(Positions); - free(Factors); - return(po); -} - -/** - \brief Create and set a U_PMF_BOUNDARYPATHDATA PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Path U_PSEUDO_OBJ containing U_PMF_PATH object - - EMF+ manual 2.2.2.6, Microsoft name: EmfPlusBoundaryPathData Object -*/ -U_PSEUDO_OBJ *U_PMF_BOUNDARYPATHDATA_set(const U_PSEUDO_OBJ *Path){ - if(!Path || Path->Type != U_PMF_PATH_OID)return(NULL); - /* PO Used is size_t, might be 8 bytes, value in record must be 4 bytes */ - uint32_t Used = Path->Used; - const U_SERIAL_DESC List[] = { - {&Used, 4, 1, U_LE}, - {Path->Data, Path->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_BOUNDARYPATHDATA_OID, List); - return(po); -} - - -/** - \brief Create and set a U_PMF_BOUNDARYPOINTDATA PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Elements members in each array - \param Points array of U_PMF_POINTF - - EMF+ manual 2.2.2.7, Microsoft name: EmfPlusBoundaryPointData Object -*/ -U_PSEUDO_OBJ *U_PMF_BOUNDARYPOINTDATA_set(uint32_t Elements, const U_PMF_POINTF *Points){ - if(!Points)return(NULL); - const U_SERIAL_DESC List[] = { - {&Elements, 4, 1, U_LE}, - {Points, 4, 2*Elements,U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_BOUNDARYPOINTDATA_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_CHARACTERRANGE PseudoObject - \return Pointer to PseudoObject, NULL on error - \param First First position in range - \param Length Range length - - EMF+ manual 2.2.2.8, Microsoft name: EmfPlusCharacterRange Object -*/ -U_PSEUDO_OBJ *U_PMF_CHARACTERRANGE_set(int32_t First, int32_t Length){ - const U_SERIAL_DESC List[] = { - {&First, 4, 1, U_LE}, - {&Length, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_CHARACTERRANGE_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_COMPOUNDLINEDATA PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Elements Members in Widths - \param Widths Array of U_FLOAT Line or gap widths (0.0 <-> 1.0, fraction of total line width ) - - EMF+ manual 2.2.2.9, Microsoft name: EmfPlusCompoundLineData Object -*/ -U_PSEUDO_OBJ *U_PMF_COMPOUNDLINEDATA_set(int32_t Elements, const char *Widths){ - if(!Widths)return(NULL); - const U_SERIAL_DESC List[] = { - {&Elements ,4, 1, U_LE}, - {Widths, 4, Elements,U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_COMPOUNDLINEDATA_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_COMPRESSEDIMAGE PseudoObject - \return Pointer to PseudoObject, NULL on error - \param cbImage Bytes in Image - \param Image Stored image in one of the supported formats (GIF, PNG, etc.). - - EMF+ manual 2.2.2.10, Microsoft name: EmfPlusCompressedImage Object -*/ -U_PSEUDO_OBJ *U_PMF_COMPRESSEDIMAGE_set(int32_t cbImage, const char *Image){ - if(!cbImage || !Image)return(NULL); - const U_SERIAL_DESC List[] = { - {Image, cbImage, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_COMPRESSEDIMAGE_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_CUSTOMENDCAPDATA PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Clc U_PSEUDO_OBJ containing a U_PMF_CUSTOMLINECAP object - - EMF+ manual 2.2.2.11, Microsoft name: EmfPlusCustomEndCapData Object -*/ -U_PSEUDO_OBJ *U_PMF_CUSTOMENDCAPDATA_set(const U_PSEUDO_OBJ *Clc){ - if(!Clc || Clc->Type != U_PMF_CUSTOMLINECAP_OID)return(NULL); - /* PO Used is size_t, might be 8 bytes, value in record must be 4 bytes */ - uint32_t Used = Clc->Used; - const U_SERIAL_DESC List[] = { - {&Used, 4, 1, U_LE}, - {Clc->Data, Clc->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_CUSTOMENDCAPDATA_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_CUSTOMLINECAPARROWDATA PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Width Arrow cap width (is multiplied by line width before draw) - \param Height Arrow cap length (is multiplied by line width before draw) - \param MiddleInset Pixels between outer edge and filled region - \param FillState If set, fill, otherwise, only border - \param StartCap LineCap enumeration (type of cap) - \param EndCap LineCap enumeration - \param Join LineJoin enumeration - \param MiterLimit Maximum (miter length / line width) - \param WidthScale Scale for U_PMF_CUSTOMLINECAP object - - EMF+ manual 2.2.2.12, Microsoft name: EmfPlusCustomLineCapArrowData Object -*/ -U_PSEUDO_OBJ *U_PMF_CUSTOMLINECAPARROWDATA_set(U_FLOAT Width, U_FLOAT Height, - U_FLOAT MiddleInset, uint32_t FillState, uint32_t StartCap, uint32_t EndCap, uint32_t Join, - U_FLOAT MiterLimit, U_FLOAT WidthScale - ){ - const U_SERIAL_DESC List[] = { - {&Width, 4, 1, U_LE}, - {&Height ,4, 1, U_LE}, - {&MiddleInset, 4, 1, U_LE}, - {&FillState, 4, 1, U_LE}, - {&StartCap, 4, 1, U_LE}, - {&EndCap, 4, 1, U_LE}, - {&Join, 4, 1, U_LE}, - {&MiterLimit, 4, 1, U_LE}, - {&WidthScale, 4, 1, U_LE}, - {NULL, 8, 2, U_LE}, /* FillHotSpots and LineHotSpots */ - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_CUSTOMLINECAPARROWDATA_OID, List); - return(po); -} - - -/** - \brief Create and set a U_PMF_CUSTOMLINECAPDATA PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Flags CustomLineCapData flags - \param Cap LineCap enumeration (type of cap) - \param Inset Distance line cap start -> line end - \param StartCap LineCap enumeration - \param EndCap LineCap enumeration - \param Join LineJoin enumeration - \param MiterLimit Maximum (miter length / line width) - \param WidthScale Scale for U_PMF_CUSTOMLINECAP object - \param Clcod U_PSEUDO_OBJ containing a U_PMF_CUSTOMLINECAPOPTIONALDATA object - - EMF+ manual 2.2.2.13, Microsoft name: EmfPlusCustomLineCapData Object -*/ -U_PSEUDO_OBJ *U_PMF_CUSTOMLINECAPDATA_set(uint32_t Flags, uint32_t Cap, - U_FLOAT Inset, uint32_t StartCap, uint32_t EndCap, - uint32_t Join, U_FLOAT MiterLimit, U_FLOAT WidthScale, - const U_PSEUDO_OBJ *Clcod - ){ - if(!Clcod || Clcod->Type != U_PMF_CUSTOMLINECAPOPTIONALDATA_OID)return(NULL); - const U_SERIAL_DESC List[] = { - {&Flags, 4, 1, U_LE}, - {&Cap, 4, 1, U_LE}, - {&Inset, 4, 1, U_LE}, - {&StartCap, 4, 1, U_LE}, - {&EndCap, 4, 1, U_LE}, - {&Join, 4, 1, U_LE}, - {&MiterLimit, 4, 1, U_LE}, - {&WidthScale, 4, 1, U_LE}, - {NULL, 8, 2, U_LE}, /* FillHotSpots and LineHotSpots */ - {Clcod->Data, Clcod->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_CUSTOMLINECAPDATA_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_CUSTOMLINECAPOPTIONALDATA PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Fill U_PSEUDO_OBJ containing a U_PMF_FILLPATHOBJ object (optional) - \param Line U_PSEUDO_OBJ containing a U_PMF_LINEPATH object (optional) - - EMF+ manual 2.2.2.14, Microsoft name: EmfPlusCustomLineCapOptionalData Object -*/ -U_PSEUDO_OBJ *U_PMF_CUSTOMLINECAPOPTIONALDATA_set(const U_PSEUDO_OBJ *Fill, const U_PSEUDO_OBJ *Line){ - if(Fill && (Fill->Type != U_PMF_FILLPATHOBJ_OID))return(NULL); - if(Line && (Line->Type != U_PMF_LINEPATH_OID))return(NULL); - const U_SERIAL_DESC List[] = { - {(Fill ? Fill->Data : NULL), (Fill ? Fill->Used : 0), 1, U_XE}, - {(Line ? Line->Data : NULL), (Line ? Line->Used : 0), 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_CUSTOMLINECAPOPTIONALDATA_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_CUSTOMSTARTCAPDATA PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Clc U_PSEUDO_OBJ containing a U_PMF_CUSTOMLINECAPDATA object - - EMF+ manual 2.2.2.15, Microsoft name: EmfPlusCustomStartCapData Object -*/ -U_PSEUDO_OBJ *U_PMF_CUSTOMSTARTCAPDATA_set(const U_PSEUDO_OBJ *Clc){ - if(!Clc || Clc->Type != U_PMF_CUSTOMLINECAP_OID)return(NULL); - const U_SERIAL_DESC List[] = { - {Clc->Data, Clc->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_CUSTOMSTARTCAPDATA_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_DASHEDLINEDATA PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Elements Members in Lengths - \param Lengths Array of U_FLOAT holding lengths of dashes and spaces. - - EMF+ manual 2.2.2.16, Microsoft name: EmfPlusDashedLineData Object -*/ -U_PSEUDO_OBJ *U_PMF_DASHEDLINEDATA_set(int32_t Elements, const U_FLOAT *Lengths){ - if(!Lengths)return(NULL); - const U_SERIAL_DESC List[] = { - {&Elements, 4, 1, U_LE}, - {Lengths, 4, Elements, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_DASHEDLINEDATA_OID, List); - return(po); -} - -/** - \brief Utility function to create and set a U_PMF_DASHEDLINEDATA PseudoObject from one of a predefined set of patterns - \return Pointer to PseudoObject, NULL on error - \param Unit Length of the repeat unit - \param StdPat Members in Lengths - - EMF+ manual 2.2.2.16, Microsoft name: EmfPlusDashedLineData Object -*/ -U_PSEUDO_OBJ *U_PMF_DASHEDLINEDATA_set2(U_FLOAT Unit, int StdPat){ - uint32_t Elements; - uint8_t *p; - U_FLOAT SubUnit; - U_FLOAT Lengths[8]; /* This is the most dash/spaces that will be needed*/ - int i; - /* Dot = 1, Dash = 2; Long = 3, 0 = terminate pattern */ - uint8_t SB[U_DD_Types][5] = - { - {0,0,0,0,0}, // Solid - {2,0,0,0,0}, // Dash - {2,2,0,0,0}, // DashDash - {2,2,2,0,0}, // DashDashDash - {2,2,2,2,0}, // DashDashDashDash - {1,0,0,0,0}, // Dot - {1,1,0,0,0}, // DotDot - {1,1,1,0,0}, // DotDotDot - {1,1,1,1,0}, // DotDotDotDot - {2,1,0,0,0}, // DashDot - {2,2,1,0,0}, // DashDashDot - {2,2,1,1,0}, // DashDashDotDot - {2,2,2,1,0}, // DashDashDashDot - {2,1,1,0,0}, // DashDotDot - {2,1,1,1,0}, // DashDotDotDot - {2,1,2,1,0}, // DashDotDashDot - {3,0,0,0,0}, // Long - {3,3,0,0,0}, // LongLong - {3,3,3,0,0}, // LongLongLong - {3,3,3,3,0}, // LongLongLongLong - {3,1,0,0,0}, // LongDot - {3,3,1,0,0}, // LongLongDot - {3,3,1,1,0}, // LongLongDotDot - {3,3,3,1,0}, // LongLongLongDot - {3,1,1,0,0}, // LongDotDot - {3,1,1,1,0}, // LongDotDotDot - {3,1,3,1,0} // LongDotLongDot - }; - if(Unit <= 0 ){ return(NULL); } - if((StdPat <= 0) || (StdPat > U_DD_LongDotLongDot)){ return(NULL); } - p = &(SB[StdPat][0]); - for(Elements = 0; *p; p++, Elements++){} - SubUnit = Unit/((U_FLOAT) Elements); - Elements *= 2; - p = &(SB[StdPat][0]); - for(i=0; *p; p++){ - switch(*p){ - case 0: break; - case 1: /* dot */ - Lengths[i++] = SubUnit * 0.125; - Lengths[i++] = SubUnit * 0.875; - break; - case 2: /* dash */ - Lengths[i++] = SubUnit * 0.5; - Lengths[i++] = SubUnit * 0.5; - break; - case 3: /* long */ - Lengths[i++] = SubUnit * 0.75; - Lengths[i++] = SubUnit * 0.25; - break; - } - } - - U_PSEUDO_OBJ *po = U_PMF_DASHEDLINEDATA_set(Elements, Lengths); - return(po); -} - -/** - \brief Utility function to create and set a U_PMF_DASHEDLINEDATA PseudoObject from the bits that are set in a uint32_t - \return Pointer to PseudoObject, NULL on error - \param Unit Length of the repeat unit - \param BitPat uint32_t holding the bit pattern, the lowest order bit MUST be set and the highest order MUST be clear. - - Make a line with a dot/dash pattern defined by the bits in the BitPat value. If a bit is set it is drawn, - if clear it is not. Every bit drawn has length Unit/32, and consecutive drawn bits are merged together. - The lowest order bit is the first bit that may be drawn, the highest the last. - - Example: if the integer has value 0x13 the pattern produced will be: - 0 -> 2*unit/32 drawn - 2*unit/32 -> 5*unit/32 not drawn - 5*unit/32 -> 6*unit/32 drawn - 6*unit/32 -> unit not drawn - - EMF+ manual 2.2.2.16, Microsoft name: EmfPlusDashedLineData Object -*/ -U_PSEUDO_OBJ *U_PMF_DASHEDLINEDATA_set3(U_FLOAT Unit, uint32_t BitPat){ - uint32_t Elements=0; - U_FLOAT SubUnit = Unit/32.0; - U_FLOAT Lengths[32]; /* This is the most dash/spaces that will be needed*/ - if(!(0x00000001 & BitPat))return(NULL); /* Pattern must start with a drawn segment, this bit must be set */ - if( 0x80000000 & BitPat )return(NULL); /* Pattern must end with an undrawn segment, this bit must be clear */ - int i=0; - int k; - int lastType=1; - int newType=0; - uint32_t j=1; - Lengths[0]=0; - for(k=0; k<32; k++, j=j<<1){ - if(j & BitPat){ - if(!lastType){ - newType=1; - } - } - else { - if(lastType){ - newType=1; - } - } - if(newType){ - i++; - Lengths[i]=0; - Elements++; - lastType = !lastType; - newType = 0; - } - Lengths[i] += SubUnit; - } - Elements = i+1; - - U_PSEUDO_OBJ *po = U_PMF_DASHEDLINEDATA_set(Elements, Lengths); - return(po); -} - -/** - \brief Create and set a U_PMF_FILLPATHOBJ PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Path U_PSEUDO_OBJ containing a U_PMF_PATH object - - EMF+ manual 2.2.2.17, Microsoft name: EmfPlusFillPath Object -*/ -U_PSEUDO_OBJ *U_PMF_FILLPATHOBJ_set(const U_PSEUDO_OBJ *Path){ - if(!Path || (Path->Type != U_PMF_PATH_OID))return(NULL); - const U_SERIAL_DESC List[] = { - {Path->Data, Path->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_FILLPATHOBJ_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_FOCUSSCALEDATA PseudoObject - \return Pointer to PseudoObject, NULL on error - \param ScaleX value 0.0 <-> 1.0 - \param ScaleY value 0.0 <-> 1.0 - - EMF+ manual 2.2.2.18, Microsoft name: EmfPlusFocusScaleData Object -*/ -U_PSEUDO_OBJ *U_PMF_FOCUSSCALEDATA_set(U_FLOAT ScaleX, U_FLOAT ScaleY){ - uint32_t tmp = 2; - const U_SERIAL_DESC List[] = { - {&tmp, 4, 1, U_LE}, - {&ScaleX, 4, 1, U_LE}, - {&ScaleY, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_FOCUSSCALEDATA_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_GRAPHICSVERSION object (Signature always set to 0xDBC01) - \return Pointer to PseudoObject, NULL on error - \param GrfVersion GraphicsVersion enumeration - - EMF+ manual 2.2.2.19, Microsoft name: EmfPlusGraphicsVersion Object -*/ -U_PSEUDO_OBJ *U_PMF_GRAPHICSVERSION_set(int GrfVersion){ - uint32_t tmp; - tmp = U_GFVR_PMF << 12; /* signature, can only have this value */ - tmp |= (GrfVersion & U_GFVR_MASKLO); - const U_SERIAL_DESC List[] = { - {&tmp, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_GRAPHICSVERSION_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_GRAPHICSVERSION object Structure (Signature always set to 0xDBC01) - \return U_PMF_GRAPHICSVERSION - \param GrfVersion GraphicsVersion enumeration - - EMF+ manual 2.2.2.19, Microsoft name: EmfPlusGraphicsVersion Object -*/ -U_PMF_GRAPHICSVERSION U_PMF_GRAPHICSVERSIONOBJ_set(int GrfVersion){ - uint32_t tmp; - tmp = U_GFVR_PMF << 12; /* signature, can only have this value */ - tmp |= (GrfVersion & U_GFVR_MASKLO); - return(tmp); -} - - -/** - \brief Create and set a U_PMF_HATCHBRUSHDATA PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Style HatchStyle enumeration - \param Fg U_PSEUDO_OBJ containing a U_ARGB object, Foreground hatch pattern line color - \param Bg U_PSEUDO_OBJ containing a U_ARGB object, Background hatch pattern line color - - EMF+ manual 2.2.2.20, Microsoft name: EmfPlusHatchBrushData Object -*/ -U_PSEUDO_OBJ *U_PMF_HATCHBRUSHDATA_set(uint32_t Style, const U_PSEUDO_OBJ *Fg, const U_PSEUDO_OBJ *Bg){ - if(!Fg ||(Fg->Type != U_PMF_ARGB_OID))return(NULL); - if(!Bg ||(Bg->Type != U_PMF_ARGB_OID))return(NULL); - const U_SERIAL_DESC List[] = { - {&Style, 4, 1, U_LE}, - {Fg->Data, Fg->Used, 1, U_XE}, - {Bg->Data, Bg->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_HATCHBRUSHDATA_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_INTEGER7 PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Value 7 bit signed integer (stored in an integer, range 63 <-> -64, inclusive) - - EMF+ manual 2.2.2.21, Microsoft name: EmfPlusInteger7 Object -*/ -U_PSEUDO_OBJ *U_PMF_INTEGER7_set(int Value){ - uint8_t utmp; - if(Value < -64 || Value > 63)return(NULL); - utmp = U_MASK_INT7 & *(unsigned int *)&Value; - U_PSEUDO_OBJ *po = U_PO_create((char *)&utmp, 1, 1, U_PMF_INTEGER7_OID); /* simple method is OK, no possibility of Endian issues */ - return(po); -} - -/** - \brief Create and set a U_PMF_INTEGER15 PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Value 15 bit signed integer (stored in an integer, range 32677 <-> -32678, inclusive) - - EMF+ manual 2.2.2.22, Microsoft name: EmfPlusInteger15 Object -*/ -U_PSEUDO_OBJ *U_PMF_INTEGER15_set(int Value){ - uint16_t utmp; - if(Value < -32678 || Value > 32677)return(NULL); - utmp = U_TEST_INT15 | (U_MASK_INT15 & *(unsigned int *)&Value); - const U_SERIAL_DESC List[] = { - {&utmp, 2, 1, U_BE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_INTEGER15_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_LANGUAGEIDENTIFIER value in 4 byte unsigned int, in NATIVE byte order - \return LID value in least significant two bytes and 0 in most significant two bytes. - \param SubLId Example: code for USA - \param PriLId Example: code for English - - EMF+ manual 2.2.2.23, Microsoft name: EmfPlusLanguageIdentifier Object -*/ -U_PMF_LANGUAGEIDENTIFIER U_PMF_LANGUAGEIDENTIFIEROBJ_set(int SubLId, int PriLId){ - U_PMF_LANGUAGEIDENTIFIER utmp32; - utmp32 = ((SubLId & U_FF_MASK_SUBLID) << U_FF_SHFT_SUBLID) | ((PriLId & U_FF_MASK_PRILID) << U_FF_SHFT_PRILID); - return(utmp32); -} - -/** - \brief Create and set a U_PMF_LANGUAGEIDENTIFIER PseudoObject - \return Pointer to PseudoObject, NULL on error - \param LId Language Identifier as produced by U_PMF_LANGUAGEIDENTIFIEROBJ_set(). - - EMF+ manual 2.2.2.23, Microsoft name: EmfPlusLanguageIdentifier Object -*/ -U_PSEUDO_OBJ *U_PMF_LANGUAGEIDENTIFIER_set(U_PMF_LANGUAGEIDENTIFIER LId){ - uint16_t utmp16; - utmp16 = (LId & U_FF_MASK_LID) << U_FF_SHFT_LID; - const U_SERIAL_DESC List[] = { - {&utmp16, 2, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_LANGUAGEIDENTIFIER_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_LINEARGRADIENTBRUSHDATA PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Lgbd U_PMF_LINEARGRADIENTBRUSHDATA object (constant part) - \param Lgbod U_PSEUDO_OBJ containing a U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA object (variable part of a U_PMF_LINEARGRADIENTBRUSHDATA object) - - - EMF+ manual 2.2.2.24, Microsoft name: EmfPlusLinearGradientBrushData Object -*/ -U_PSEUDO_OBJ *U_PMF_LINEARGRADIENTBRUSHDATA_set(const U_PMF_LINEARGRADIENTBRUSHDATA *Lgbd, const U_PSEUDO_OBJ *Lgbod){ - if(!Lgbd || !Lgbod || (Lgbod->Type != U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA_OID))return(NULL); - const U_SERIAL_DESC List[] = { - {Lgbd, 4, 6, U_LE}, - {&(Lgbd->StartColor), 4, 2, U_XE}, - {&(Lgbd->StartColor), 4, 2, U_XE}, /* repeat the start/end colors. Supposedly reserved. */ -// {NULL, 4, 2, U_LE}, /* zero fill the two Reserved fields, no matter what is passed in */ - {(Lgbod->Used ? Lgbod->Data : NULL), Lgbod->Used, 1, U_XE}, /* optional Data can exist and Used can be zero, SERIAL_set would throw an error on that */ - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_LINEARGRADIENTBRUSHDATA_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Flags Bits are set that indicate which of the following were included. The caller must clear before passing it in. - \param Tm (optional) U_PSEUDO_OBJ containing a U_PMF_TRANSFORMMATRIX object - \param Bc (optional) U_PSEUDO_OBJ containing a U_PMF_BLENDCOLORS object or NULL - \param BfH (optional) U_PSEUDO_OBJ containing a U_PMF_BLENDFACTORS (H) object or NULL - \param BfV (optional) U_PSEUDO_OBJ containing a U_PMF_BLENDFACTORS (V) object or NULL (WARNING, GDI+ defines this field but does not render it. DO NOT USE.) - - - EMF+ manual 2.2.2.25, Microsoft name: EmfPlusLinearGradientBrushOptionalData Object - - - The rectangular gradients repeat in a tiled pattern. Tm can rotate and offset the gradient within each tile. - The gradient wraps when it is offset. - -*/ -U_PSEUDO_OBJ *U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA_set(uint32_t *Flags, const U_PSEUDO_OBJ *Tm, - const U_PSEUDO_OBJ *Bc, const U_PSEUDO_OBJ *BfH, const U_PSEUDO_OBJ *BfV){ - if(!Flags )return(NULL); - if(Tm && (Tm->Type != U_PMF_TRANSFORMMATRIX_OID))return(NULL); - if(Bc && (Bc->Type != U_PMF_BLENDCOLORS_OID) )return(NULL); - if(BfH && (BfH->Type != U_PMF_BLENDFACTORS_OID) )return(NULL); - if(BfV && (BfV->Type != U_PMF_BLENDFACTORS_OID) )return(NULL); - if(Bc && (BfH || BfV) )return(NULL); - const U_SERIAL_DESC List[] = { - {(Tm ? Tm->Data : NULL), (Tm ? Tm->Used : 0), 1, U_XE}, - {(Bc ? Bc->Data : NULL), (Bc ? Bc->Used : 0), 1, U_XE}, - {(BfH ? BfH->Data : NULL), (BfH ? BfH->Used : 0), 1, U_XE}, - {(BfV ? BfV->Data : NULL), (BfV ? BfV->Used : 0), 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA_OID, List); - if(Tm ){ *Flags |= U_BD_Transform; } - if(Bc ){ *Flags |= U_BD_PresetColors; } - if(BfH){ *Flags |= U_BD_BlendFactorsH; } - if(BfV){ *Flags |= U_BD_BlendFactorsV; } - return(po); -} - -/** - \brief Create and set a U_PMF_LINEPATH PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Path U_PSEUDO_OBJ containing a U_PMF_PATH object - - - EMF+ manual 2.2.2.26, Microsoft name: EmfPlusLinePath Object -*/ -U_PSEUDO_OBJ *U_PMF_LINEPATH_set(const U_PSEUDO_OBJ *Path){ - if(!Path || (Path->Type != U_PMF_PATH_OID))return(NULL); - const U_SERIAL_DESC List[] = { - {&Path->Data, Path->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_LINEPATH_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_METAFILE object (NOT SUPPORTED!) - \return Null - - - EMF+ manual 2.2.2.27, Microsoft name: EmfPlusMetafile Object -*/ -U_PSEUDO_OBJ *U_PMF_METAFILE_set(void){ - return(NULL); -} - -/** - \brief Create and set a U_PMF_PALETTE PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Flags PaletteStyle flags - \param Elements Members in Lengths - \param Pd Array of U_PMF_ARGB holding colors of palettes. (Palette Data) - - EMF+ manual 2.2.2.28, Microsoft name: EmfPlusPalette Object -*/ -U_PSEUDO_OBJ *U_PMF_PALETTE_set(uint32_t Flags, uint32_t Elements, const U_PMF_ARGB *Pd){ - if(!Pd)return(NULL); - const U_SERIAL_DESC List[] = { - {&Flags, 4, 1, U_LE}, - {&Elements, 4, 1, U_LE}, - {Pd, 4, Elements, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_PALETTE_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_PATHGRADIENTBRUSHDATA PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Flags PaletteStyle flags - \param WrapMode WrapMode enumeration - \param CenterColor U_PMF_ARGB Center color - \param Center Center coordinates - \param Gradient U_PSEUDO_OBJ containing an Array of U_PMF_ARGB holding colors of Gradient - \param Boundary U_PSEUDO_OBJ containing a U_PMF_BOUNDARYPATHDATA or U_PMF_BOUNDARYPOINTDATA object. (Boundary Data) - \param Data variable part of U_PMF_LINEARGRADIENTBRUSHDATA, exact composition depends on Flags - - EMF+ manual 2.2.2.29, Microsoft name: EmfPlusPathGradientBrushData Object -*/ -U_PSEUDO_OBJ *U_PMF_PATHGRADIENTBRUSHDATA_set(uint32_t Flags, int32_t WrapMode, U_PMF_ARGB CenterColor, - U_PMF_POINTF Center, - const U_PSEUDO_OBJ *Gradient, const U_PSEUDO_OBJ *Boundary, const U_PSEUDO_OBJ *Data){ - if( (Flags & U_BD_Path) && (!Boundary || (Boundary->Type != U_PMF_BOUNDARYPATHDATA_OID)))return(NULL); - if(!(Flags & U_BD_Path) && (!Boundary || (Boundary->Type != U_PMF_BOUNDARYPOINTDATA_OID)))return(NULL); - if(!Gradient || (Gradient->Type != (U_PMF_ARGB_OID | U_PMF_ARRAY_OID)))return(NULL); - if(!(Flags & U_BD_Transform) && - !(Flags & U_BD_PresetColors) && - !(Flags & U_BD_BlendFactorsH) && - !(Flags & U_BD_FocusScales) && - (!Data || (Data->Type != U_PMF_PATHGRADIENTBRUSHOPTIONALDATA_OID)))return(NULL); - - const U_SERIAL_DESC List[] = { - {&Flags, 4, 1, U_LE}, - {&WrapMode, 4, 1, U_LE}, - {&CenterColor, 4, 1, U_XE}, - {&Center.X, 4, 2, U_LE}, - {Gradient->Data, Gradient->Used, 1, U_XE}, /* includes Elements */ - {Boundary->Data, Boundary->Used, 1, U_XE}, - {(Data ? Data->Data : NULL), (Data ? Data->Used : 0), 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_PATHGRADIENTBRUSHDATA_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_PATHGRADIENTBRUSHOPTIONALDATA PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Flags PaletteStyle flags - \param Tm U_PSEUDO_OBJ containing a U_PMF_TRANSFORMMATRIX. (Transformation matrix) - \param Pd U_PSEUDO_OBJ containing a U_PMF_BLENDCOLORS or U_PMF_BLENDFACTORS object. (Pattern Data) - \param Fsd U_PSEUDO_OBJ containing a U_PMF_FOCUSSSCALEDATA object. (Focus Scale Data) - - EMF+ manual 2.2.2.30, Microsoft name: EmfPlusPathGradientBrushOptionalData Object -*/ -U_PSEUDO_OBJ *U_PMF_PATHGRADIENTBRUSHOPTIONALDATA_set(uint32_t Flags, - const U_PSEUDO_OBJ *Tm, const U_PSEUDO_OBJ *Pd, const U_PSEUDO_OBJ *Fsd){ - if(Tm && (Tm->Type != U_PMF_TRANSFORMMATRIX_OID))return(NULL); - if(Pd && !(Flags & (U_BD_PresetColors | U_BD_BlendFactorsH)))return(NULL); - if( (Flags & U_BD_PresetColors) && ((Flags & U_BD_BlendFactorsH) || !Pd || (Pd->Type != U_PMF_BLENDCOLORS_OID) ))return(NULL); - if( (Flags & U_BD_BlendFactorsH) && ((Flags & U_BD_PresetColors) || !Pd || (Pd->Type != U_PMF_BLENDFACTORS_OID)))return(NULL); - if(Fsd && !(Flags & U_BD_FocusScales))return(NULL); - if( (Flags & U_BD_FocusScales) && (!Fsd || (Fsd->Type != U_PMF_BLENDCOLORS_OID) ))return(NULL); - const U_SERIAL_DESC List[] = { - {(Tm ? Tm->Data : NULL), (Tm ? Tm->Used : 0), 1, U_XE}, - {(Pd ? Pd->Data : NULL), (Pd ? Pd->Used : 0), 1, U_XE}, - {(Fsd ? Fsd->Data : NULL), (Fsd ? Fsd->Used : 0), 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_PATHGRADIENTBRUSHOPTIONALDATA_OID, List); - return(po); -} - -/** - \brief Create and set an ARRAY of U_PMF_PATHPOINTTYPE objects - \return Pointer to PseudoObject, NULL on error - \param Elements Number of entries in Flags and Enumerations - \param Ppt Array of unsigned bytes, lower 4 bits hold the PathPointType flag upper 4 bits hold the PathPointType enumeration. - - EMF+ manual 2.2.2.31, Microsoft name: EmfPlusPathPointType Object -*/ -U_PSEUDO_OBJ *U_PMF_PATHPOINTTYPE_set(uint32_t Elements, const uint8_t *Ppt){ - if(!Elements || !Ppt)return(NULL); - const U_SERIAL_DESC List[] = { - {&Elements, 4, 1, U_LE}, - {Ppt, 1, Elements, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_PATHPOINTTYPE_OID | U_PMF_ARRAY_OID, List); - return(po); -} - -/** - \brief Create and set an ARRAY of U_PMF_PATHPOINTTYPE objects, with a preceding Elements count - \return Pointer to PseudoObject, NULL on error - \param Elements Number of elements to add. First is added once and Others Elements-1 times. - \param First Apply to first point, unsigned byte, lower 4 bits hold the PathPointType flag upper 4 bits hold the PathPointType enumeration. - \param Others Apply to all other points, unsigned byte, lower 4 bits hold the PathPointType flag upper 4 bits hold the PathPointType enumeration. - - EMF+ manual 2.2.2.31, Microsoft name: EmfPlusPathPointType Object -*/ -U_PSEUDO_OBJ *U_PMF_PATHPOINTTYPE_set2(uint32_t Elements, uint8_t First, uint8_t Others){ - if(!Elements)return(NULL); - const U_SERIAL_DESC List[] = { - {&Elements, 4, 1, U_XE}, - {&First, 1, 1, U_XE}, - {&Others, 1, Elements-1, U_RP}, /* replicate the one value N-1 times */ - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_PATHPOINTTYPE_OID | U_PMF_ARRAY_OID, List); - return(po); -} - -/** - \brief Create and set an ARRAY of U_PMF_PATHPOINTTYPERLE objects - \return Pointer to PseudoObject containing first the number of elements, then an array of U_PMF_PATHPOINTTYPERLE, NULL on error - \param Elements Number of entries in the arrays - \param Bz Array of unsigned bytes, if not zero, element has Bezier bit set - \param RL Array of unsigned bytes, Run lengths. - \param Ppte Array of unsigned bytes, PathPointType enumerations. - - EMF+ manual 2.2.2.32, Microsoft name: EmfPlusPathPointTypeRLE Object -*/ -U_PSEUDO_OBJ *U_PMF_PATHPOINTTYPERLE_set(uint32_t Elements, const uint8_t *Bz, const uint8_t *RL, const uint8_t *Ppte){ - uint8_t utmp; - if(!Bz || !RL || !Ppte)return(NULL); - /* allocate space in the structure but put no data in */ - U_PSEUDO_OBJ *po = U_PO_create(NULL, 4 + 2*Elements, 0, U_PMF_PATHPOINTTYPERLE_OID | U_PMF_ARRAY_OID); - U_PSEUDO_OBJ *holdpo = po; - if(po){ - U_PSEUDO_OBJ *poi = U_PMF_4NUM_set(Elements); - if(!poi)goto end; - po = U_PO_append(po, poi->Data, poi->Used); - U_PO_free(&poi); - if(!po)goto end; - - for( ;Elements; Elements--, Bz++, RL++, Ppte++){ - po = U_PO_append(po, (char *)Ppte, 1); - if(!po)goto end; - - if(*RL > 0x3F) goto end; /* run length too big for field */ - - utmp = (*Bz ? 1 : 0) | ((*RL & 0x3F)<<2); /* bit 1 is not used and is set to 0 */ - po = U_PO_append(po, (char *)&utmp, 1); - if(!po)goto end; - } - } -end: - if(!po)U_PO_free(&holdpo); - return(holdpo); -} - -/** - \brief Create and set a U_PMF_PENDATA PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Unit UnitType enumeration - \param Width Width in units set by Unit - \param Pod U_PSEUDO_OBJ containing first the PenData flags then a U_PMF_PENOPTIONALDATA object (the second part - may be an empty if Flags is 0) - - - EMF+ manual 2.2.2.33, Microsoft name: EmfPlusPenData Object -*/ -U_PSEUDO_OBJ *U_PMF_PENDATA_set(uint32_t Unit, U_FLOAT Width, const U_PSEUDO_OBJ *Pod){ - if(Pod && ((Pod->Type != U_PMF_PENOPTIONALDATA_OID) || Pod->Used < 4))return(NULL); - const U_SERIAL_DESC List[] = { - {(Pod ? Pod->Data : NULL), 4, 1, U_XE}, /* the Flags field, clear if no optional data */ - {&Unit, 4, 1, U_LE}, - {&Width, 4, 1, U_LE}, - /* next is the (optional) U_PMF_PENOPTIONALDATA part or a terminator */ - {(Pod ? Pod->Data + 4 : NULL), (Pod ? Pod->Used - 4 : 0), (Pod ? 1 : 0), (Pod ? U_XE : U_XX)}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_PENDATA_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_PENOPTIONALDATA PseudoObject - \return Pointer to PseudoObject, NULL on error. Returned PO contains first the Flags, then the PO proper. - \param Flags Determines which of the values are stored. - \param Tm U_PSEUDO_OBJ containing a U_PMF_TRANSFORMMATRIX object (Transformation matrix) - \param StartCap LineCapType enumeration - \param EndCap LineCapType enumeration - \param Join LineJoinType enumeration - \param MiterLimit Maximum (miter length / line width) - \param Style LineStyle enumeration - \param DLCap DashedLineCapType enumeration - \param DLOffset Distance line start to first dash start - \param DLData U_PSEUDO_OBJ containing a U_PMF_DASHEDLINEDATA object Dash and space widths - \param PenAlignment PenAlignment enumeration - \param CmpndLineData U_PSEUDO_OBJ containing a U_PMF_COMPOUNDLINEDATA object Compount Line (parallel lines drawn instead of one) - \param CSCapData U_PSEUDO_OBJ containing a U_PMF_CUSTOMSTARTCAPDATA object Custom start cap - \param CECapData U_PSEUDO_OBJ containing a U_PMF_CUSTOMENDCAPDATA object Custom end cap - - - EMF+ manual 2.2.2.34, Microsoft name: EmfPlusPenOptionalData Object -*/ -U_PSEUDO_OBJ *U_PMF_PENOPTIONALDATA_set(uint32_t Flags, U_PSEUDO_OBJ *Tm, int32_t StartCap, int32_t EndCap, uint32_t Join, - U_FLOAT MiterLimit, int32_t Style, int32_t DLCap, U_FLOAT DLOffset, - U_PSEUDO_OBJ *DLData, int32_t PenAlignment, U_PSEUDO_OBJ *CmpndLineData, U_PSEUDO_OBJ *CSCapData, - U_PSEUDO_OBJ *CECapData - ){ - - if((Flags & U_PD_Transform) && (!Tm || (Tm->Type != U_PMF_TRANSFORMMATRIX_OID)) )return(NULL); - if((Flags & U_PD_DLData) && (!DLData || (DLData->Type != U_PMF_DASHEDLINEDATA_OID)) )return(NULL); - if((Flags & U_PD_CLData) && (!CmpndLineData || (CmpndLineData->Type != U_PMF_COMPOUNDLINEDATA_OID)) )return(NULL); - if((Flags & U_PD_CustomStartCap) && (!CSCapData || (CSCapData->Type != U_PMF_CUSTOMSTARTCAPDATA_OID)))return(NULL); - if((Flags & U_PD_CustomEndCap) && (!CECapData || (CECapData->Type != U_PMF_CUSTOMENDCAPDATA_OID)) )return(NULL); - - /* prepend the Flags field to the PseudoObject proper */ - const U_SERIAL_DESC List[] = { - {&Flags, 4, 1, U_LE}, - {((Flags & U_PD_Transform) ? Tm->Data : NULL), ((Flags & U_PD_Transform) ? Tm->Used : 0), 1, U_XE}, - {((Flags & U_PD_StartCap ) ? (char *)&StartCap : NULL), ((Flags & U_PD_StartCap ) ? 4 : 0), 1, U_LE}, - {((Flags & U_PD_EndCap ) ? (char *)&EndCap : NULL), ((Flags & U_PD_EndCap ) ? 4 : 0), 1, U_LE}, - {((Flags & U_PD_Join ) ? (char *)&Join : NULL), ((Flags & U_PD_Join ) ? 4 : 0), 1, U_LE}, - {((Flags & U_PD_MiterLimit ) ? (char *)&MiterLimit : NULL), ((Flags & U_PD_MiterLimit ) ? 4 : 0), 1, U_LE}, - {((Flags & U_PD_LineStyle ) ? (char *)&Style : NULL), ((Flags & U_PD_LineStyle ) ? 4 : 0), 1, U_LE}, - {((Flags & U_PD_DLCap ) ? (char *)&DLCap : NULL), ((Flags & U_PD_DLCap ) ? 4 : 0), 1, U_LE}, - {((Flags & U_PD_DLOffset ) ? (char *)&DLOffset : NULL), ((Flags & U_PD_DLOffset ) ? 4 : 0), 1, U_LE}, - {((Flags & U_PD_DLData ) ? DLData->Data : NULL), ((Flags & U_PD_DLData ) ? DLData->Used : 0), 1, U_XE}, - {((Flags & U_PD_NonCenter ) ? (char *)&PenAlignment : NULL), ((Flags & U_PD_NonCenter ) ? 4 : 0), 1, U_LE}, - {((Flags & U_PD_CLData ) ? CmpndLineData->Data : NULL), ((Flags & U_PD_CLData ) ? CmpndLineData->Used : 0), 1, U_XE}, - {((Flags & U_PD_CustomStartCap) ? CSCapData->Data : NULL), ((Flags & U_PD_CustomStartCap) ? CSCapData->Used : 0), 1, U_XE}, - {((Flags & U_PD_CustomEndCap ) ? CECapData->Data : NULL), ((Flags & U_PD_CustomEndCap ) ? CECapData->Used : 0), 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_PENOPTIONALDATA_OID, List); - return(po); -} - -/** - \brief Create and set an ARRAY of U_PMF_POINT objects - \return Pointer to PseudoObject, NULL on error - \param Elements Number of pairs of points in Coords - \param Coords Array of X,Y pairs. - - EMF+ manual 2.2.2.35, Microsoft name: EmfPlusPoint Object -*/ -U_PSEUDO_OBJ *U_PMF_POINT_set(uint32_t Elements, const U_PMF_POINT *Coords){ - if(!Elements || !Coords)return(NULL); - const U_SERIAL_DESC List[] = { - {&Elements, 4, 1, U_LE}, - { Coords, 2, 2*Elements, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_POINT_OID | U_PMF_ARRAY_OID, List); - return(po); -} - -/** - \brief Create and set an ARRAY of U_PMF_POINTF objects, with a leading Elements value - \return Pointer to PseudoObject, NULL on error - \param Elements Number of pairs of points in Coords - \param Coords Array of X,Y pairs. - - EMF+ manual 2.2.2.36, Microsoft name: EmfPlusPointF Object -*/ -U_PSEUDO_OBJ *U_PMF_POINTF_set(uint32_t Elements, const U_PMF_POINTF *Coords){ - if(!Elements || !Coords)return(NULL); - const U_SERIAL_DESC List[] = { - {&Elements, 4, 1, U_LE}, - {Coords, 4, 2*Elements, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_POINTF_OID | U_PMF_ARRAY_OID, List); - return(po); -} - -/** - \brief Create and set an ARRAY of U_PMF_POINTR objects - \return Pointer to PseudoObject, NULL on error - \param Elements Number of pairs of points in Coords - \param Coords Array of X,Y pairs. These are absolute coordinates, they are converted to Relative here. - - EMF+ manual 2.2.2.37, Microsoft name: EmfPlusPointR Object -*/ -U_PSEUDO_OBJ *U_PMF_POINTR_set(uint32_t Elements, const U_PMF_POINTF *Coords){ - int X,Y; - U_FLOAT Xf,Yf; - U_PSEUDO_OBJ *poi; - /* Worst case scenario it is 4 bytes per coord, plus the count */ - U_PSEUDO_OBJ *po = U_PO_create(NULL, 4 + 4*Elements, 0, U_PMF_POINTR_OID); /* not exactly an array, so no U_PMF_ARRAY_OID */ - U_PSEUDO_OBJ *holdpo = po; - if(!po)goto end; - - poi = U_PMF_4NUM_set(Elements); - po = U_PO_append(po, poi->Data, poi->Used); - U_PO_free(&poi); - if(!po)goto end; - - for(Xf = Yf = 0.0 ;Elements; Elements--, Coords++){ - Xf = U_ROUND(Coords->X) - Xf; - Yf = U_ROUND(Coords->Y) - Yf; - X = ( Xf >= UINT16_MAX ? UINT16_MAX : ( Xf <= INT16_MIN ? INT16_MIN : Xf)); - Y = ( Yf >= UINT16_MAX ? UINT16_MAX : ( Yf <= INT16_MIN ? INT16_MIN : Yf)); - Xf = U_ROUND(Coords->X); - Yf = U_ROUND(Coords->Y); - - /* this is not a very efficient method, too much mucking around with memory */ - - poi = U_PMF_INTEGER7_set(X); - if(!poi)poi = U_PMF_INTEGER15_set(X); /* This one must work because of the range checking, above */ - po = U_PO_append(po, poi->Data, poi->Used); - U_PO_free(&poi); - if(!po)goto end; - - poi = U_PMF_INTEGER7_set(Y); - if(!poi)poi = U_PMF_INTEGER15_set(Y); /* This one must work because of the range checking, above */ - po = U_PO_append(po, poi->Data, poi->Used); - U_PO_free(&poi); - if(!po)goto end; - } - /* Because the values stored were some unpredictable combination of 1 and 2 bytes, the last byte may not end - on a 4 byte boundary. Make it do so by padding with up to 3 zero bytes. */ - - int residual; - residual = 3 & po->Used; - if(residual){ - po = U_PO_append(po, NULL, (4 - residual)); - if(!po)goto end; - } - -end: - if(!po)U_PO_free(&holdpo); - return(holdpo); -} - -/** - \brief Create and set a U_PMF_RECT object - \return Pointer to PseudoObject, NULL on error - \param X UL X value - \param Y UL Y value - \param Width Width - \param Height Height - - EMF+ manual 2.2.2.38, Microsoft name: EmfPlusRect Object -*/ -U_PSEUDO_OBJ *U_PMF_RECT4_set(int16_t X, int16_t Y, int16_t Width, int16_t Height){ - const U_SERIAL_DESC List[] = { - {&X, 2, 1, U_LE}, - {&Y, 2, 1, U_LE}, - {&Width, 2, 1, U_LE}, - {&Height, 2, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_RECT_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_RECT object - \return Pointer to PseudoObject, NULL on error - \param Rect U_PMF_RECT structures - - EMF+ manual 2.2.2.38, Microsoft name: EmfPlusRect Object -*/ -U_PSEUDO_OBJ *U_PMF_RECT_set(U_PMF_RECT *Rect){ - const U_SERIAL_DESC List[] = { - {Rect, 2, 4, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_RECT_OID, List); - return(po); -} - -/** - \brief Create and set an array of U_PMF_RECT objects in a PseudoObject - \return Pointer to PseudoObject, NULL on error. PseudoObject contains Elements followed by the array of U_PMF_RECT objects. - \param Elements Number of elements in Rects - \param Rects Array of U_PMF_RECT structures - - EMF+ manual 2.2.2.38, Microsoft name: EmfPlusRect Object -*/ -U_PSEUDO_OBJ *U_PMF_RECTN_set(uint32_t Elements, U_PMF_RECT *Rects){ - if(!Rects){ return(NULL); } - uint32_t count = Elements; - U_SERIAL_DESC *List = (U_SERIAL_DESC *) malloc((Elements + 2) * sizeof(U_SERIAL_DESC)); - U_SERIAL_DESC *Lptr = List; - if(!List){ return(NULL); } - *Lptr++ = (U_SERIAL_DESC){&Elements, 4, 1, U_LE}; - for(; count; count--, Lptr++, Rects++){ - *Lptr = (U_SERIAL_DESC){Rects, 2, 4, U_LE}; - } - *Lptr = (U_SERIAL_DESC){NULL,0,0,U_XX}; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_RECT_OID | U_PMF_ARRAY_OID, List); - free(List); - return(po); -} - -/** - \brief Create and set a U_PMF_RECTF object in a PseudoObject - \return Pointer to PseudoObject, NULL on error - \param X UL X value - \param Y UL Y value - \param Width Width - \param Height Height - - EMF+ manual 2.2.2.39, Microsoft name: EmfPlusRectF Object -*/ -U_PSEUDO_OBJ *U_PMF_RECTF4_set(U_FLOAT X, U_FLOAT Y, U_FLOAT Width, U_FLOAT Height){ - const U_SERIAL_DESC List[] = { - {&X, 4, 1, U_LE}, - {&Y, 4, 1, U_LE}, - {&Width, 4, 1, U_LE}, - {&Height, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_RECTF_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_RECTF object in a PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Rect U_PMF_RECTF structure - - EMF+ manual 2.2.2.39, Microsoft name: EmfPlusRectF Object -*/ -U_PSEUDO_OBJ *U_PMF_RECTF_set(U_PMF_RECTF *Rect){ - const U_SERIAL_DESC List[] = { - {Rect, 4, 4, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_RECTF_OID, List); - return(po); -} - -/** - \brief Create and set an array of U_PMF_RECTF objects in a PseudoObject - \return Pointer to PseudoObject, NULL on error. PseudoObject contains Elements followed by the array of U_PMF_RECTF objects. - \param Elements Number of elements in Rects - \param Rects Array of U_PMF_RECTF structures - - EMF+ manual 2.2.2.39, Microsoft name: EmfPlusRectF Object -*/ -U_PSEUDO_OBJ *U_PMF_RECTFN_set(uint32_t Elements, U_PMF_RECTF *Rects){ - if(!Rects){ return(NULL); } - uint32_t count = Elements; - U_SERIAL_DESC *List = (U_SERIAL_DESC *) malloc((Elements + 2) * sizeof(U_SERIAL_DESC)); - U_SERIAL_DESC *Lptr = List; - if(!List){ return(NULL); } - *Lptr++ = (U_SERIAL_DESC){&Elements, 4, 1, U_LE}; - for(; count; count--, Lptr++, Rects++){ - *Lptr = (U_SERIAL_DESC){Rects, 4, 4, U_LE}; - } - *Lptr = (U_SERIAL_DESC){NULL,0,0,U_XX}; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_RECTF_OID | U_PMF_ARRAY_OID, List); - free(List); - return(po); -} - -/** - \brief Create and set a U_PMF_REGIONNODE PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Type RegionNodeDataType Enumeration - \param Rnd (optional) U_PSEUDO_OBJ containing a U_PMF_REGIONNODEPATH, U_PMF_RECTF, or U_PMF_REGIONNODECHILDNODES object (Region Node Data) - - - EMF+ manual 2.2.2.40, Microsoft name: EmfPlusRegionNode Object -*/ -U_PSEUDO_OBJ *U_PMF_REGIONNODE_set(int32_t Type, const U_PSEUDO_OBJ *Rnd){ - int32_t pType; - /* make sure that the type of Rnd agrees with Type */ - if(Rnd){ - pType = U_OID_To_RNDT(Rnd->Type); - if( pType < 0){ return(NULL); } - if((pType > 0) && (pType != Type)){ return(NULL); } - if((pType == 0) && - ( - (Type < U_RNDT_And) || - (Type > U_RNDT_Complement) - ) - ){ return(NULL); } - if((Type == U_RNDT_Rect) && (Rnd->Type != U_PMF_RECTF_OID)){ return(NULL); } - if((Type == U_RNDT_Path) && (Rnd->Type != U_PMF_REGIONNODEPATH_OID)){ return(NULL); } - - } - else { /* only U_RNDT_Empty and U_RNDT_Infinite do not have data */ - if((Type != U_RNDT_Empty) || - (Type != U_RNDT_Infinite) ){ return(NULL); } - } - - - const U_SERIAL_DESC List[] = { - {&Type, 4, 1, U_LE}, - {(Rnd ? Rnd->Data : NULL), (Rnd ? Rnd->Used : 0), 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_REGIONNODE_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_REGIONNODECHILDNODES PseudoObject - \return Pointer to PseudoObject containing a U_PMF_REGIONNODECHILDNODES_OID object, NULL on error - \param Left U_PSEUDO_OBJ containing a U_PMF_REGIONNODE object - \param Right U_PSEUDO_OBJ containing a U_PMF_REGIONNODE object - - - EMF+ manual 2.2.2.41, Microsoft name: EmfPlusRegionNodeChildNodes Object -*/ -U_PSEUDO_OBJ *U_PMF_REGIONNODECHILDNODES_set(const U_PSEUDO_OBJ *Left, const U_PSEUDO_OBJ *Right){ - if(!Left || (Left->Type != U_PMF_REGIONNODE_OID)){ return(NULL); } - if(!Right || (Right->Type != U_PMF_REGIONNODE_OID)){ return(NULL); } - - const U_SERIAL_DESC List[] = { - {Left->Data, Left->Used, 1, U_XE}, - {Right->Data, Right->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_REGIONNODECHILDNODES_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_REGIONNODEPATH PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Path U_PSEUDO_OBJ containing a U_PMF_PATH object - - - EMF+ manual 2.2.2.42, Microsoft name: EmfPlusRegionNodePath Object -*/ -U_PSEUDO_OBJ *U_PMF_REGIONNODEPATH_set(const U_PSEUDO_OBJ *Path){ - if(!Path || (Path->Type != U_PMF_PATH_OID)){ return(NULL); } - /* PO Used is size_t, might be 8 bytes, value in record must be 4 bytes */ - uint32_t Used = Path->Used; - - const U_SERIAL_DESC List[] = { - {&Used, 4, 1, U_LE}, - {Path->Data, Path->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_REGIONNODEPATH_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_SOLIDBRUSHDATA PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Color U_PSEUDO_OBJ containing a U_PMF_ARGB object - - - EMF+ manual 2.2.2.43, Microsoft name: EmfPlusSolidBrushData Object -*/ -U_PSEUDO_OBJ *U_PMF_SOLIDBRUSHDATA_set(const U_PSEUDO_OBJ *Color){ - if(!Color || (Color->Type != U_PMF_ARGB_OID)){ return(NULL); } - - const U_SERIAL_DESC List[] = { - {Color->Data, Color->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_SOLIDBRUSHDATA_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_STRINGFORMATDATA PseudoObject - \return Pointer to PseudoObject, NULL on error - \param TabStopCount Entries in TabStop array - \param TabStops (optional) Array of tabstop locations - \param Ranges (optional) U_PSEUDO_OBJ containing an array of U_PMF_CHARACTERRANGE objects - - - EMF+ manual 2.2.2.44, Microsoft name: EmfPlusStringFormatData Object -*/ -U_PSEUDO_OBJ *U_PMF_STRINGFORMATDATA_set(uint32_t TabStopCount, U_FLOAT *TabStops, const U_PSEUDO_OBJ *Ranges){ - if(Ranges && (Ranges->Type != (U_PMF_CHARACTERRANGE_OID | U_PMF_ARRAY_OID))){ return(NULL); } - - const U_SERIAL_DESC List[] = { - {TabStops, TabStopCount*4, 1, U_LE}, - {(Ranges ? Ranges->Data : NULL), (Ranges ? Ranges->Used : 0), 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_STRINGFORMATDATA_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_TEXTUREBRUSHDATA PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Flags BrushData flags - \param WrapMode WrapMode enumeration - \param Tbod U_PSEUDO_OBJ containing an U_PMF_TEXTUREBRUSHOPTIONALDATA object - - - EMF+ manual 2.2.2.45, Microsoft name: EmfPlusTextureBrushData Object -*/ -U_PSEUDO_OBJ *U_PMF_TEXTUREBRUSHDATA_set(uint32_t Flags, uint32_t WrapMode, const U_PSEUDO_OBJ *Tbod){ - if(Flags & ~U_BD_MASKB){ return(NULL); } /* a bit was set that is not supported for this record */ - if(WrapMode > U_WM_Clamp){ return(NULL); } - if(!Tbod || (Tbod->Type != (U_PMF_TEXTUREBRUSHOPTIONALDATA_OID))){ return(NULL); } - - const U_SERIAL_DESC List[] = { - {&Flags, 4, 1, U_LE}, - {&WrapMode, 4, 1, U_LE}, - {Tbod->Data, Tbod->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_TEXTUREBRUSHDATA_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_TEXTUREBRUSHOPTIONALDATA PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Tm (optional) U_PSEUDO_OBJ containing an U_PMF_TRANSFORMMATRIX object - \param Image (optional) U_PSEUDO_OBJ containing an U_PMF_IMAGE object - - - EMF+ manual 2.2.2.46, Microsoft name: EmfPlusTextureBrushOptionalData Object -*/ -U_PSEUDO_OBJ *U_PMF_TEXTUREBRUSHOPTIONALDATA_set(const U_PSEUDO_OBJ *Tm, const U_PSEUDO_OBJ *Image){ - if(Tm && (Tm->Type != (U_PMF_TRANSFORMMATRIX_OID))){ return(NULL); } - if(Image && (Image->Type != (U_PMF_IMAGE_OID))){ return(NULL); } - - const U_SERIAL_DESC List[] = { - {(Tm ? Tm->Data : NULL), (Tm ? Tm->Used : 0), 1, U_XE}, - {(Image ? Image->Data : NULL), (Image ? Image->Used : 0), 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_TEXTUREBRUSHOPTIONALDATA_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_TRANSFORMMATRIX PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Tm U_PMF_TRANSFORMMATRIX_ object - - - EMF+ manual 2.2.2.47, Microsoft name: EmfPlusTransformMatrix Object -*/ -U_PSEUDO_OBJ *U_PMF_TRANSFORMMATRIX_set(U_PMF_TRANSFORMMATRIX *Tm){ - if(!Tm){ return(NULL); } - - const U_SERIAL_DESC List[] = { - {Tm, 4, 6, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_TRANSFORMMATRIX_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_IE_BLUR PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Radius Blur radius in pixels - \param ExpandEdge 1: expand bitmap by Radius; 0: bitmap size unchanged - - - EMF+ manual 2.2.3.1, Microsoft name: BlurEffect Object -*/ -U_PSEUDO_OBJ *U_PMF_IE_BLUR_set(U_FLOAT Radius, uint32_t ExpandEdge){ - - const U_SERIAL_DESC List[] = { - {&Radius, 4, 1, U_LE}, - {&ExpandEdge, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_IE_BLUR_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_IE_BRIGHTNESSCONTRAST PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Brightness -255 to 255, 0 is unchanged, positive increases, negative decreases - \param Contrast -100 to 100, 0 is unchanged, positive increases, negative decreases - - - EMF+ manual 2.2.3.2, Microsoft name: BrightnessContrastEffect Object -*/ -U_PSEUDO_OBJ *U_PMF_IE_BRIGHTNESSCONTRAST_set(int32_t Brightness, int32_t Contrast){ - - const U_SERIAL_DESC List[] = { - {&Brightness, 4, 1, U_LE}, - {&Contrast, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_IE_BRIGHTNESSCONTRAST_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_IE_COLORBALANCE PseudoObject - \return Pointer to PseudoObject, NULL on error - \param CyanRed -100 to 100, 0 is unchanged, positive increases Red & decreases Cyan, negative is opposite - \param MagentaGreen -100 to 100, 0 is unchanged, positive increases Green & decreases Magenta, negative is opposite - \param YellowBlue -100 to 100, 0 is unchanged, positive increases Blue & decreases Yellow, negative is opposite - - - EMF+ manual 2.2.3.3, Microsoft name: ColorBalanceEffect Object -*/ -U_PSEUDO_OBJ *U_PMF_IE_COLORBALANCE_set(int32_t CyanRed, int32_t MagentaGreen, int32_t YellowBlue){ - - const U_SERIAL_DESC List[] = { - {&CyanRed, 4, 1, U_LE}, - {&MagentaGreen, 4, 1, U_LE}, - {&YellowBlue, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_IE_COLORBALANCE_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_IE_COLORCURVE PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Adjust CurveAdjustment enumeration - \param Channel CurveChannel enumeration - \param Intensity adjustment to apply. "Adjust" determines what field this is and range values. - - - EMF+ manual 2.2.3.4, Microsoft name: ColorCurveEffect Object -*/ -U_PSEUDO_OBJ *U_PMF_IE_COLORCURVE_set(uint32_t Adjust, uint32_t Channel, int32_t Intensity){ - - const U_SERIAL_DESC List[] = { - {&Adjust, 4, 1, U_LE}, - {&Channel, 4, 1, U_LE}, - {&Intensity, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_IE_COLORCURVE_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_IE_COLORLOOKUPTABLE PseudoObject - \return Pointer to PseudoObject, NULL on error - \param BLUT Blue color lookup table - \param GLUT Green color lookup table - \param RLUT Red color lookup table - \param ALUT Alpha color lookup table - - - - EMF+ manual 2.2.3.5, Microsoft name: ColorLookupTableEffect Object. - All tables have 256 entries. -*/ -U_PSEUDO_OBJ *U_PMF_IE_COLORLOOKUPTABLE_set(const uint8_t *BLUT, const uint8_t *GLUT, const uint8_t *RLUT, const uint8_t *ALUT){ - if(!BLUT || !GLUT || !RLUT || !ALUT)return(NULL); - - const U_SERIAL_DESC List[] = { - {BLUT, 1, 256, U_XE}, - {GLUT, 1, 256, U_XE}, - {RLUT, 1, 256, U_XE}, - {ALUT, 1, 256, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_IE_COLORLOOKUPTABLE_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_IE_COLORMATRIX PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Matrix 5 x 5 color transformation matrix, First 4 rows are [{4 multiplier values},0.0] for R,G,B,A, last Row is [{4 color translation valuess}, 1.0] - - - EMF+ manual 2.2.3.6, Microsoft name: ColorMatrixEffect Object -*/ -U_PSEUDO_OBJ *U_PMF_IE_COLORMATRIX_set(const U_FLOAT *Matrix){ - if(!Matrix)return(NULL); - - const U_SERIAL_DESC List[] = { - {Matrix, 4, 25, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_IE_COLORMATRIX_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_IE_HUESATURATIONLIGHTNESS PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Hue -180 to 180, 0 is unchanged - \param Saturation -100 to 100, 0 is unchanged - \param Lightness -100 to 100, 0 is unchanged - - - EMF+ manual 2.2.3.7, Microsoft name: HueSaturationLightnessEffect Object -*/ -U_PSEUDO_OBJ *U_PMF_IE_HUESATURATIONLIGHTNESS_set(int32_t Hue, int32_t Saturation, int32_t Lightness){ - - const U_SERIAL_DESC List[] = { - {&Hue, 4, 1, U_LE}, - {&Saturation, 4, 1, U_LE}, - {&Lightness, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_IE_HUESATURATIONLIGHTNESS_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_IE_LEVELS PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Highlight 0 to 100, 100 is unchanged - \param Midtone -100 to 0, 0 is unchanged - \param Shadow 0 to 100, 0 is unchanged - - - EMF+ manual 2.2.3.8, Microsoft name: LevelsEffect Object -*/ -U_PSEUDO_OBJ *U_PMF_IE_LEVELS_set(int32_t Highlight, int32_t Midtone, int32_t Shadow){ - - const U_SERIAL_DESC List[] = { - {&Highlight, 4, 1, U_LE}, - {&Midtone, 4, 1, U_LE}, - {&Shadow, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_IE_LEVELS_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_IE_REDEYECORRECTION PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Elements Number of members in Rects - \param Rects Array of U_RECTL rectangular area(s) to apply red eye correction - - - EMF+ manual 2.2.3.9, Microsoft name: RedEyeCorrectionEffect Object -*/ -U_PSEUDO_OBJ *U_PMF_IE_REDEYECORRECTION_set(uint32_t Elements, const U_RECTL *Rects){ - if(!Elements || !Rects){return(NULL);} - - const U_SERIAL_DESC List[] = { - {&Elements, 4, 1, U_LE}, - {Rects, 4*4, Elements,U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_IE_REDEYECORRECTION_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_IE_SHARPEN PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Radius Sharpening radius in pixels - \param Sharpen 0 to 100, 0 is unchanged - - - EMF+ manual 2.2.3.10, Microsoft name: SharpenEffect Object -*/ -U_PSEUDO_OBJ *U_PMF_IE_SHARPEN_set(U_FLOAT Radius, int32_t Sharpen){ - - const U_SERIAL_DESC List[] = { - {&Radius, 4, 1, U_LE}, - {&Sharpen, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_IE_SHARPEN_OID, List); - return(po); -} - -/** - \brief Create and set a U_PMF_IE_TINT PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Hue -180 to 180, [positive==clockwise] rotation in degrees starting from blue - \param Amount -100 [add black] to 100[add white], 0 is unchanged. Change in hue on specified axis - - - EMF+ manual 2.2.3.11, Microsoft name: TintEffect Object -*/ -U_PSEUDO_OBJ *U_PMF_IE_TINT_set(const int32_t Hue, const int32_t Amount){ - - const U_SERIAL_DESC List[] = { - {&Hue, 4, 1, U_LE}, - {&Amount, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_IE_TINT_OID, List); - return(po); -} - -//! \cond -/* internal routine, not part of the API. - Returns a PseudoObject containing a U_PMR_CMN_HDR_OID object. - The type is something like U_PMR_OFFSETCLIP (the record type, NOT the U_PMR_OFFSETCLIP_OID PseudoObject Type!). - The U_PMR_RECFLAG bit is added both in the data and in the Type of the PseudoObject. - If that bit is already set no harm, no foul. -*/ - -U_PSEUDO_OBJ *U_PMR_CMN_HDR_set(uint32_t Type, uint16_t Flags, uint32_t DataSize){ - - uint32_t Size = 12 + UP4(DataSize); /* The header itself is always 12, PMR records must be a multiple of 4 */ - Type |= U_PMR_RECFLAG; - uint16_t utmp16 = Type; - const U_SERIAL_DESC List[] = { - {&utmp16, 2, 1, U_LE}, - {&Flags, 2, 1, U_LE}, /* Microsoft EMF+ manual is BE, but this field in this implementation is LE */ - {&Size, 4, 1, U_LE}, - {&DataSize, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_CMN_HDR_OID, List); - return(po); -} -//! \endcond - - -/** - \brief Create and set a U_PMR_STROKEFILLPATH PseudoObject - \return Pointer to PseudoObject, NULL on error - - - EMF+ manual mentioned in 2.1.1.1, not otherwise documented, Microsoft name: EmfPlusStrokeFillPath Record, Index 0x37 - - "This record closes any open figures in a path, strokes the outline of - the path by using the current pen, and fills its interior by using the current brush." - -*/ -U_PSEUDO_OBJ *U_PMR_STROKEFILLPATH_set(void){ - int Size = 0; - uint16_t utmp16 = 0; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_STROKEFILLPATH,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_STROKEFILLPATH_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_OFFSETCLIP PseudoObject - \return Pointer to PseudoObject, NULL on error - \param dX horizontal translation offset to apply to clipping region - \param dY vertical translation offset to apply to clipping region - - - EMF+ manual 2.3.1.1, Microsoft name: EmfPlusOffsetClip Record, Index 0x35 -*/ -U_PSEUDO_OBJ *U_PMR_OFFSETCLIP_set(U_FLOAT dX, U_FLOAT dY){ - int Size = 2*4; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_OFFSETCLIP,0,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {&dX, 4, 1, U_LE}, - {&dY, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_OFFSETCLIP_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_RESETCLIP PseudoObject - \return Pointer to PseudoObject, NULL on error - - - EMF+ manual 2.3.1.2, Microsoft name: EmfPlusResetClip Record, Index 0x31 -*/ -U_PSEUDO_OBJ *U_PMR_RESETCLIP_set(void){ - int Size = 0; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_RESETCLIP,0,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_RESETCLIP_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_SETCLIPPATH PseudoObject - \return Pointer to PseudoObject, NULL on error - \param CMenum CombineMode enumeration.. - \param PathID U_PMF_PATH object in the EMF+ object table (0-63, inclusive) - - - EMF+ manual 2.3.1.3, Microsoft name: EmfPlusSetClipPath Record, Index 0x33 -*/ -U_PSEUDO_OBJ *U_PMR_SETCLIPPATH_set(uint32_t PathID, uint32_t CMenum){ - if(PathID>63)return(NULL); - int Size=0; - uint16_t utmp16 = ((PathID & U_FF_MASK_OID8) << U_FF_SHFT_OID8) | ((CMenum & U_FF_MASK_CM4) << U_FF_SHFT_CM4); - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETCLIPPATH,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETCLIPPATH_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_SETCLIPRECT PseudoObject - \return Pointer to PseudoObject, NULL on error - \param CMenum CombineMode enumeration.. - \param Rect U_PSEUDO_OBJ containing an U_PMF_RECTF object or an array of U_PMF_RECTF objects (the first is used) - - - EMF+ manual 2.3.1.4, Microsoft name: EmfPlusSetClipRect Record, Index 0x32 -*/ -U_PSEUDO_OBJ *U_PMR_SETCLIPRECT_set(uint32_t CMenum, const U_PSEUDO_OBJ *Rect){ - int Size=4*4; - const char *start; - uint16_t utmp16 = ((CMenum & U_FF_MASK_CM4) << U_FF_SHFT_CM4); - if(Rect){ - if( Rect->Type == U_PMF_RECTF_OID){ - start = Rect->Data; - } - else if(Rect->Type == (U_PMF_RECTF_OID | U_PMF_ARRAY_OID)){ - start = Rect->Data + 4; - } - else { return(0); } - } - else { return(0); } - - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETCLIPRECT,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {start, 4, 4, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETCLIPRECT_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_SETCLIPREGION PseudoObject - \return Pointer to PseudoObject, NULL on error - \param PathID U_PMF_PATH object in the EMF+ object table (0-63, inclusive) - \param CMenum CombineMode enumeration.. - - - EMF+ manual 2.3.1.5, Microsoft name: EmfPlusSetClipRegion Record, Index 0x34 -*/ -U_PSEUDO_OBJ *U_PMR_SETCLIPREGION_set(uint32_t PathID, uint32_t CMenum){ - if(PathID>63)return(NULL); - int Size=0; - uint16_t utmp16 = ((PathID & U_FF_MASK_OID8) << U_FF_SHFT_OID8) | ((CMenum & U_FF_MASK_CM4) << U_FF_SHFT_CM4); - - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETCLIPREGION,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETCLIPREGION_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_COMMENT PseudoObject - \return Pointer to PseudoObject, NULL on error - \param cbData Number of bytes in Data, must be a multiple of 4 - \param Data Private data, may be anything. Stored in PseudoObject without adjusting byte order. - - - EMF+ manual 2.3.2.1, Microsoft name: EmfPlusComment Record, Index 0x03 -*/ -U_PSEUDO_OBJ *U_PMR_COMMENT_set(size_t cbData, const void *Data){ - if(UP4(cbData) != cbData){ return(NULL); } - if(cbData && !Data){ return(NULL); } - int Size=cbData; - - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_COMMENT,0,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {Data, cbData, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_COMMENT_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_ENDOFFILE PseudoObject - \return Pointer to PseudoObject, NULL on error - - - EMF+ manual 2.3.3.1, Microsoft name: EmfPlusEndOfFile Record, Index 0x02 -*/ -U_PSEUDO_OBJ *U_PMR_ENDOFFILE_set(void){ - int Size=0; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_ENDOFFILE,0,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_ENDOFFILE_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_GETDC PseudoObject - \return Pointer to PseudoObject, NULL on error - - - EMF+ manual 2.3.3.2, Microsoft name: EmfPlusGetDC Record, Index 0x04 -*/ -U_PSEUDO_OBJ *U_PMR_GETDC_set(void){ - int Size=0; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_GETDC,0,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_GETDC_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_HEADER PseudoObject - \return Pointer to PseudoObject, NULL on error - \param IsDual set = Dual-mode file, clear= EMF+ only file. - \param IsVideo set = video device, clear= printer. Ignore all other bits. - \param Version U_PSEUDO_OBJ containing a U_PMF_GRAPHICSVERSION object - \param LogicalDpiX Horizontal resolution reference device in DPI - \param LogicalDpiY Vertical resolution reference device in DPI - - - EMF+ manual 2.3.3.3, Microsoft name: EmfPlusHeader Record, Index 0x01 -*/ -U_PSEUDO_OBJ *U_PMR_HEADER_set(int IsDual, int IsVideo, const U_PSEUDO_OBJ *Version, - uint32_t LogicalDpiX, uint32_t LogicalDpiY){ - if(!Version || (Version->Type != U_PMF_GRAPHICSVERSION_OID)){ return(NULL); } - int Size=Version->Used + 3*4; - uint16_t utmp16 = (IsDual ? U_PPF_DM : 0); - uint32_t Flags = (IsVideo ? U_PPF_VIDEO : 0); - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_HEADER,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {Version->Data, Version->Used, 1, U_XE}, - {&Flags, 4, 1, U_LE}, - {&LogicalDpiX, 4, 1, U_LE}, - {&LogicalDpiY, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_HEADER_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_CLEAR PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Color U_PSEUDO_OBJ containing a U_PMF_ARGB object. - - - - EMF+ manual 2.3.4.1, Microsoft name: EmfPlusClear Record, Index 0x09 - - Erase everything preceding, set background ARGB to Color. -*/ -U_PSEUDO_OBJ *U_PMR_CLEAR_set(const U_PSEUDO_OBJ *Color){ - if(!Color || (Color->Type != U_PMF_ARGB_OID)){ return(NULL); } - int Size=Color->Used; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_CLEAR,0,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {Color->Data, Color->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_CLEAR_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_DRAWARC PseudoObject - \return Pointer to PseudoObject, NULL on error - \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive) - \param Start Start angle, >=0.0, degrees clockwise from 3:00 - \param Sweep Sweep angle, -360<= angle <=360, degrees clockwise from Start - \param Rect U_PSEUDO_OBJ containing a U_PMF_RECT or U_PMF_RECTF object - - - EMF+ manual 2.3.4.2, Microsoft name: EmfPlusDrawArc Record, Index 0x12 -*/ -U_PSEUDO_OBJ *U_PMR_DRAWARC_set(uint32_t PenID, U_FLOAT Start, U_FLOAT Sweep, const U_PSEUDO_OBJ *Rect){ - int ctype; - if(PenID>63)return(NULL); - if(!Rect){ return(NULL); } - else { - if( Rect->Type == U_PMF_RECT_OID ){ ctype = 1; } - else if(Rect->Type == U_PMF_RECTF_OID){ ctype = 0; } - else { return(NULL); } - } - int Size = 2*4 + Rect->Used; - uint16_t utmp16 = (ctype ? U_PPF_C : 0) | (PenID & U_FF_MASK_OID8) << U_FF_SHFT_OID8; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_DRAWARC,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {&Start, 4, 1, U_LE}, - {&Sweep, 4, 1, U_LE}, - {Rect->Data, Rect->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_DRAWARC_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_DRAWBEZIERS PseudoObject - \return Pointer to PseudoObject, NULL on error - \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive) - \param Points U_PSEUDO_OBJ containing first Elements, then a U_PMF_POINT, U_PMF_POINTR or U_PMF_POINTF object - - - EMF+ manual 2.3.4.3, Microsoft name: EmfPlusDrawBeziers Record, Index 0x19 -*/ -U_PSEUDO_OBJ *U_PMR_DRAWBEZIERS_set(uint32_t PenID, const U_PSEUDO_OBJ *Points){ - int ctype, RelAbs; - if(PenID>63)return(NULL); - if(Points){ - if( Points->Type == U_PMF_POINTR_OID){ RelAbs = 1; ctype = 0; } - else if(Points->Type == (U_PMF_POINT_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 1; } - else if(Points->Type == (U_PMF_POINTF_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 0; } - else { return(NULL); } - } - else { return(NULL); } - int Size = Points->Used; - uint16_t utmp16 = (ctype ? U_PPF_C : 0) | (RelAbs ? U_PPF_P : 0) |(PenID & U_FF_MASK_OID8) << U_FF_SHFT_OID8; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_DRAWBEZIERS,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {Points->Data, Points->Used, 1, U_XE}, /* Includes Elements */ - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_DRAWBEZIERS_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_DRAWCLOSEDCURVE PseudoObject - \return Pointer to PseudoObject, NULL on error - \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive) - \param Tension Controls splines, 0 is straight line, >0 is curved - \param Points U_PSEUDO_OBJ containing a U_PMF_POINT, U_PMF_POINTR or U_PMF_POINTF object - - - EMF+ manual 2.3.4.4, Microsoft name: EmfPlusDrawClosedCurve Record, Index 0x17 - - Curve is a cardinal spline. - - References sent by MS support: - - http://alvyray.com/Memos/CG/Pixar/spline77.pdf - - http://msdn.microsoft.com/en-us/library/4cf6we5y(v=vs.110).aspx - - -*/ -U_PSEUDO_OBJ *U_PMR_DRAWCLOSEDCURVE_set(uint32_t PenID, U_FLOAT Tension, const U_PSEUDO_OBJ *Points){ - int ctype, RelAbs; - if(PenID>63)return(NULL); - if(Points){ - if( Points->Type == U_PMF_POINTR_OID){ RelAbs = 1; ctype = 0; } - else if(Points->Type == (U_PMF_POINT_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 1; } - else if(Points->Type == (U_PMF_POINTF_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 0; } - else { return(NULL); } - } - else { return(NULL); } - int Size = 4 + Points->Used; - uint16_t utmp16 = (ctype ? U_PPF_C : 0) | (RelAbs ? U_PPF_P : 0) |(PenID & U_FF_MASK_OID8) << U_FF_SHFT_OID8; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_DRAWCLOSEDCURVE,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {&Tension, 4, 1, U_LE}, - {Points->Data, Points->Used, 1, U_XE}, /* includes Elements*/ - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_DRAWCLOSEDCURVE_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_DRAWCURVE PseudoObject - \return Pointer to PseudoObject, NULL on error - \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive) - \param Tension Controls splines, 0 is straight line, >0 is curved - \param Offset The starting point in the list of points, 0 is first. - \param NSegs Number of segments to draw. Starting at Offset go NSegs straight lines, must not run out of points.. - \param Points U_PSEUDO_OBJ containing an element count then a series of U_PMF_POINT or U_PMF_POINTF object - - - EMF+ manual 2.3.4.5, Microsoft name: EmfPlusDrawCurve Record, Index 0x18 - - Curve is a cardinal spline, using doubled terminator points to generate curves for the terminal segments. - - References sent by MS support: - - http://alvyray.com/Memos/CG/Pixar/spline77.pdf - - http://msdn.microsoft.com/en-us/library/4cf6we5y(v=vs.110).aspx - -*/ -U_PSEUDO_OBJ *U_PMR_DRAWCURVE_set(uint32_t PenID, U_FLOAT Tension, uint32_t Offset, uint32_t NSegs, const U_PSEUDO_OBJ *Points){ - int ctype; - if(PenID>63)return(NULL); - if(!Points){ return(NULL); } - if(!NSegs){ return(NULL); } - else { - if( Points->Type == (U_PMF_POINT_OID | U_PMF_ARRAY_OID)){ ctype = 1; } - else if(Points->Type == (U_PMF_POINTF_OID | U_PMF_ARRAY_OID)){ ctype = 0; } - else { return(NULL); } - } - uint32_t Elements = (Points->Used - 4)/(ctype ? 4 : 8); /* This way do not need to worry about byte order */ - if(Offset + NSegs + 1 > Elements){ return(NULL); } - int Size = 3*4 + Points->Used; - uint16_t utmp16 = (ctype ? U_PPF_C : 0) |(PenID & U_FF_MASK_OID8) << U_FF_SHFT_OID8; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_DRAWCURVE,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {&Tension, 4, 1, U_LE}, - {&Offset, 4, 1, U_LE}, - {&NSegs, 4, 1, U_LE}, - {Points->Data, Points->Used, 1, U_XE}, /* Elements, points */ - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_DRAWCURVE_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_DRAWDRIVERSTRING PseudoObject - \return Pointer to PseudoObject, NULL on error - \param FontID U_PMF_FONT object in the EMF+ object table (0-63, inclusive) - \param BrushID U_PSEUDO_OBJ containing a U_PMF_ARGB or a U_PMF_4NUM. Color or U_PMF_BRUSH object in the EMF+ object table (0-63, inclusive) - \param DSOFlags DriverStringOptions flags - \param HasMatrix If 1 record contains a TransformMatrix field, if 0 it does not. - \param GlyphCount The number of Elements in Glyphs, must agree with the number of elements in Points. - \param Glyphs If U_DSO_CmapLookup is set in DSOFlags this is an array of UTF16LE characters, otherwise, it is an array of indices into the U_PMF_FONT object indexed by Object_ID in flags. - \param Points U_PSEUDO_OBJ containing a U_PMF_POINTF object - \param Tm U_PSEUDO_OBJ containing a U_PMF_TRANSFORMMATRIX object. Apply to Glyphs & Positions. Present if HasMatrix is 1 - - - EMF+ manual 2.3.4.6, Microsoft name: EmfPlusDrawDriverString Record, Index 0x36 -*/ -U_PSEUDO_OBJ *U_PMR_DRAWDRIVERSTRING_set(uint32_t FontID, const U_PSEUDO_OBJ *BrushID, - uint32_t DSOFlags, uint32_t HasMatrix, uint32_t GlyphCount, - const uint16_t *Glyphs, const U_PSEUDO_OBJ *Points, const U_PSEUDO_OBJ *Tm){ - int btype; - if(FontID>63){ return(NULL); } - if(!Glyphs){ return(NULL); } - if(!Points || (Points->Type != (U_PMF_POINTF_OID | U_PMF_ARRAY_OID))){ return(NULL); } - uint32_t Elements = (Points->Used -4)/4; - if(GlyphCount != Elements){ return(NULL); } - if(BrushID){ - if( BrushID->Used != 4){ return(NULL); } - else if( BrushID->Type == U_PMF_ARGB_OID){ btype = 1; } - else if( BrushID->Type == U_PMF_4NUM_OID){ btype = 0; } - else { return(NULL); } - } - else { return(NULL); } - int Size = 4 + BrushID->Used + 3*4 + Elements*2 + (Points->Used - 4); - if(HasMatrix){ - if(!Tm){ return(NULL); } - else if(Tm->Type != (U_PMF_TRANSFORMMATRIX_OID)){ return(NULL); } - Size += Tm->Used; - } - uint16_t utmp16 = (btype ? U_PPF_B : 0) |(FontID & U_FF_MASK_OID8) << U_FF_SHFT_OID8; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_DRAWDRIVERSTRING,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data,ph->Used, 1, U_XE}, - {BrushID->Data, BrushID->Used, 1, U_XE}, - {&DSOFlags, 4, 1, U_LE}, - {&HasMatrix, 4, 1, U_LE}, - {&Elements, 4, 1, U_LE}, - {Glyphs, 2, Elements, U_LE}, - {Points->Data + 4, Points->Used - 4, 1, U_XE}, /* omit Elements */ - {(HasMatrix ? Tm->Data : NULL), (HasMatrix ? Tm->Used : 0), 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_DRAWDRIVERSTRING_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_DRAWELLIPSE PseudoObject - \return Pointer to PseudoObject, NULL on error - \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive) - \param Rect U_PSEUDO_OBJ containing a U_PMF_RECT or U_PMF_RECTF object - - - EMF+ manual 2.3.4.7, Microsoft name: EmfPlusDrawEllipse Record, Index 0x0F -*/ -U_PSEUDO_OBJ *U_PMR_DRAWELLIPSE_set(uint32_t PenID, const U_PSEUDO_OBJ *Rect){ - if(PenID>63)return(NULL); - int ctype; - if(!Rect){ return(NULL); } - else { - if( Rect->Type == U_PMF_RECT_OID ){ ctype = 1; } - else if(Rect->Type == U_PMF_RECTF_OID){ ctype = 0; } - else { return(NULL); } - } - int Size = Rect->Used; - uint16_t utmp16 = (ctype ? U_PPF_C : 0) | (PenID & U_FF_MASK_OID8) << U_FF_SHFT_OID8; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_DRAWELLIPSE,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {Rect->Data, Rect->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_DRAWELLIPSE_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_DRAWIMAGE PseudoObject - \return Pointer to PseudoObject, NULL on error - \param ImgID U_PMF_IMAGE object in the EMF+ object table (0-63, inclusive) - \param ImgAttrID index of a U_PMF_IMAGEATTRIBUTES object in the object table - \param SrcUnit UnitType enumeration - \param SrcRect U_PSEUDO_OBJ containing a U_PMF_RECTF object, Source region of image - \param DstRect U_PSEUDO_OBJ containing a U_PMF_RECT or U_PMF_RECTF object - - - EMF+ manual 2.3.4.8, Microsoft name: EmfPlusDrawImage Record, Index 0x1A -*/ -U_PSEUDO_OBJ *U_PMR_DRAWIMAGE_set(uint32_t ImgID, - int32_t ImgAttrID, int32_t SrcUnit, const U_PSEUDO_OBJ *SrcRect, const U_PSEUDO_OBJ *DstRect){ - int ctype; - if(ImgID>63)return(NULL); - if(!SrcRect || (SrcRect->Type != U_PMF_RECTF_OID)){ return(NULL); } - if(!DstRect){ return(NULL); } - else { - if( DstRect->Type == U_PMF_RECT_OID ){ ctype = 1; } - else if(DstRect->Type == U_PMF_RECTF_OID){ ctype = 0; } - else { return(NULL); } - } - int Size = 2*4 + SrcRect->Used + DstRect->Used; - uint16_t utmp16 = (ctype ? U_PPF_C : 0) | (ImgID & U_FF_MASK_OID8) << U_FF_SHFT_OID8; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_DRAWIMAGE,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {&ImgAttrID, 4, 1, U_LE}, - {&SrcUnit, 4, 1, U_LE}, - {SrcRect->Data, SrcRect->Used, 1, U_XE}, - {DstRect->Data, DstRect->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_DRAWIMAGE_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_DRAWIMAGEPOINTS PseudoObject - \return Pointer to PseudoObject, NULL on error - \param ImgID U_PMF_IMAGE object in the EMF+ object table (0-63, inclusive) - \param etype Set: effect from previous U_PMR_SERIALIZABLEOBJECT record will be applied; Clear: no effect applied - \param ImgAttrID index of a U_PMF_IMAGEATTRIBUTES object in the object table - \param SrcUnit UnitType enumeration - \param SrcRect U_PSEUDO_OBJ containing a U_PMF_RECTF object, Source region of image - \param Points U_PSEUDO_OBJ containing an array of 3 (U_PMF_POINT, U_PMF_POINTF, or U_PMF_POINTF) objects. These points are the UL, UR, and LL vertices of a parallelogram. - - - EMF+ manual 2.3.4.9, Microsoft name: EmfPlusDrawImagePoints Record, Index 0x1B - - - WARNING! Windows XP Preview does not show filter effects, whether or not U_PPF_E is set. They are visible if the EMF+ - file is inserted as an image into PowerPoint. -*/ -U_PSEUDO_OBJ *U_PMR_DRAWIMAGEPOINTS_set(uint32_t ImgID, int etype, - int32_t ImgAttrID, int32_t SrcUnit, const U_PSEUDO_OBJ *SrcRect, - const U_PSEUDO_OBJ *Points){ - int ctype, RelAbs; - if(ImgID>63){ return(NULL); } - if(!SrcRect || (SrcRect->Type != U_PMF_RECTF_OID)){ return(NULL); } - if(Points){ - if( Points->Type == U_PMF_POINTR_OID){ RelAbs = 1; ctype = 0; } - else if(Points->Type == (U_PMF_POINT_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 1; } - else if(Points->Type == (U_PMF_POINTF_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 0; } - else { return(NULL); } - } - else { return(NULL); } - int Size = 2*4 + SrcRect->Used + Points->Used; - uint16_t utmp16 = (ctype ? U_PPF_C : 0) | (etype ? U_PPF_E : 0) | (RelAbs ? U_PPF_P : 0) | (ImgID & U_FF_MASK_OID8) << U_FF_SHFT_OID8; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_DRAWIMAGEPOINTS,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {&ImgAttrID, 4, 1, U_LE}, - {&SrcUnit, 4, 1, U_LE}, - {SrcRect->Data, SrcRect->Used, 1, U_XE}, - {Points->Data, Points->Used, 1, U_XE}, /* includes Elements*/ - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_DRAWIMAGEPOINTS_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_DRAWLINES PseudoObject - \return Pointer to PseudoObject, NULL on error - \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive) - \param dtype Set: path must be closed, Clear: path is open - \param Points U_PSEUDO_OBJ containing an array of 3 U_PMF_POINT, U_PMF_POINTR, or U_PMF_POINTF objects - - - EMF+ manual 2.3.4.10, Microsoft name: EmfPlusDrawLines Record, Index 0x0D -*/ -U_PSEUDO_OBJ *U_PMR_DRAWLINES_set(uint32_t PenID, int dtype, const U_PSEUDO_OBJ *Points){ - int ctype, RelAbs; - if(PenID>63){ return(NULL); } - if(Points){ - if( Points->Type == U_PMF_POINTR_OID){ RelAbs = 1; ctype = 0; } - else if(Points->Type == (U_PMF_POINT_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 1; } - else if(Points->Type == (U_PMF_POINTF_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 0; } - else { return(NULL); } - } - else { return(NULL); } - int Size = Points->Used; - uint16_t utmp16 = (ctype ? U_PPF_C : 0) | (dtype ? U_PPF_D : 0) | (RelAbs ? U_PPF_P : 0) | (PenID & U_FF_MASK_OID8) << U_FF_SHFT_OID8; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_DRAWLINES,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {Points->Data, Points->Used, 1, U_XE}, /* includes Elements */ - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_DRAWLINES_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_DRAWPATH PseudoObject - \return Pointer to PseudoObject, NULL on error - \param PathID U_PMF_PATH object in the EMF+ object table (0-63, inclusive) - \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive) - - - EMF+ manual 2.3.4.11, Microsoft name: EmfPlusDrawPath Record, Index 0x15 -*/ -U_PSEUDO_OBJ *U_PMR_DRAWPATH_set(uint32_t PathID, uint32_t PenID){ - if(PathID>63)return(NULL); - if(PenID>63)return(NULL); - int Size = 4; - uint16_t utmp16 = (PathID & U_FF_MASK_OID8) << U_FF_SHFT_OID8; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_DRAWPATH,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {&PenID, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_DRAWPATH_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_DRAWPIE PseudoObject - \return Pointer to PseudoObject, NULL on error - \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive) - \param Start Start angle, >=0.0, degrees clockwise from 3:00 - \param Sweep Sweep angle, -360<= angle <=360, degrees clockwise from Start - \param Rect U_PSEUDO_OBJ containing a U_PMF_RECT or U_PMF_RECTF object - - - EMF+ manual 2.3.4.12, Microsoft name: EmfPlusDrawPie Record, Index 0x0D -*/ -U_PSEUDO_OBJ *U_PMR_DRAWPIE_set(uint32_t PenID, - U_FLOAT Start, U_FLOAT Sweep, const U_PSEUDO_OBJ *Rect){ - int ctype; - if(PenID>63)return(NULL); - if(!Rect){ return(NULL); } - else { - if( Rect->Type == U_PMF_RECT_OID ){ ctype = 1; } - else if(Rect->Type == U_PMF_RECTF_OID){ ctype = 0; } - else { return(NULL); } - } - int Size = 2*4 + Rect->Used; - uint16_t utmp16 = (ctype ? U_PPF_C : 0) | (PenID & U_FF_MASK_OID8) << U_FF_SHFT_OID8; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_DRAWPIE,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {&Start, 4, 1, U_LE}, - {&Sweep, 4, 1, U_LE}, - {Rect->Data, Rect->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_DRAWPIE_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_DRAWRECTS PseudoObject - \return Pointer to PseudoObject, NULL on error - \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive) - \param Rects U_PSEUDO_OBJ containing 1 rect OR a count N follwed by N rects. Rects may be either U_PMF_RECT or U_PMF_RECTF - - - EMF+ manual 2.3.4.13, Microsoft name: EmfPlusDrawRects Record, Index 0x0B -*/ -U_PSEUDO_OBJ *U_PMR_DRAWRECTS_set(uint32_t PenID, const U_PSEUDO_OBJ *Rects){ - int ctype; - int just1; - uint32_t Elements=1; /* only used when a single rect is passed in, not an array, not even an array with one member*/ - if(PenID>63){ return(NULL); } - if(Rects){ - if( (Rects->Type & U_PMF_MASK_OID) == U_PMF_RECT_OID ){ ctype = 1; } - else if( (Rects->Type & U_PMF_MASK_OID) == U_PMF_RECTF_OID){ ctype = 0; } - else { return(NULL); } - } - else { return(NULL); } - just1 = (Rects->Type & U_PMF_ARRAY_OID ? 0 : 1); - int Size = Rects->Used + (just1 ? 4 : 0); /* Elements in Rects for array, not for single */ - uint16_t utmp16 = (ctype ? U_PPF_C : 0)| (PenID & U_FF_MASK_OID8) << U_FF_SHFT_OID8; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_DRAWRECTS,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {(just1 ? (char *)&Elements : NULL), (just1 ? 4: 0), 1, U_LE}, /* element count if a single Rect was passed in, empty otherwise */ - {Rects->Data, Rects->Used, 1, U_XE}, /* Elements + Array, already stored in Rects, if an array was passed in, just rect if a single */ - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_DRAWRECTS_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_DRAWSTRING PseudoObject - \return Pointer to PseudoObject, NULL on error - \param FontID U_PMF_FONT object in the EMF+ object table (0-63, inclusive) - \param BrushID U_PSEUDO_OBJ containing a U_PMF_ARGB or a U_PMF_4NUM. Color or U_PMF_BRUSH object in the EMF+ object table (0-63, inclusive) - \param FormatID U_PMF_STRINGFORMAT object in EMF+ Object Table. - \param Length Number of characters in the string. - \param Rect U_PSEUDO_OBJ containing a U_PMF_RECTF object, string's bounding box - \param Text Array of UFT-16LE unicode characters. - - - EMF+ manual 2.3.4.14, Microsoft name: EmfPlusDrawString Record, Index 0x1C -*/ -U_PSEUDO_OBJ *U_PMR_DRAWSTRING_set(uint32_t FontID, const U_PSEUDO_OBJ *BrushID, - uint32_t FormatID, uint32_t Length, const U_PSEUDO_OBJ *Rect, const uint16_t *Text){ - int btype; - if(FontID>63){ return(NULL); } - if(!Length){ return(NULL); } - else if (!Text){ return(NULL); } - if(!Rect || Rect->Type != U_PMF_RECTF_OID){ return(NULL); } - if(BrushID){ - if( BrushID->Used != 4){ return(NULL); } - else if( BrushID->Type == U_PMF_ARGB_OID){ btype = 1; } - else if( BrushID->Type == U_PMF_4NUM_OID){ btype = 0; } - else { return(NULL); } - } - else { return(NULL); } - int Size = BrushID->Used + 2*4 + Rect->Used +2*Length; - uint16_t utmp16 = (btype ? U_PPF_B : 0)| (FontID & U_FF_MASK_OID8) << U_FF_SHFT_OID8; - uint32_t pad = (0x1 & Length ? 2 : 0); - Size+=pad; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_DRAWSTRING,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {BrushID->Data, BrushID->Used, 1, U_XE}, - {&FormatID, 4, 1, U_LE}, - {&Length, 4, 1, U_LE}, - {Rect->Data, Rect->Used, 1, U_XE}, - {Text, 2*Length, 1, U_XE}, - {NULL, pad, (pad ? 1 : 0), (pad ? U_XE : U_XX)}, /* Entire record must be a multiple of 4 */ - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_DRAWSTRING_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_FILLCLOSEDCURVE PseudoObject - \return Pointer to PseudoObject, NULL on error - \param ftype If U_WINDING use winding fill, else use fill - \param BrushID U_PSEUDO_OBJ containing a U_PMF_ARGB or a U_PMF_4NUM. Color or U_PMF_BRUSH object in the EMF+ object table (0-63, inclusive) - \param Tension Controls splines, 0 is straight line, >0 is curved - \param Points U_PSEUDO_OBJ containing a U_PMF_POINT, U_PMF_POINTR or U_PMF_POINTF object - - - EMF+ manual 2.3.4.15, Microsoft name: EmfPlusFillClosedCurve Record, Index 0x16 -*/ -U_PSEUDO_OBJ *U_PMR_FILLCLOSEDCURVE_set(int ftype, U_FLOAT Tension, const U_PSEUDO_OBJ *BrushID, const U_PSEUDO_OBJ *Points){ - int btype, ctype, RelAbs; - int Size=0; - if(BrushID){ - if( BrushID->Used != 4){ return(NULL); } - else if( BrushID->Type == U_PMF_ARGB_OID){ btype = 1; } - else if( BrushID->Type == U_PMF_4NUM_OID){ btype = 0; } - else { return(NULL); } - } - else { return(NULL); } - if(Points){ - if( Points->Type == U_PMF_POINTR_OID){ RelAbs = 1; ctype = 0; } - else if(Points->Type == (U_PMF_POINT_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 1; } - else if(Points->Type == (U_PMF_POINTF_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 0; } - else { return(NULL); } - } - else { return(NULL); } - Size = BrushID->Used + 4 + Points->Used; - uint16_t utmp16 = (btype ? U_PPF_B : 0) | (ctype ? U_PPF_C : 0) |((ftype == U_WINDING) ? U_PPF_F : 0) |(RelAbs ? U_PPF_P : 0); - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_FILLCLOSEDCURVE,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {BrushID->Data, BrushID->Used, 1, U_XE}, - {&Tension, 4, 1, U_LE}, - {Points->Data, Points->Used, 1, U_XE}, /* includes Elements */ - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_FILLCLOSEDCURVE_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_FILLELLIPSE PseudoObject - \return Pointer to PseudoObject, NULL on error - \param BrushID U_PSEUDO_OBJ containing a U_PMF_ARGB or a U_PMF_4NUM. Color or U_PMF_BRUSH object in the EMF+ object table (0-63, inclusive) - \param Rect U_PSEUDO_OBJ containing a U_PMF_RECT or U_PMF_RECTF object - - - EMF+ manual 2.3.4.16, Microsoft name: EmfPlusFillEllipse Record, Index 0x0E -*/ -U_PSEUDO_OBJ *U_PMR_FILLELLIPSE_set(const U_PSEUDO_OBJ *BrushID, const U_PSEUDO_OBJ *Rect){ - int btype, ctype; - if(BrushID){ - if( BrushID->Used != 4){ return(NULL); } - else if( BrushID->Type == U_PMF_ARGB_OID){ btype = 1; } - else if( BrushID->Type == U_PMF_4NUM_OID){ btype = 0; } - else { return(NULL); } - } - else { return(NULL); } - if(Rect){ - if( Rect->Type == U_PMF_RECT_OID ){ ctype = 1; } - else if(Rect->Type == U_PMF_RECTF_OID){ ctype = 0; } - else { return(NULL); } - } - else { return(NULL); } - int Size = BrushID->Used + Rect->Used; - uint16_t utmp16 = (btype ? U_PPF_B : 0) | (ctype ? U_PPF_C : 0); - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_FILLELLIPSE,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {BrushID->Data, BrushID->Used, 1, U_XE}, - {Rect->Data, Rect->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_FILLELLIPSE_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_FILLPATH PseudoObject - \return Pointer to PseudoObject, NULL on error - \param PathID U_PMF_PATH object in the EMF+ object table (0-63, inclusive) - \param BrushID U_PSEUDO_OBJ containing a U_PMF_ARGB or a U_PMF_4NUM. Color or U_PMF_BRUSH object in the EMF+ object table (0-63, inclusive) - - - EMF+ manual 2.3.4.17, Microsoft name: EmfPlusFillPath Record, Index 0x14 -*/ -U_PSEUDO_OBJ *U_PMR_FILLPATH_set(uint32_t PathID, const U_PSEUDO_OBJ *BrushID){ - int btype; - int Size=0; - if(PathID>63)return(NULL); - if(BrushID){ - if( BrushID->Used != 4){ return(NULL); } - else if( BrushID->Type == U_PMF_ARGB_OID){ btype = 1; } - else if( BrushID->Type == U_PMF_4NUM_OID){ btype = 0; } - else { return(NULL); } - } - else { return(NULL); } - Size = BrushID->Used; - uint16_t utmp16 = (btype ? U_PPF_B : 0) | (PathID & U_FF_MASK_OID8) << U_FF_SHFT_OID8 ; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_FILLPATH,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {BrushID->Data, BrushID->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_FILLPATH_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_FILLPIE PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Start Start angle, >=0.0, degrees clockwise from 3:00 - \param Sweep Sweep angle, -360<= angle <=360, degrees clockwise from Start - \param BrushID U_PSEUDO_OBJ containing a U_PMF_ARGB or a U_PMF_4NUM. Color or U_PMF_BRUSH object in the EMF+ object table (0-63, inclusive) - \param Rect U_PSEUDO_OBJ containing a U_PMF_RECT or U_PMF_RECTF object - - - EMF+ manual 2.3.4.18, Microsoft name: EmfPlusFillPie Record, Index 0x10 -*/ -U_PSEUDO_OBJ *U_PMR_FILLPIE_set(U_FLOAT Start, U_FLOAT Sweep, const U_PSEUDO_OBJ *BrushID, const U_PSEUDO_OBJ *Rect){ - int btype, ctype; - if(BrushID){ - if( BrushID->Used != 4){ return(NULL); } - else if( BrushID->Type == U_PMF_ARGB_OID){ btype = 1; } - else if( BrushID->Type == U_PMF_4NUM_OID){ btype = 0; } - else { return(NULL); } - } - else { return(NULL); } - if(!Rect){ return(NULL); } - else { - if( Rect->Type == U_PMF_RECT_OID ){ ctype = 1; } - else if(Rect->Type == U_PMF_RECTF_OID){ ctype = 0; } - else { return(NULL); } - } - int Size = BrushID->Used + 2*4 + Rect->Used; - uint16_t utmp16 = (btype ? U_PPF_B : 0) | (ctype ? U_PPF_C : 0); - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_FILLPIE,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {BrushID->Data, BrushID->Used, 1, U_XE}, - {&Start, 4, 1, U_LE}, - {&Sweep, 4, 1, U_LE}, - {Rect->Data, Rect->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_FILLPIE_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_FILLPOLYGON PseudoObject - \return Pointer to PseudoObject, NULL on error - \param BrushID U_PSEUDO_OBJ containing a U_PMF_ARGB or a U_PMF_4NUM. Color or U_PMF_BRUSH object in the EMF+ object table (0-63, inclusive) - \param Points U_PSEUDO_OBJ containing an array of 3 U_PMF_POINT, U_PMF_POINTR, or U_PMF_POINTF objects - - - EMF+ manual 2.3.4.19, Microsoft name: EmfPlusFillPolygon Record, Index 0x0C -*/ -U_PSEUDO_OBJ *U_PMR_FILLPOLYGON_set(const U_PSEUDO_OBJ *BrushID, const U_PSEUDO_OBJ *Points){ - int btype, ctype, RelAbs; - if(BrushID){ - if( BrushID->Used != 4){ return(NULL); } - else if( BrushID->Type == U_PMF_ARGB_OID){ btype = 1; } - else if( BrushID->Type == U_PMF_4NUM_OID){ btype = 0; } - else { return(NULL); } - } - else { return(NULL); } - if(Points){ - if( Points->Type == U_PMF_POINTR_OID){ RelAbs = 1; ctype = 0; } - else if(Points->Type == (U_PMF_POINT_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 1; } - else if(Points->Type == (U_PMF_POINTF_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 0; } - else { return(NULL); } - } - else { return(NULL); } - int Size = BrushID->Used + Points->Used; - uint16_t utmp16 = (btype ? U_PPF_B : 0) | (ctype ? U_PPF_C : 0) |(RelAbs ? U_PPF_P : 0); - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_FILLPOLYGON,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {BrushID->Data, BrushID->Used, 1, U_XE}, - {Points->Data, Points->Used, 1, U_XE}, /* includes Elements */ - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_FILLPOLYGON_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_FILLRECTS PseudoObject - \return Pointer to PseudoObject, NULL on error - \param BrushID U_PSEUDO_OBJ containing a U_PMF_ARGB or a U_PMF_4NUM. Color or U_PMF_BRUSH object in the EMF+ object table (0-63, inclusive) - \param Rects U_PSEUDO_OBJ containing 1 rect OR a count N followed by N rects. Rects may be either U_PMF_RECT or U_PMF_RECTF - - - EMF+ manual 2.3.4.20, Microsoft name: EmfPlusFillRects Record, Index 0x0A -*/ -U_PSEUDO_OBJ *U_PMR_FILLRECTS_set(const U_PSEUDO_OBJ *BrushID, const U_PSEUDO_OBJ *Rects){ - int btype, ctype; - int just1; - uint32_t Elements=1; /* only used when a single rect is passed in, not an array, not even an array with one member*/ - if(BrushID){ - if( BrushID->Used != 4){ return(NULL); } - else if( BrushID->Type == U_PMF_ARGB_OID){ btype = 1; } - else if( BrushID->Type == U_PMF_4NUM_OID){ btype = 0; } - else { return(NULL); } - } - else { return(NULL); } - if(Rects){ - if( (Rects->Type & U_PMF_MASK_OID) == U_PMF_RECT_OID ){ ctype = 1; } - else if( (Rects->Type & U_PMF_MASK_OID) == U_PMF_RECTF_OID){ ctype = 0; } - else { return(NULL); } - } - else { return(NULL); } - just1 = (Rects->Type & U_PMF_ARRAY_OID ? 0 : 1); - int Size = BrushID->Used + Rects->Used + (just1 ? 4 : 0); /* Elements in Rects for array, not for single */ - uint16_t utmp16 = (btype ? U_PPF_B : 0)|(ctype ? U_PPF_C : 0); - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_FILLRECTS,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {BrushID->Data, BrushID->Used, 1, U_XE}, - {(just1 ? (char *)&Elements : NULL), (just1 ? 4: 0), 1, U_LE}, /* element count if a single Rect was passed in, empty otherwise */ - {Rects->Data, Rects->Used, 1, U_XE}, /* Elements + Array, already stored in Rects, if an array was passed in, just rect if a single */ - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_FILLRECTS_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_FILLREGION PseudoObject - \return Pointer to PseudoObject, NULL on error - \param RgnID U_PMF_REGION object in the EMF+ object table (0-63, inclusive) - \param BrushID U_PSEUDO_OBJ containing a U_PMF_ARGB or a U_PMF_4NUM. Color or U_PMF_BRUSH object in the EMF+ object table (0-63, inclusive) - - - EMF+ manual 2.3.4.21, Microsoft name: EmfPlusFillRegion Record, Index 0x13 -*/ -U_PSEUDO_OBJ *U_PMR_FILLREGION_set(uint32_t RgnID, const U_PSEUDO_OBJ *BrushID){ - int btype; - if(BrushID){ - if( BrushID->Used != 4){ return(NULL); } - else if( BrushID->Type == U_PMF_ARGB_OID){ btype = 1; } - else if( BrushID->Type == U_PMF_4NUM_OID){ btype = 0; } - else { return(NULL); } - } - else { return(NULL); } - int Size = BrushID->Used; - uint16_t utmp16 = (btype ? U_PPF_B : 0) | (RgnID & U_FF_MASK_OID8) << U_FF_SHFT_OID8; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_FILLREGION,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {BrushID->Data, BrushID->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_FILLREGION_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_OBJECT PseudoObject from another PseudoObject - \return Pointer to PseudoObject, NULL on error - \param ObjID Index for this object in the EMF+ object table (0-63, inclusive) - \param Po U_PSEUDO_OBJ containing an object type that may be stored in the EMF+ object table -*/ -U_PSEUDO_OBJ *U_PMR_OBJECT_PO_set(uint32_t ObjID, U_PSEUDO_OBJ *Po){ - if(!Po){ return(NULL); } - int otype = U_OID_To_OT(Po->Type); /* This will return 0 if the type is not valid for an object */ - if(!otype){ return(NULL); } - U_PSEUDO_OBJ *po = U_PMR_OBJECT_set(ObjID, otype, 0, 0, Po->Used, Po->Data); /* 0,0 = rec. not continued, TSize value (ignored) */ - return(po); -} - -/** - \brief Create and set a U_PMR_OBJECT PseudoObject - \return Pointer to PseudoObject, NULL on error - \param ObjID Index for this object in the EMF+ object table (0-63, inclusive) - \param otype ObjectType enumeration for this Object - \param ntype Set: object definition continues in next record; Clear: this is the sole object definition record - \param TSize If ntype is set the total number of data bytes split across multiple records. If ntype is clear, it is ignored. - \param cbData Object's data size, in bytes. - \param Data Object's data. Type from otype. - - - EMF+ manual 2.3.5.1, Microsoft name: EmfPlusObject Record, Index 0x13 - - Normally this is only called by U_PMR_OBJECT_PO_set(). - - U_PMR_OBJECT records can only hold a maximum of 65020 bytes of data. If the object is larger than that - then multiple U_PMR_OBJECT records are created, one after the other. If this - happens each record has cbData following ph, and the ntype flag is set. If all of the data is less than 65020 - then cbData is NOT entered following ph, and the ntype flag is clear. - - Call initially in all cases with ntype clear and TSize = 0. If the record needs to be fragmented - the function will call itself recursively to do so. - -*/ -U_PSEUDO_OBJ *U_PMR_OBJECT_set(uint32_t ObjID, int otype, int ntype, uint32_t TSize, size_t cbData, const char *Data){ - uint32_t CSize; - int Pad = UP4(TSize) - TSize; - if((otype < U_OT_Brush) || (otype > U_OT_CustomLineCap)){ return(NULL); } - if(ntype && (cbData > U_OBJRECLIM)){ return(NULL); } - if(!Data || !cbData){ return(NULL); } - U_PSEUDO_OBJ *po; - - if(!ntype && !TSize && (cbData > U_OBJRECLIM)){ - ntype = 1; - TSize = cbData; - po = U_PO_create(NULL, TSize + 16 * (1 + (TSize/cbData)), 0, U_PMR_OBJECT_OID); - if(po){ - while(cbData){ - CSize = (cbData > U_OBJRECLIM ? U_OBJRECLIM : cbData); - U_PSEUDO_OBJ *pot = U_PMR_OBJECT_set(ObjID, otype, ntype, TSize, CSize, Data); - if(!pot)break; - U_PSEUDO_OBJ *newpo = U_PO_po_append(po, pot, U_PMF_KEEP_ELEMENTS); - U_PO_free(&pot); - if(!newpo)break; - po = newpo; - Data += U_OBJRECLIM; - cbData -= CSize; - } - if(cbData){ /* some error */ - U_PO_free(&po); - } - } - } - else { - /* Send in DataSize, U_PMR_CMN_HDR_set will adjust Header Size with 1-3 pad bytes if needed */ - uint16_t utmp16 = otype << 8 | (ntype ? U_PPF_N : 0) | (ObjID & U_FF_MASK_OID8) << U_FF_SHFT_OID8; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_OBJECT,utmp16,cbData + (ntype ? 4 : 0)); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE }, - {(ntype ? &TSize : NULL), (ntype ? 4 : 0), (ntype ? 1 : 0), U_LE }, - {Data, cbData, 1, U_XE }, - {NULL, (Pad ? Pad : 0), (Pad ? 1 : 0), (Pad ? U_XE : U_XX)}, /* Either 1-3 pad bytes or a terminator */ - {NULL,0,0,U_XX} /* terminator, possibly a second in the list, which is harmless */ - }; - po = U_PMF_SERIAL_set(U_PMR_OBJECT_OID, List); - U_PO_free(&ph); - } - return(po); -} - -/** - \brief Create and set a U_PMR_SERIALIZABLEOBJECT PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Siepb U_PSEUDO_OBJ containing a "Serialized image effects parameter block". One of the ImageEffects objects. - - EMF+ manual 2.3.5.2, Microsoft name: EmfPlusSerializableObject Record, Index 0x38 - - - This sets an ImageEffect in the renderer, which will be applied to the next EmfPlusDrawImagePoints - record that is encountered. The image effect is "consumed" by that EmfPlusDrawImagePoints record, resetting - the renderer to its original state.\n - - WARNING! Windows XP Preview does not show filter effects, whether or not U_PPF_E is set. They are visible if the EMF+ - file is inserted as an image into PowerPoint. - -*/ -U_PSEUDO_OBJ *U_PMR_SERIALIZABLEOBJECT_set(const U_PSEUDO_OBJ *Siepb){ - if(!Siepb){ return(NULL); } - uint8_t *GUID = U_OID_To_GUID(Siepb->Type); - if(!GUID){ return(NULL); } - /* PO Used is size_t, might be 8 bytes, value in record must be 4 bytes */ - uint32_t Used = Siepb->Used; - int Size = 16 + 4 + Siepb->Used; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SERIALIZABLEOBJECT,0,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {GUID, 16, 1, U_XE}, - {&Used, 4, 1, U_LE}, - {Siepb->Data, Siepb->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SERIALIZABLEOBJECT_OID, List); - U_PO_free(&ph); - free(GUID); - return(po); -} - -/** - \brief Create and set a U_PMR_SETANTIALIASMODE PseudoObject - \return Pointer to PseudoObject, NULL on error - \param SMenum SmoothingMode enumeration - \param aatype Set: anti-aliasing on; Clear: anti-aliasing off - - - EMF+ manual 2.3.6.1, Microsoft name: EmfPlusSetAntiAliasMode Record, Index 0x1E -*/ -U_PSEUDO_OBJ *U_PMR_SETANTIALIASMODE_set(int SMenum, int aatype){ - int Size = 0; - uint16_t utmp16 = (aatype ? U_PPF_AA : 0) | (SMenum & U_FF_MASK_AA)<<U_FF_SHFT_AA; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETANTIALIASMODE,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETANTIALIASMODE_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_SETCOMPOSITINGMODE PseudoObject - \return Pointer to PseudoObject, NULL on error - \param CMenum CompositingMode enumeration - - - EMF+ manual 2.3.6.2, Microsoft name: EmfPlusSetCompositingMode Record, Index 0x23 -*/ -U_PSEUDO_OBJ *U_PMR_SETCOMPOSITINGMODE_set(int CMenum){ - int Size = 0; - uint16_t utmp16 = (CMenum & U_FF_MASK_CM)<<U_FF_SHFT_CM; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETCOMPOSITINGMODE,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETCOMPOSITINGMODE_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_SETCOMPOSITINGQUALITY PseudoObject - \return Pointer to PseudoObject, NULL on error - \param CQenum CompositingQuality enumeration - - - EMF+ manual 2.3.6.3, Microsoft name: EmfPlusSetCompositingQuality Record, Index 0x24 -*/ -U_PSEUDO_OBJ *U_PMR_SETCOMPOSITINGQUALITY_set(int CQenum){ - int Size = 0; - uint16_t utmp16 = (CQenum & U_FF_MASK_CQ)<<U_FF_SHFT_CQ; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETCOMPOSITINGQUALITY,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETCOMPOSITINGQUALITY_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_SETINTERPOLATIONMODE PseudoObject - \return Pointer to PseudoObject, NULL on error - \param IMenum InterpolationMode enumeration - - - EMF+ manual 2.3.6.4, Microsoft name: EmfPlusSetInterpolationMode Record, Index 0x21 -*/ -U_PSEUDO_OBJ *U_PMR_SETINTERPOLATIONMODE_set(int IMenum){ - int Size = 0; - uint16_t utmp16 = (IMenum & U_FF_MASK_IM)<<U_FF_SHFT_IM; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETINTERPOLATIONMODE,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETINTERPOLATIONMODE_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_SETPIXELOFFSETMODE PseudoObject - \return Pointer to PseudoObject, NULL on error - \param POMenum PixelOffsetMode enumeration - - - EMF+ manual 2.3.6.5, Microsoft name: EmfPlusSetPixelOffsetMode Record, Index 0x22 -*/ -U_PSEUDO_OBJ *U_PMR_SETPIXELOFFSETMODE_set(int POMenum){ - int Size = 0; - uint16_t utmp16 = (POMenum & U_FF_MASK_PxOffM) << U_FF_SHFT_PxOffM; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETPIXELOFFSETMODE,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETPIXELOFFSETMODE_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_SETRENDERINGORIGIN PseudoObject - \return Pointer to PseudoObject, NULL on error - \param X X coordinate of rendering origin. - \param Y Y coordinate of rendering origin. - - - EMF+ manual 2.3.6.6, Microsoft name: EmfPlusSetRenderingOrigin Record, Index 0x1D -*/ -U_PSEUDO_OBJ *U_PMR_SETRENDERINGORIGIN_set(int32_t X, int32_t Y){ - int Size = 2*4; - uint16_t utmp16 = 0; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETRENDERINGORIGIN,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {&X, 4, 1, U_LE}, - {&Y, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETRENDERINGORIGIN_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_SETTEXTCONTRAST PseudoObject - \return Pointer to PseudoObject, NULL on error - \param TGC Text Gamma correction value (x 1000). - - - EMF+ manual 2.3.6.7, Microsoft name: EmfPlusSetTextContrast Record, Index 0x20 -*/ -U_PSEUDO_OBJ *U_PMR_SETTEXTCONTRAST_set(int TGC){ - int Size = 0; - uint16_t utmp16 = (TGC & U_FF_MASK_TGC) << U_FF_SHFT_TGC; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETTEXTCONTRAST,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETTEXTCONTRAST_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_SETTEXTRENDERINGHINT PseudoObject - \return Pointer to PseudoObject, NULL on error - \param TRHenum TextRenderingHint enumeration - - - EMF+ manual 2.3.6.8, Microsoft name: EmfPlusSetTextRenderingHint Record, Index 0x1F -*/ -U_PSEUDO_OBJ *U_PMR_SETTEXTRENDERINGHINT_set(int TRHenum){ - int Size = 0; - uint16_t utmp16 = (TRHenum & U_FF_MASK_TRH) << U_FF_SHFT_TRH; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETTEXTRENDERINGHINT,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETTEXTRENDERINGHINT_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_BEGINCONTAINER PseudoObject - \return Pointer to PseudoObject, NULL on error - \param UTenum UnitType enumeration - \param DstRect a U_PSEUDO_OBJ containing a U_PMF_RECTF object. with SrcRect specifies a transformation - \param SrcRect a U_PSEUDO_OBJ containing a U_PMF_RECTF object. with DstRect specifies a transformation - \param StackID EMF+ Object Stack Index to use for this graphics container - - - EMF+ manual 2.3.7.1, Microsoft name: EmfPlusBeginContainer Record, Index 0x27 -*/ -U_PSEUDO_OBJ *U_PMR_BEGINCONTAINER_set(int UTenum, U_PSEUDO_OBJ *DstRect, U_PSEUDO_OBJ *SrcRect, uint32_t StackID){ - if(UTenum < U_UT_World || UTenum > U_UT_Millimeter){ return(NULL); } - if(!DstRect || (DstRect->Type != U_PMF_RECTF_OID)){ return(NULL); } - if(!SrcRect || (SrcRect->Type != U_PMF_RECTF_OID)){ return(NULL); } - int Size = DstRect->Used + SrcRect->Used + 4; - uint16_t utmp16 = (UTenum & U_FF_MASK_UT) << U_FF_SHFT_UT; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_BEGINCONTAINER,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {DstRect->Data, DstRect->Used, 1, U_XE}, - {SrcRect->Data, SrcRect->Used, 1, U_XE}, - {&StackID, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_BEGINCONTAINER_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_BEGINCONTAINERNOPARAMS PseudoObject - \return Pointer to PseudoObject, NULL on error - \param StackID EMF+ Object Stack Index to use for this graphics container - - - EMF+ manual 2.3.7.2, Microsoft name: EmfPlusBeginContainerNoParams Record, Index 0x28 -*/ -U_PSEUDO_OBJ *U_PMR_BEGINCONTAINERNOPARAMS_set(int StackID){ - int Size = 4; - uint16_t utmp16 = 0; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_BEGINCONTAINERNOPARAMS,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {&StackID, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_BEGINCONTAINERNOPARAMS_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_ENDCONTAINER PseudoObject - \return Pointer to PseudoObject, NULL on error - \param StackID EMF+ Object Stack Index to use for this graphics container - - - EMF+ manual 2.3.7.3, Microsoft name: EmfPlusEndContainer Record, Index 0x29 -*/ -U_PSEUDO_OBJ *U_PMR_ENDCONTAINER_set(int StackID){ - int Size = 4; - uint16_t utmp16 = 0; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_ENDCONTAINER,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {&StackID, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_ENDCONTAINER_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_RESTORE PseudoObject - \return Pointer to PseudoObject, NULL on error - \param StackID EMF+ Graphics State Stack to restore from. Must have been put on the GSS with a U_PMR_SAVE. - - - EMF+ manual 2.3.7.4, Microsoft name: EmfPlusRestore Record, Index 0x26 -*/ -U_PSEUDO_OBJ *U_PMR_RESTORE_set(int StackID){ - int Size = 4; - uint16_t utmp16 = 0; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_RESTORE,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {&StackID, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_RESTORE_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_SAVE PseudoObject - \return Pointer to PseudoObject, NULL on error - \param StackID EMF+ Graphics State Stack to restore from. Must have been put on the GSS with a U_PMR_SAVE. - - - EMF+ manual 2.3.7.5, Microsoft name: EmfPlusSave Record, Index 0x25 -*/ -U_PSEUDO_OBJ *U_PMR_SAVE_set(int StackID){ - int Size = 4; - uint16_t utmp16 = 0; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SAVE,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {&StackID, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SAVE_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_SETTSCLIP PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Rects a U_PSEUDO_OBJ containing an array of U_PMF_RECT or U_PMF_RECTF objects. - - - EMF+ manual 2.3.8.1, Microsoft name: EmfPlusSetTSClip Record, Index 0x3A -*/ -U_PSEUDO_OBJ *U_PMR_SETTSCLIP_set(U_PSEUDO_OBJ *Rects){ - int ctype; - uint32_t Elements; - if(Rects){ - if( Rects->Type == (U_PMF_RECT_OID | U_PMF_ARRAY_OID)){ ctype = 1; Elements = (Rects->Used - 4)/8; } - else if(Rects->Type == (U_PMF_RECTF_OID | U_PMF_ARRAY_OID)){ ctype = 0; Elements = (Rects->Used - 4)/16; } - else { return(NULL); } - } - else { return(NULL); } - int Size = Rects->Used; /* Rects includes Elements */ - uint16_t utmp16 = (ctype ? U_PPF_K : 0) | (Elements & U_FF_MASK_TSC) << U_FF_SHFT_TSC; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETTSCLIP,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {Rects->Data, Rects->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETTSCLIP_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_SETTSGRAPHICS PseudoObject - \return Pointer to PseudoObject, NULL on error - \param vgatype Set: Palette is VGA basic colors; Clear: Palette is ??? - \param Tsg A U_PMF_SETTSGRAPHICS object - \param Palette (optional) a U_PSEUDO_OBJ containing a U_PMF_PALETTE object. - - - EMF+ manual 2.3.8.2, Microsoft name: EmfPlusSetTSGraphics Record, Index 0x39 -*/ -U_PSEUDO_OBJ *U_PMR_SETTSGRAPHICS_set(int vgatype, U_PMF_SETTSGRAPHICS *Tsg, U_PSEUDO_OBJ *Palette){ - if(!Tsg){ return(NULL); } - int Size = sizeof(U_PMF_SETTSGRAPHICS) + (Palette ? Palette->Used : 0); - uint16_t utmp16 = (vgatype ? U_PPF_VGA : 0) | (Palette ? U_PPF_PP : 0) ; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETTSGRAPHICS,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {&(Tsg->AntiAliasMode), 1, 1, U_XE}, - {&(Tsg->TextRenderHint), 1, 1, U_XE}, - {&(Tsg->CompositingMode), 1, 1, U_XE}, - {&(Tsg->CompositingQuality), 1, 1, U_XE}, - {&(Tsg->RenderOriginX), 2, 1, U_LE}, - {&(Tsg->RenderOriginY), 2, 1, U_LE}, - {&(Tsg->TextContrast), 2, 1, U_LE}, - {&(Tsg->FilterType), 1, 1, U_XE}, - {&(Tsg->PixelOffset), 1, 1, U_XE}, - {&(Tsg->WorldToDevice), 4, 6, U_LE}, - {(Palette ? Palette->Data : NULL), (Palette ? Palette->Used: 0), 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETTSGRAPHICS_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_MULTIPLYWORLDTRANSFORM PseudoObject - \return Pointer to PseudoObject, NULL on error - \param xmtype Set: Post multiply; Clear: Pre multiply - \param Tm a U_PSEUDO_OBJ containing a U_PMF_TRANSFORMMATRIX. (Transformation matrix) - - - EMF+ manual 2.3.9.1, Microsoft name: EmfPlusMultiplyWorldTransform Record, Index 0x2C -*/ -U_PSEUDO_OBJ *U_PMR_MULTIPLYWORLDTRANSFORM_set(int xmtype, U_PSEUDO_OBJ *Tm){ - if(!Tm || (Tm->Type != U_PMF_TRANSFORMMATRIX_OID)){ return(NULL); } - int Size = Tm->Used; - uint16_t utmp16 = (xmtype ? U_PPF_XM : 0); - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_MULTIPLYWORLDTRANSFORM,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {Tm->Data, Tm->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_MULTIPLYWORLDTRANSFORM_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_RESETWORLDTRANSFORM PseudoObject - \return Pointer to PseudoObject, NULL on error - - - EMF+ manual 2.3.9.2, Microsoft name: EmfPlusResetWorldTransform Record, Index 0x2B -*/ -U_PSEUDO_OBJ *U_PMR_RESETWORLDTRANSFORM_set(void){ - int Size = 0; - uint16_t utmp16 = 0; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_RESETWORLDTRANSFORM,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_RESETWORLDTRANSFORM_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_ROTATEWORLDTRANSFORM PseudoObject - \return Pointer to PseudoObject, NULL on error - \param xmtype Set: Post multiply; Clear: Pre multiply - \param Angle Rotation angle, in degrees - - - EMF+ manual 2.3.9.3, Microsoft name: EmfPlusRotateWorldTransform Record, Index 0x2F -*/ -U_PSEUDO_OBJ *U_PMR_ROTATEWORLDTRANSFORM_set(int xmtype, U_FLOAT Angle){ - int Size = 4; - uint16_t utmp16 = (xmtype ? U_PPF_XM : 0); - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_ROTATEWORLDTRANSFORM,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {&Angle, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_ROTATEWORLDTRANSFORM_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_SCALEWORLDTRANSFORM PseudoObject - \return Pointer to PseudoObject, NULL on error - \param xmtype Set: Post multiply; Clear: Pre multiply - \param X Scale in X - \param Y Scale in Y - - EMF+ manual 2.3.9.4, Microsoft name: EmfPlusScaleWorldTransform Record, Index 0x2E -*/ -U_PSEUDO_OBJ *U_PMR_SCALEWORLDTRANSFORM_set(int xmtype, U_FLOAT X, U_FLOAT Y){ - int Size = 2*4; - uint16_t utmp16 = (xmtype ? U_PPF_XM : 0); - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SCALEWORLDTRANSFORM,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {&X, 4, 1, U_LE}, - {&Y, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SCALEWORLDTRANSFORM_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_SETPAGETRANSFORM PseudoObject - \return Pointer to PseudoObject, NULL on error - \param PUenum Page Unit, in UnitType enumeration - \param Scale Scale factor to convert page space to device space - - - - EMF+ manual 2.3.9.5, Microsoft name: EmfPlusSetPageTransform Record, Index 0x30 - - Defines Page Space -> Device Space transformation -*/ -U_PSEUDO_OBJ *U_PMR_SETPAGETRANSFORM_set(int PUenum, U_FLOAT Scale){ - int Size = 4; - uint16_t utmp16 = (PUenum & U_FF_MASK_PU) << U_FF_SHFT_PU; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETPAGETRANSFORM,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {&Scale, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETPAGETRANSFORM_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_SETWORLDTRANSFORM PseudoObject - \return Pointer to PseudoObject, NULL on error - \param Tm a U_PSEUDO_OBJ containing a U_PMF_TRANSFORMMATRIX. (Transformation matrix) - - - - EMF+ manual 2.3.9.6, Microsoft name: EmfPlusSetWorldTransform Record, Index 0x2A - - Defines World Space -> Page Space transformation -*/ -U_PSEUDO_OBJ *U_PMR_SETWORLDTRANSFORM_set(U_PSEUDO_OBJ *Tm){ - if(!Tm || (Tm->Type != U_PMF_TRANSFORMMATRIX_OID)){ return(NULL); } - int Size = Tm->Used; - uint16_t utmp16 = 0; - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETWORLDTRANSFORM,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {Tm->Data, Tm->Used, 1, U_XE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETWORLDTRANSFORM_OID, List); - U_PO_free(&ph); - return(po); -} - -/** - \brief Create and set a U_PMR_TRANSLATEWORLDTRANSFORM PseudoObject - \return Pointer to PseudoObject, NULL on error - \param xmtype Set: Post multiply; Clear: Pre multiply - \param Dx X offset - \param Dy Y offset - - - EMF+ manual 2.3.9.7, Microsoft name: EmfPlusTranslateWorldTransform Record, Index 0x2D -*/ -U_PSEUDO_OBJ *U_PMR_TRANSLATEWORLDTRANSFORM_set(int xmtype, U_FLOAT Dx, U_FLOAT Dy){ - int Size = 2*4; - uint16_t utmp16 = (xmtype ? U_PPF_XM : 0); - U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_TRANSLATEWORLDTRANSFORM,utmp16,Size); - const U_SERIAL_DESC List[] = { - {ph->Data, ph->Used, 1, U_XE}, - {&Dx, 4, 1, U_LE}, - {&Dy, 4, 1, U_LE}, - {NULL,0,0,U_XX} - }; - U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_TRANSLATEWORLDTRANSFORM_OID, List); - U_PO_free(&ph); - return(po); -} - -/* - - end of U_PMF_*_set() functions - ===================================================================================== - start of U_PMF_*_get() functions - - These functions all take a blimit value so that they can check if the data description in the fields - they process extend beyond the end of the record. - -*/ - - -//! \cond -/* core _get functions, not accessed outside of this routine */ - -/* get copies of up to 0-6 consecutive 4 byte values and a pointer to the rest */ -int U_PMF_CORE1_get(const char *contents, void *v1, void *v2, void *v3, void *v4, void *v5, void *v6, const char **vR){ - if(v1){ U_PMF_MEMCPY_SRCSHIFT(v1, &contents, 4); - if(v2){ U_PMF_MEMCPY_SRCSHIFT(v2, &contents, 4); - if(v3){ U_PMF_MEMCPY_SRCSHIFT(v3, &contents, 4); - if(v4){ U_PMF_MEMCPY_SRCSHIFT(v4, &contents, 4); - if(v5){ U_PMF_MEMCPY_SRCSHIFT(v5, &contents, 4); - if(v6){ U_PMF_MEMCPY_SRCSHIFT(v6, &contents, 4); }}}}}} - if(vR){ *vR = contents; } - return(1); -} -//! \endcond - - -/** - \brief Get data from a U_PMF_BRUSH object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Version EmfPlusGraphicsVersion object - \param Type BrushType Enumeration - \param Data one of the 5 types of Brush data - \param blimit one byte past the end of data - - EMF+ manual 2.2.1.1, Microsoft name: EmfPlusBrush Object - - Caller must check Data for possible memory access violations. -*/ -int U_PMF_BRUSH_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **Data, const char *blimit){ - if(!contents || !Version || !Type || !Data || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents,sizeof(U_PMF_BRUSH), blimit))return(0); - U_PMF_SERIAL_get(&contents, Version, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Type, 4, 1, U_LE); - U_PMF_PTRSAV_SHIFT(Data, &contents, 0); - return(1); -} - -/** - \brief Get data from a U_PMF_CUSTOMLINECAP object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Version EmfPlusGraphicsVersion object - \param Type CustomLineCapData Enumeration - \param Data one of the 2 types of Linecap data - \param blimit one byte past the end of data - - EMF+ manual 2.2.1.2, Microsoft name: EmfPlusCustomLineCap Object - - Caller must check Data for possible memory access violations. -*/ -int U_PMF_CUSTOMLINECAP_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **Data, const char *blimit){ - if(!contents || !Version || !Type || !Data || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_CUSTOMLINECAP), blimit))return(0); - U_PMF_SERIAL_get(&contents, Version, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Type, 4, 1, U_LE); - U_PMF_PTRSAV_SHIFT(Data, &contents, 0); - return(1); -} - -/** - \brief Get data from a U_PMF_FONT object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Version EmfPlusGraphicsVersion object - \param EmSize em size in units of SizeUnit - \param SizeUnit UnitType enumeration - \param FSFlags FontStyle flags - \param Length Number of Unicode Characters in FamilyName - \param Data Unicode (UTF-16LE) name of font family - - EMF+ manual 2.2.1.3, Microsoft name: EmfPlusFont Object - - Caller must check Data for possible memory access violations. -*/ -int U_PMF_FONT_get(const char *contents, uint32_t *Version, U_FLOAT *EmSize, uint32_t *SizeUnit, - int32_t *FSFlags, uint32_t *Length, const char **Data, const char *blimit){ - if(!contents || !Version || !EmSize || !SizeUnit || !FSFlags || !Length || !Data || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_FONT), blimit))return(0); - U_PMF_SERIAL_get(&contents, Version, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, EmSize, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, SizeUnit, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, FSFlags, 4, 1, U_LE); - contents += 4; /* Reserved field, which is ignored */ - U_PMF_SERIAL_get(&contents, Length, 4, 1, U_LE); - U_PMF_PTRSAV_SHIFT(Data, &contents, 0); - return(1); -} - - -/** - \brief Get data from a U_PMF_IMAGE object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Version EmfPlusGraphicsVersion object - \param Type ImageDataType Enumeration - \param Data one of the 2 types of image data - - EMF+ manual 2.2.1.4, Microsoft name: EmfPlusImage Object - - Caller must check Data for possible memory access violations. -*/ -int U_PMF_IMAGE_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **Data, const char *blimit){ - if(!contents || !Version || !Type || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IMAGE), blimit))return(0); - U_PMF_SERIAL_get(&contents, Version, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Type, 4, 1, U_LE); - U_PMF_PTRSAV_SHIFT(Data, &contents, 0); - return(1); -} - -/** - \brief Get data from a U_PMF_IMAGEATTRIBUTES object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Version EmfPlusGraphicsVersion object - \param WrapMode WrapMode object - \param ClampColor EmfPlusARGB object - \param ObjectClamp ObjectClamp Identifiers - - EMF+ manual 2.2.1.5, Microsoft name: EmfPlusImageAttributes Object -*/ -int U_PMF_IMAGEATTRIBUTES_get(const char *contents, uint32_t *Version, uint32_t *WrapMode, uint32_t *ClampColor, - uint32_t *ObjectClamp, const char *blimit){ - if(!contents || !Version || !WrapMode || !ClampColor || !ObjectClamp || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IMAGEATTRIBUTES), blimit))return(0); - U_PMF_SERIAL_get(&contents, Version, 4, 1, U_LE); - contents += 4; /* Skip Reserved 1*/ - U_PMF_SERIAL_get(&contents, WrapMode, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, ClampColor, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, ObjectClamp,4, 1, U_LE); - /* Skip Reserved 2*/ - return(1); -} - -/** - \brief Get data from a U_PMF_PATH object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Version EmfPlusGraphicsVersion object - \param Count Number of points and point types in this object - \param Flags PathPoint Flags - \param Points array of points type PMFPointR, PMFPoint, or PMFPointF - \param Types array of U_PMF_PATHPOINTTYPERLE and/or U_PMF_PATHPOINTTYPE - - EMF+ manual 2.2.1.6, Microsoft name: EmfPlusPath Object - - Caller must check Types for possible memory access violations if type can be U_PMF_PATHPOINTTYPERLE. -*/ -int U_PMF_PATH_get(const char *contents, uint32_t *Version, uint32_t *Count, uint16_t *Flags, - const char **Points, const char **Types, const char *blimit){ - if(!contents || !Version || !Count || !Flags || !Points || !Types || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_PATH), blimit))return(0); - U_PMF_SERIAL_get(&contents, Version, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Count, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Flags, 2, 1, U_LE); - contents+=2; /* reserved */ - uint32_t sizeP, sizeT; - if(*Flags & U_PPF_P){ - sizeP = U_PMF_LEN_REL715(contents,*Count); //DEBUG - printf("DEBUG U_PMF_PATH_get count:%d LENREL715:%d\n",*Count,sizeP);fflush(stdout); - } - else if(*Flags & U_PPF_C){ sizeP = *Count * sizeof(U_PMF_POINT); } - else { sizeP = *Count * sizeof(U_PMF_POINTF); } - if(IS_MEM_UNSAFE(contents, sizeP, blimit))return(0); - U_PMF_PTRSAV_SHIFT(Points, &contents, 0); - contents += sizeP; - /* this limit is correct if there are only U_PMF_PATHPOINTTYPE PointTypes, it is a lower bound if - there can also be U_PMF_PATHPOINTTYPERLE */ - sizeT = *Count * sizeof(U_PMF_PATHPOINTTYPE); - if(IS_MEM_UNSAFE(contents, sizeT, blimit))return(0); - U_PMF_PTRSAV_SHIFT(Types, &contents, 0); - return(1); -} - -/** - \brief Get data from a U_PMF_PEN object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Version EmfPlusGraphicsVersion object - \param Type must be zero - \param PenData Pen description - \param Brush Brush Description - - EMF+ manual 2.2.1.7, Microsoft name: EmfPlusPen Object - - Caller must check Brush and PenData for possible memory access violations. -*/ -int U_PMF_PEN_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **PenData, const char **Brush, const char *blimit){ - if(!contents || !Type || !PenData || !Brush || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_PEN), blimit))return(0); - U_PMF_SERIAL_get(&contents, Version, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Type, 4, 1, U_LE); - U_PMF_PTRSAV_SHIFT(PenData, &contents, 0); - *Brush = *PenData + U_PMF_LEN_PENDATA(*PenData); - return(1); -} - -/** - \brief Get data from a U_PMF_REGION object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Version EmfPlusGraphicsVersion object - \param Count Number of CHILD nodes. This is one less than the total number of U_PMF_REGIONNODE objects in Nodes. - \param Nodes Nodes defining region - - EMF+ manual 2.2.1.8, Microsoft name: EmfPlusRegion Object -*/ -int U_PMF_REGION_get(const char *contents, uint32_t *Version, uint32_t *Count, const char **Nodes, const char *blimit){ - if(!contents || !Version || !Count || !Nodes || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_REGION), blimit))return(0); - U_PMF_SERIAL_get(&contents, Version, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Count, 4, 1, U_LE); - U_PMF_PTRSAV_SHIFT(Nodes, &contents, 0); - return(1); -} - -/** - \brief Get data from a U_PMF_STRINGFORMAT object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Sfs pointer to U_PMF_STRINGFORMAT structure, with no variable part - \param Data pointer to variable part - - EMF+ manual 2.2.1.9, Microsoft name: EmfPlusStringFormat Object -*/ -int U_PMF_STRINGFORMAT_get(const char *contents, U_PMF_STRINGFORMAT *Sfs, const char **Data, const char *blimit){ - if(!contents || !Sfs || !Data || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_STRINGFORMAT), blimit))return(0); - U_PMF_SERIAL_get(&contents, Sfs, 4, 15, U_LE); - *Data = contents; - return(1); -} - -/** - \brief Get data from a U_PMF_ARGB object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Blue Blue color (0-255) - \param Green Green color (0-255) - \param Red Red color (0-255) - \param Alpha Alpha (0-255) - - EMF+ manual 2.2.2.1, Microsoft name: EmfPlusARGB Object -*/ -int U_PMF_ARGB_get(const char *contents, uint8_t *Blue, uint8_t *Green, uint8_t *Red, uint8_t *Alpha, const char *blimit){ - if(!contents || !Blue || !Green || !Red || !Alpha || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_ARGB), blimit))return(0); - U_PMF_SERIAL_get(&contents, Blue, 1, 1, U_XE); - U_PMF_SERIAL_get(&contents, Green, 1, 1, U_XE); - U_PMF_SERIAL_get(&contents, Red, 1, 1, U_XE); - U_PMF_SERIAL_get(&contents, Alpha, 1, 1, U_XE); - return(1); -} - -/** - \brief Get data from a U_PMF_BITMAP object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Bs pointer to U_PMF_BITMAP structure, with no variable part - \param Data pointer to variable part - - EMF+ manual 2.2.2.2, Microsoft name: EmfPlusBitmap Object - - Caller must check Data for possible memory access violations. -*/ -int U_PMF_BITMAP_get(const char *contents, U_PMF_BITMAP *Bs, const char **Data, const char *blimit){ - if(!contents || !Bs || !Data || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_BITMAP), blimit))return(0); - U_PMF_SERIAL_get(&contents, Bs, 4, 5, U_LE); // width, height, stride, pixelformat, type - U_PMF_PTRSAV_SHIFT(Data, &contents, 0); // bitmapdata - return(1); -} - -/** - \brief Get data from a U_PMF_BITMAPDATA object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Ps pointer to U_PMF_PALETTE structure, with no variable part - \param Colors Color part of U_PMF_PALETTE object - \param Data An array of bytes, meaning depends on fields in U_PMF_BITMAP object and the PixelFormat enumeration. - - EMF+ manual 2.2.2.3, Microsoft name: EmfPlusBitmapData Object - - Caller must check Data for possible memory access violations. -*/ -int U_PMF_BITMAPDATA_get(const char *contents, U_PMF_PALETTE *Ps, const char **Colors, const char **Data, const char *blimit){ - if(!contents || !Ps || !Colors || !Data || !blimit){ return(0); } - /* this structure is entirely optional */ - if(IS_MEM_UNSAFE(contents, 4*2, blimit))return(0); - U_PMF_SERIAL_get(&contents, Ps, 4, 2, U_LE); - U_PMF_PTRSAV_SHIFT(Colors, &contents, Ps->Elements * sizeof(U_PMF_ARGB)); - /* difficult to know how big the actual bitmap will be, just return the pointer to it untested */ - U_PMF_PTRSAV_SHIFT(Data, &contents, 0); - return(1); -} - -/** - \brief Get data from a U_PMF_BLENDCOLORS object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Elements Number of members in Positions and Colors - \param Positions Caller must free. Pointer to memory holding positions along gradient line. - \param Colors Caller must NOT free memory, Pointer to memory holding colors at positions on gradient line. - - EMF+ manual 2.2.2.4, Microsoft name: EmfPlusBlendColors Object -*/ -int U_PMF_BLENDCOLORS_get(const char *contents, uint32_t *Elements, U_FLOAT **Positions, const char **Colors, const char *blimit){ - if(!contents || !Positions || !Colors || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_BLENDCOLORS), blimit))return(0); - U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); - if(IS_MEM_UNSAFE(contents, *Elements * 4, blimit))return(0); - if(!U_PMF_SERIAL_array_copy_get(&contents, (void **)Positions, 4, *Elements, U_LE,1)){ return(0); } - U_PMF_PTRSAV_SHIFT(Colors, &contents, 0); - return(1); -} - -/** - \brief Get data from a U_PMF_BLENDFACTORS object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Elements members in each array - \param Positions Caller must free. Pointer to memory holding positions along gradient line. - \param Factors Caller must free. Pointer to memory holding blending factors, 0.0->1.0 values, inclusive along gradient line. - - EMF+ manual 2.2.2.5, Microsoft name: EmfPlusBlendFactors Object -*/ -int U_PMF_BLENDFACTORS_get(const char *contents, uint32_t *Elements, U_FLOAT **Positions, U_FLOAT **Factors, const char *blimit){ - if(!contents || !Elements || !Positions || !Factors || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_BLENDFACTORS), blimit))return(0); - U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); - if(IS_MEM_UNSAFE(contents, *Elements * 4 * 2, blimit))return(0); - if(!U_PMF_SERIAL_array_copy_get(&contents, (void **)Positions, 4, *Elements, U_LE, 1)){ return(0); } - if(!U_PMF_SERIAL_array_copy_get(&contents, (void **)Factors, 4, *Elements, U_LE, 1)){ - free(*Positions); - return(0); - } - return(1); -} - -/** - \brief Get data from a U_PMF_BOUNDARYPATHDATA object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Size bytes in Data - \param Data boundary of the brush - - EMF+ manual 2.2.2.6, Microsoft name: EmfPlusBoundaryPathData Object - - Caller must check Data for possible memory access violations. -*/ -int U_PMF_BOUNDARYPATHDATA_get(const char *contents, int32_t *Size, const char **Data, const char *blimit){ - if(!contents || !Size || !Data || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_BOUNDARYPATHDATA), blimit))return(0); - U_PMF_SERIAL_get(&contents, Size, 4, 1, U_LE); - U_PMF_PTRSAV_SHIFT(Data, &contents, 0); - return(1); -} - -/** - \brief Get data from a U_PMF_BOUNDARYPOINTDATA object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Elements Members in Points - \param Points Caller must free. Pointer to memory holding points along gradient line. Boundary of the brush. - - EMF+ manual 2.2.2.7, Microsoft name: EmfPlusBoundaryPointData Object -*/ -int U_PMF_BOUNDARYPOINTDATA_get(const char *contents, int32_t *Elements, U_PMF_POINTF **Points, const char *blimit){ - if(!contents || !Elements || !Points || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_BOUNDARYPOINTDATA), blimit))return(0); - U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); - if(IS_MEM_UNSAFE(contents, *Elements * 2, blimit))return(0); - if(!U_PMF_SERIAL_array_copy_get(&contents, (void **)Points, 4, *Elements * 2, U_LE, 1)){ return(0); } - return(1); -} - -/** - \brief Get data from a U_PMF_CHARACTERRANGE object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param First First position in range - \param Length Range length - - EMF+ manual 2.2.2.8, Microsoft name: EmfPlusCharacterRange Object -*/ -int U_PMF_CHARACTERRANGE_get(const char *contents, int32_t *First, int32_t *Length, const char *blimit){ - if(!contents || !First || !Length || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_CHARACTERRANGE), blimit))return(0); - U_PMF_SERIAL_get(&contents, First, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Length, 4, 1, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMF_COMPOUNDLINEDATA object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Elements Members in the array - \param Widths Caller must free. Pointer to memory holding Line or gap widths (0.0 <-> 1.0, fraction of total line width ). - - EMF+ manual 2.2.2.9, Microsoft name: EmfPlusCompoundLineData Object -*/ -int U_PMF_COMPOUNDLINEDATA_get(const char *contents, int32_t *Elements, U_FLOAT **Widths, const char *blimit){ - if(!contents || !Elements || !Widths || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_COMPOUNDLINEDATA), blimit))return(0); - U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); - if(IS_MEM_UNSAFE(contents, *Elements * sizeof(U_FLOAT), blimit))return(0); - *Widths = (U_FLOAT *)malloc(*Elements * sizeof(U_FLOAT)); - if(!*Widths){ return(0); } - U_PMF_SERIAL_get(&contents, *Widths, 4, *Elements, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMF_COMPRESSEDIMAGE object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Data Stored image in one of the supported formats. - - EMF+ manual 2.2.2.10, Microsoft name: EmfPlusCompressedImage Object - - - This function does not do anything useful, but it is included so that all objects have a corresponding _get(). - - Caller must check Data for possible memory access violations. -*/ -int U_PMF_COMPRESSEDIMAGE_get(const char *contents, const char **Data, const char *blimit){ - if(!contents || !Data || !blimit){ return(0); } - if(contents >= blimit)return(0); - U_PMF_PTRSAV_SHIFT(Data, &contents, 0); - return(1); -} - -/** - \brief Get data from a U_PMF_CUSTOMENDCAPDATA object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Size Bytes in Data - \param Data Description of linecap - - EMF+ manual 2.2.2.11, Microsoft name: EmfPlusCustomEndCapData Object - - Caller must check Data for possible memory access violations. -*/ -int U_PMF_CUSTOMENDCAPDATA_get(const char *contents, int32_t *Size, const char **Data, const char *blimit){ - if(!contents || !Size || !Data || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_CUSTOMENDCAPDATA), blimit))return(0); - U_PMF_SERIAL_get(&contents, Size, 4, 1, U_LE); - U_PMF_PTRSAV_SHIFT(Data, &contents, 0); - return(1); -} - -/** - \brief Get data from a U_PMF_CUSTOMLINECAPARROWDATA object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Ccad pointer to U_PMF_CUSTOMLINECAPARROWDATA structure - - EMF+ manual 2.2.2.12, Microsoft name: EmfPlusCustomLineCapArrowData Object -*/ -int U_PMF_CUSTOMLINECAPARROWDATA_get(const char *contents, U_PMF_CUSTOMLINECAPARROWDATA *Ccad, const char *blimit){ - if(!contents || !Ccad || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_CUSTOMLINECAPARROWDATA), blimit))return(0); - U_PMF_SERIAL_get(&contents, Ccad, 4, 13, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMF_CUSTOMLINECAPDATA object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Clcd pointer to U_PMF_CUSTOMLINECAPDATA structure, with no variable part - \param Data variable part of U_PMF_CUSTOMLINECAPDATA - - EMF+ manual 2.2.2.13, Microsoft name: EmfPlusCustomLineCapData Object - - Caller must check Data for possible memory access violations. -*/ -int U_PMF_CUSTOMLINECAPDATA_get(const char *contents, U_PMF_CUSTOMLINECAPDATA *Clcd, const char **Data, const char *blimit){ - if(!contents || !Clcd || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_CUSTOMLINECAPDATA), blimit))return(0); - U_PMF_SERIAL_get(&contents, Clcd, 4, 12, U_LE); - U_PMF_PTRSAV_SHIFT(Data, &contents, 0); - return(1); -} - -/** - \brief Get data from a U_PMF_CUSTOMLINECAPOPTIONALDATA object - \return on success 3,5, or 7 (for varying combinations of data present) or 1 (no data is present), 0 on error - \param contents Record from which to extract data - \param Flags bits set to indicate the presence of FillData and/or LineData - \param FillData Path to fill (optional) - \param LineData Path to stroke (optional) - - EMF+ manual 2.2.2.14, Microsoft name: EmfPlusCustomLineCapOptionalData Object - - Caller must check LineData for possible memory access violations. -*/ -int U_PMF_CUSTOMLINECAPOPTIONALDATA_get(const char *contents, uint32_t Flags, const char **FillData, const char **LineData, const char *blimit){ - uint32_t length; - int status = 1; - if(!contents || !*FillData || !*LineData || !blimit){ return(0); } - /* this structure is entirely optional */ - if(Flags & U_CLCD_FillPath){ - if(!FillData){ return(0); } - if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); - U_PMF_SERIAL_get(&contents, &length, 4, 1, U_LE); - if(IS_MEM_UNSAFE(contents, length, blimit))return(0); - contents -= 4; /* undo the unneeded shift from preceding */ - U_PMF_PTRSAV_SHIFT(FillData, &contents, 4 + length); - status += 2; - } - else { *FillData = NULL; } - - if(Flags & U_CLCD_LinePath){ - if(!LineData){ return(0); } - if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); - U_PMF_SERIAL_get(&contents, &length, 4, 1, U_LE); - if(IS_MEM_UNSAFE(contents, length, blimit))return(0); - contents -= 4; /* undo the unneeded shift from preceding */ - U_PMF_PTRSAV_SHIFT(LineData, &contents, 0); - status += 4; - } - else { *LineData = NULL; } - return(status); -} - -/** - \brief Get data from a U_PMF_CUSTOMSTARTCAPDATA object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Size Bytes in Data - \param Data Description of linecap - - EMF+ manual 2.2.2.15, Microsoft name: EmfPlusCustomStartCapData Object - - Caller must check Data for possible memory access violations. -*/ -int U_PMF_CUSTOMSTARTCAPDATA_get(const char *contents, int32_t *Size, const char **Data, const char *blimit){ - if(!contents || !Size || !Data || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_CUSTOMSTARTCAPDATA), blimit))return(0); - U_PMF_SERIAL_get(&contents, Size, 4, 1, U_LE); - U_PMF_PTRSAV_SHIFT(Data, &contents, 0); - return(1); -} - -/** - \brief Get data from a U_PMF_DASHEDLINEDATA object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Elements Members in the array - \param Lengths Caller must free. Pointer to memory holding lengths of dashes and spaces. - - EMF+ manual 2.2.2.16, Microsoft name: EmfPlusDashedLineData Object -*/ -int U_PMF_DASHEDLINEDATA_get(const char *contents, int32_t *Elements, U_FLOAT **Lengths, const char *blimit){ - if(!contents || !Elements || !Lengths || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_DASHEDLINEDATA), blimit))return(0); - U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); - if(IS_MEM_UNSAFE(contents, *Elements * sizeof(U_FLOAT), blimit))return(0); - *Lengths = (U_FLOAT *)malloc(*Elements * sizeof(U_FLOAT)); - if(!*Lengths){ return(0); } - U_PMF_SERIAL_get(&contents, *Lengths, 4, *Elements, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMF_FILLPATHOBJ object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Size Bytes in Data - \param Data Path specification - - EMF+ manual 2.2.2.17, Microsoft name: EmfPlusFillPath Object - - Caller must check Data for possible memory access violations. -*/ -int U_PMF_FILLPATHOBJ_get(const char *contents, int32_t *Size, const char **Data, const char *blimit){ - if(!contents || !Size || !Data || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_FILLPATHO), blimit))return(0); - U_PMF_SERIAL_get(&contents, Size, 4, 1, U_LE); - U_PMF_PTRSAV_SHIFT(Data, &contents, 0); - return(1); -} - -/** - \brief Get data from a U_PMF_FOCUSSCALEDATA object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Count must be 2 - \param ScaleX value 0.0 <-> 1.0 - \param ScaleY value 0.0 <-> 1.0 - - EMF+ manual 2.2.2.18, Microsoft name: EmfPlusFocusScaleData Object -*/ -int U_PMF_FOCUSSCALEDATA_get(const char *contents, uint32_t *Count, U_FLOAT *ScaleX, U_FLOAT *ScaleY, const char *blimit){ - if(!contents || !Count || !ScaleX || !ScaleY || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_FOCUSSCALEDATA), blimit))return(0); - U_PMF_SERIAL_get(&contents, Count, 4, 1, U_LE); - if(*Count != 2){ return(0); } - U_PMF_SERIAL_get(&contents, ScaleX, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, ScaleY, 4, 1, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMF_GRAPHICSVERSION object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Signature Must be U_GFVR_PMF (0xDBC01) - \param GrfVersion GraphicsVersion enumeration - - EMF+ manual 2.2.2.19, Microsoft name: EmfPlusGraphicsVersion Object -*/ -int U_PMF_GRAPHICSVERSION_get(const char *contents, int *Signature, int *GrfVersion, const char *blimit){ - uint32_t tmp; - if(!contents || !Signature || !GrfVersion || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_GRAPHICSVERSION), blimit))return(0); - memcpy(&tmp, contents, 4); - *Signature = tmp >> 12; - *GrfVersion = tmp & U_GFVR_MASKLO; - return(1); -} - -/** - \brief Get data from a U_PMF_HATCHBRUSHDATA object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Style HatchStyle enumeration - \param Foreground Hatch pattern line color - \param Background Hatch pattern bkground color - - EMF+ manual 2.2.2.20, Microsoft name: EmfPlusHatchBrushData Object -*/ -int U_PMF_HATCHBRUSHDATA_get(const char *contents, uint32_t *Style, U_PMF_ARGB *Foreground, U_PMF_ARGB *Background, const char *blimit){ - if(!contents || !Style || !Foreground || !Background || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_HATCHBRUSHDATA), blimit))return(0); - U_PMF_SERIAL_get(&contents, Style, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Foreground, 4, 1, U_XE); - U_PMF_SERIAL_get(&contents, Background, 4, 1, U_XE); - return(1); -} - -/** - \brief Get data from a U_PMF_INTEGER7 object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Value 7 bit signed integer (stored in an integer) - \param blimit one byte past the end of data - - EMF+ manual 2.2.2.21, Microsoft name: EmfPlusInteger7 Object -*/ -int U_PMF_INTEGER7_get(const char **contents, U_FLOAT *Value, const char *blimit){ - uint8_t tmp; - if(!contents || !*contents || !Value || !blimit){ return(0); } - if(IS_MEM_UNSAFE(*contents, 1, blimit))return(0); /* past end of buffer */ - if(**contents & U_TEST_INT7)return(0); /* this bit must be 0 in this object type */ - U_PMF_SERIAL_get(contents, &tmp, 1, 1, U_XE); - if(tmp & U_SIGN_INT7){ - tmp |= U_TEST_INT7; /* now it has the bit pattern of a signed int8_t */ - *Value = *(int8_t *)&tmp; - } - else { - *Value = tmp; - } - return(1); -} - -/** - \brief Get data from a U_PMF_INTEGER15 object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Value 15 bit signed integer (stored in an integer) - \param blimit one byte past the end of data - - EMF+ manual 2.2.2.22, Microsoft name: EmfPlusInteger15 Object -*/ -int U_PMF_INTEGER15_get(const char **contents, U_FLOAT *Value, const char *blimit){ - if(!contents || !*contents || !Value || !blimit){ return(0); } - uint16_t tmp; - if(IS_MEM_UNSAFE(*contents, 2, blimit))return(0); /* past end of buffer */ - if(!(**contents & U_TEST_INT7))return(0); /* this bit must be 1 in this object type */ - U_PMF_SERIAL_get(contents, &tmp, 2, 1, U_BE); - tmp &= U_MASK_INT15; /* drop the 7/15 flag from the most significant bit */ - if(tmp & U_SIGN_INT15){ - tmp |= U_TEST_INT15; /* now it has the bit pattern of a signed int16_t */ - *Value = *(int16_t *)&tmp; - } - else { - *Value = tmp; - } - return(1); -} - -/** - \brief Get data from a U_PMF_LANGUAGEIDENTIFIER object - \return 1 on success, 0 on error - \param LId U_PMF_LANGUAGEIDENTIFIER from which to extract data - \param SubLId Example: code for USA - \param PriLId Example: code for English - - - - EMF+ manual 2.2.2.23, Microsoft name: EmfPlusLanguageIdentifier Object - - This type is defined as 16 bits in the manual section, but it is only ever used as part of a 32 bit field! -*/ -int U_PMF_LANGUAGEIDENTIFIER_get(U_PMF_LANGUAGEIDENTIFIER LId, int *SubLId, int *PriLId){ - if(!SubLId || !PriLId){ return(0); } - *SubLId = (LId >> U_FF_SHFT_SUBLID ) & U_FF_MASK_SUBLID; - *PriLId = (LId >> U_FF_SHFT_PRILID ) & U_FF_MASK_PRILID; - /* 16 bits above that are not used */ - return(1); -} - -/** - \brief Get data from a U_PMF_LINEARGRADIENTBRUSHDATA object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Lgbd U_PMF_LINEARGRADIENTBRUSHDATA structure, with no variable part - \param Data variable part of U_PMF_LINEARGRADIENTBRUSHDATA - \param blimit one byte past the end of data - - EMF+ manual 2.2.2.24, Microsoft name: EmfPlusLinearGradientBrushData Object - - Caller must check Data for possible memory access violations. -*/ -int U_PMF_LINEARGRADIENTBRUSHDATA_get(const char *contents, U_PMF_LINEARGRADIENTBRUSHDATA *Lgbd, const char **Data, const char *blimit){ - if(!contents || !Lgbd || !Data || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_LINEARGRADIENTBRUSHDATA), blimit))return(0); - U_PMF_SERIAL_get(&contents, Lgbd, 4, 6, U_LE); /* Flags, WrapMode, RectF*/ - U_PMF_SERIAL_get(&contents, &(Lgbd->StartColor), 4, 4, U_XE); /* StartColor, EndColor, Reserved1 & 2 */ - U_PMF_PTRSAV_SHIFT(Data, &contents, 0); - return(1); -} - -/** - \brief Get data from a U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Flags BrushData flags - indicates which of the following date fields are present. - \param Tm Transformation matrix - \param Bc U_PMF_BLENDCOLORS object or NULL - \param BfH U_PMF_BLENDFACTORS (H) object or NULL - \param BfV U_PMF_BLENDFACTORS (V) object or NULL (WARNING, GDI+ defines this field but does not render it. DO NOT USE.) - \param blimit one byte past the end of data - - EMF+ manual 2.2.2.25, Microsoft name: EmfPlusLinearGradientBrushOptionalData Object - -*/ -int U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA_get(const char *contents, uint32_t Flags, U_PMF_TRANSFORMMATRIX *Tm, - const char **Bc, const char **BfH, const char **BfV, const char *blimit){ - uint32_t Elements; - if(!contents || !Tm|| !Bc || !BfH || !BfV || !blimit){ return(0); } - /* all of the fields are optional! */ - *Bc = *BfH = *BfV = NULL; - if(Flags & U_BD_Transform){ - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_ROTMATRIX), blimit))return(0); - U_PMF_SERIAL_get(&contents, Tm, 4, 6, U_LE); - } - if(Flags & U_BD_PresetColors){ - if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); - U_PMF_SERIAL_get(&contents, &Elements, 4, 1, U_LE); /* starts with a 4 byte count*/ - if(IS_MEM_UNSAFE(contents, Elements * ( sizeof(U_FLOAT) + sizeof(U_PMF_ARGB)), blimit))return(0); - contents-=4; /* back up to the front of the count, as it is part of the data field */ - U_PMF_PTRSAV_SHIFT(Bc, &contents, 0); - } - else if(Flags & U_BD_BlendFactorsH){ - U_PMF_SERIAL_get(&contents, &Elements, 4, 1, U_LE); /* starts with a 4 byte count*/ - if(IS_MEM_UNSAFE(contents, Elements * 2 * sizeof(U_FLOAT), blimit))return(0); - contents-=4; /* back up to the front of the count, as it is part of the data field */ - U_PMF_PTRSAV_SHIFT(BfH, &contents, 4 + (Elements * 2 * sizeof(U_FLOAT))); /* 4 byte count + 2 * 4bytes * Elements */ - if(Flags & U_BD_BlendFactorsV){ - if(IS_MEM_UNSAFE(contents, Elements * 2 * sizeof(U_FLOAT), blimit))return(0); - U_PMF_PTRSAV_SHIFT(BfV, &contents, 0); - } - } - else if(Flags & U_BD_BlendFactorsV){ - U_PMF_SERIAL_get(&contents, &Elements, 4, 1, U_LE); /* starts with a 4 byte count*/ - if(IS_MEM_UNSAFE(contents, Elements * 2 * sizeof(U_FLOAT), blimit))return(0); - contents-=4; /* back up to the front of the count, as it is part of the data field */ - U_PMF_PTRSAV_SHIFT(BfV, &contents, 0); - } - return(1); -} - -/** - \brief Get data from a U_PMF_LINEPATH object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Size Bytes in Data - \param Data Outline path - \param blimit one byte past the end of data - - EMF+ manual 2.2.2.26, Microsoft name: EmfPlusLinePath Object - - Caller must check Data for possible memory access violations. -*/ -int U_PMF_LINEPATH_get(const char *contents, int32_t *Size, const char **Data, const char *blimit){ - if(!contents || !Size || !Data || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_LINEPATH), blimit))return(0); - U_PMF_SERIAL_get(&contents, Size, 4, 1, U_LE); - U_PMF_PTRSAV_SHIFT(Data, &contents, 0); - return(1); -} - -/** - \brief Get data from a U_PMF_METAFILE object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Type - \param Size Bytes in Data - \param Data Various types of data, like an EMF metafile, WMF metafile, another EMF+ metafile - \param blimit one byte past the end of data - - EMF+ manual 2.2.2.27, Microsoft name: EmfPlusMetafile Object - - Caller must check Data for possible memory access violations. -*/ -int U_PMF_METAFILE_get(const char *contents, uint32_t *Type, uint32_t *Size, const char **Data, const char *blimit){ - if(!contents || !Type || !Size || !Data || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_METAFILE), blimit))return(0); - U_PMF_SERIAL_get(&contents, &Type, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, &Size, 4, 1, U_LE); - U_PMF_PTRSAV_SHIFT(Data, &contents, 0); - return(1); -} - -/** - \brief Get data from a U_PMF_PALETTE object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Flags PaletteStyle flags - \param Elements Members in the array - \param Colors Palette data (array of colors) - \param blimit one byte past the end of data - - EMF+ manual 2.2.2.28, Microsoft name: EmfPlusPalette Object -*/ -int U_PMF_PALETTE_get(const char *contents, uint32_t *Flags, uint32_t *Elements, const char **Colors, const char *blimit){ - if(!contents || !Flags || !Elements || !Colors || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_PALETTE), blimit))return(0); - U_PMF_SERIAL_get(&contents, &Flags, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, &Elements, 4, 1, U_LE); - if(IS_MEM_UNSAFE(contents, *Elements*sizeof(U_RGBQUAD), blimit))return(0); - U_PMF_PTRSAV_SHIFT(Colors, &contents, 0); - return(1); - -} - -/** - \brief Get data from a U_PMF_PATHGRADIENTBRUSHDATA object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Pgbd constant part of U_PMF_PATHGRADIENTBRUSHDATA object - \param Gradient variable part of U_PMF_LINEARGRADIENTBRUSHDATA, Color Gradient with Elements members - \param Boundary variable part of U_PMF_LINEARGRADIENTBRUSHDATA, U_PMF_BOUNDARYPATHDATA object if BrushDataPath bit set in Flag, else U_PMF_BOUNDARYPOINTDATA object - \param Data variable part of U_PMF_LINEARGRADIENTBRUSHDATA, exact composition depends on Flags - \param blimit one byte past the end of data - - EMF+ manual 2.2.2.29, Microsoft name: EmfPlusPathGradientBrushData Object - - Caller must check Data for possible memory access violations. - -*/ -int U_PMF_PATHGRADIENTBRUSHDATA_get(const char *contents, U_PMF_PATHGRADIENTBRUSHDATA *Pgbd, const char **Gradient, - const char **Boundary, const char **Data, const char *blimit){ - if(!contents || !Pgbd || !Gradient || !Boundary || !Data || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_PATHGRADIENTBRUSHDATA), blimit))return(0); - uint32_t Size; - U_PMF_SERIAL_get(&contents, Pgbd, 4, 2, U_LE); /* Flags and WrapMode*/ - U_PMF_SERIAL_get(&contents, &(Pgbd->CenterColor), 4, 1, U_XE); - U_PMF_SERIAL_get(&contents, &(Pgbd->Center), 4, 3, U_LE); /* Center and Elements */ - if(IS_MEM_UNSAFE(contents, Pgbd->Elements * sizeof(U_PMF_ARGB), blimit))return(0); - U_PMF_PTRSAV_SHIFT(Gradient, &contents, Pgbd->Elements * sizeof(U_PMF_ARGB)); - U_PMF_PTRSAV_SHIFT(Boundary, &contents, 0); - U_PMF_SERIAL_get(&contents, &Size, 4, 1, U_LE); /* The first 4 bytes of the Boundary are always a size */ - if(Pgbd->Flags & U_BD_Path){ contents += Size; } // U_PMF_BOUNDARYPATHDATA - else { contents += Size*2*sizeof(U_FLOAT); } // U_PMF_BOUNDARYPOINTDATA - if(Pgbd->Flags & (U_BD_Transform |U_BD_PresetColors | U_BD_BlendFactorsH| U_BD_FocusScales)){ // optional data present - if(contents >= blimit)return(0); // the size is variable but this must still hold - U_PMF_PTRSAV_SHIFT(Data, &contents, 0); - } - else { *Data = NULL; } // no optional data present - return(1); -} - -/** - \brief Get data from a U_PMF_PATHGRADIENTBRUSHOPTIONALDATA object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Flags bits set to indicate the presence of FillData and/or LineData - \param Matrix Transformation matrix - \param Pattern Blend Pattern - \param Data Focus scales for the brush - \param blimit one byte past the end of data - - EMF+ manual 2.2.2.30, Microsoft name: EmfPlusPathGradientBrushOptionalData Object -*/ -int U_PMF_PATHGRADIENTBRUSHOPTIONALDATA_get(const char *contents, uint32_t Flags, U_PMF_TRANSFORMMATRIX *Matrix, - const char **Pattern, const char **Data, const char *blimit){ - int varsize; - if(!contents || !Flags || !Matrix || !Pattern || !Data || !blimit){ return(0); } - /* this structure is entirely optional */ - if(Flags & U_BD_Transform){ - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_TRANSFORMMATRIX), blimit))return(0); - U_PMF_SERIAL_get(&contents, Matrix, 4, 6, U_LE); - } - if(Flags & (U_BD_PresetColors | U_BD_BlendFactorsH)){ - if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); - uint32_t Elements; - U_PMF_SERIAL_get(&contents, &Elements, 4, 1, U_LE); - contents -= 4; - varsize=(Elements * 4 * (Flags & U_BD_BlendFactorsH ? 2 :1)); - if(IS_MEM_UNSAFE(contents, varsize, blimit))return(0); - U_PMF_PTRSAV_SHIFT(Pattern, &contents, varsize); - } - else { *Pattern=NULL; } - if(Flags & U_BD_FocusScales){ - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_FOCUSSCALEDATA), blimit))return(0); - U_PMF_PTRSAV_SHIFT(Data, &contents, sizeof(U_PMF_FOCUSSCALEDATA)); - } - else { *Data=NULL; } - return(1); -} - -/** - \brief Get data from a U_PMF_PATHPOINTTYPE object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Flags PathPointType flags - \param Type PathPointType enumeration - \param blimit one byte past the end of data - - EMF+ manual 2.2.2.31, Microsoft name: EmfPlusPathPointType Object - - Note: order of 4bit fields appears to be shown in the LE column, not as - documented in the BE column. -*/ -int U_PMF_PATHPOINTTYPE_get(const char *contents, int *Flags, int *Type, const char *blimit){ - if(!contents || !Flags || !Type || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, 1, blimit))return(0); - uint8_t tmp; - memcpy(&tmp, contents, 1); - *Flags =(tmp & U_PTP_MASK) >> U_PTP_SHIFT; - *Type = (tmp & U_PPT_MASK); - return(1); -} - -/** - \brief Get data from a U_PMF_PATHPOINTTYPERLE object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Bezier Set: Bezier curve, Clear: straight line - \param RL Run Length - \param Ppt PathPointType enumeration - \param blimit one byte past the end of data - - EMF+ manual 2.2.2.32, Microsoft name: EmfPlusPathPointTypeRLE Object -*/ -int U_PMF_PATHPOINTTYPERLE_get(const char *contents, int *Bezier, int *RL, int *Ppt, const char *blimit){ - if(!contents || !Bezier || !RL || !Ppt || !blimit){ return(0); } - uint16_t tmp; - if(IS_MEM_UNSAFE(contents, 2, blimit))return(0); - U_PMF_SERIAL_get(&contents, &tmp, 2, 1, U_LE); - *Bezier = tmp & U_PPF_BZ; - *RL = (tmp >> U_FF_SHFT_RL) & U_FF_MASK_RL; - *Ppt = (tmp >> U_FF_SHFT_PPT) & U_FF_MASK_PPT; - return(1); -} - -/** - \brief Get data from a U_PMF_PENDATA object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Flags PenData flags - \param Unit UnitType enumeration - \param Width Width in units set by Unit - \param Data Optional pen data, exact composition depends on Flags - \param blimit one byte past the end of data - - EMF+ manual 2.2.2.33, Microsoft name: EmfPlusPenData Object -*/ -int U_PMF_PENDATA_get(const char *contents, uint32_t *Flags, uint32_t *Unit, U_FLOAT *Width, const char **Data, const char *blimit){ - if(!contents || !Flags || !Unit || !Width || !Data || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, 3*4, blimit))return(0); - U_PMF_SERIAL_get(&contents, Flags, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Unit, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Width, 4, 1, U_LE); - if(contents >= blimit)return(0); // variable data will extend farther, but this much at least must be true - U_PMF_PTRSAV_SHIFT(Data, &contents, 0); - return(1); -} - -/** - \brief Get data from a U_PMF_PENOPTIONALDATA object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Flags; PenData Flags - indicated which of the many fields are present. - \param Matrix; Transformation matrix - \param StartCap LineCapType enumeration - \param EndCap LineCapType enumeration - \param Join LineJoinType enumeration - \param MiterLimit Maximum (miter length / line width) - \param Style LineStyle enumeration - \param DLCap DashedLineCapType enumeration - \param DLOffset Distance line start to first dash start - \param DLData Dash and space widths - \param Alignment PenAlignment enumeration - \param CmpndLineData Compount Line (parallel lines drawn instead of one) - \param CSCapData Custom start cap - \param CECapData Custom end cap - \param blimit one byte past the end of data - - EMF+ manual 2.2.2.34, Microsoft name: EmfPlusPenOptionalData Object - - This object consists of a large number of optional and or variable values, which - are returned, or not, depending on bits in Flags. -*/ -int U_PMF_PENOPTIONALDATA_get( - const char *contents, - uint32_t Flags, // determines which fields are filled - U_PMF_TRANSFORMMATRIX *Matrix, - int32_t *StartCap, - int32_t *EndCap, - uint32_t *Join, - U_FLOAT *MiterLimit, - int32_t *Style, - int32_t *DLCap, - U_FLOAT *DLOffset, - const char **DLData, - int32_t *Alignment, - const char **CmpndLineData, - const char **CSCapData, - const char **CECapData, - const char *blimit){ - if(!contents || - !Flags || !Matrix || !StartCap || !EndCap || - !Join || !MiterLimit || !Style || !DLCap || - !DLOffset || !DLData || !Alignment || !CmpndLineData || - !CSCapData || !CECapData || !blimit){ return(0); } - - if(Flags & U_PD_Transform){ if(IS_MEM_UNSAFE(contents, 4*6, blimit))return(0); - U_PMF_SERIAL_get(&contents, Matrix, 4, 6, U_LE); - } - if(Flags & U_PD_StartCap){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); - U_PMF_SERIAL_get(&contents, StartCap, 4, 1, U_LE); - } - if(Flags & U_PD_EndCap){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); - U_PMF_SERIAL_get(&contents, EndCap, 4, 1, U_LE); - } - if(Flags & U_PD_Join){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); - U_PMF_SERIAL_get(&contents, Join, 4, 1, U_LE); - } - if(Flags & U_PD_MiterLimit){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); - U_PMF_SERIAL_get(&contents, MiterLimit, 4, 1, U_LE); - } - if(Flags & U_PD_LineStyle){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); - U_PMF_SERIAL_get(&contents, Style, 4, 1, U_LE); - } - if(Flags & U_PD_DLCap){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); - U_PMF_SERIAL_get(&contents, DLCap, 4, 1, U_LE); - } - if(Flags & U_PD_DLOffset){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); - U_PMF_SERIAL_get(&contents, DLOffset, 4, 1, U_LE); - } - if(Flags & U_PD_DLData){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); - if(IS_MEM_UNSAFE(contents, U_PMF_LEN_FLOATDATA(contents), blimit))return(0); - U_PMF_PTRSAV_SHIFT( DLData, &contents, U_PMF_LEN_FLOATDATA(contents)); - } - if(Flags & U_PD_NonCenter){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); - U_PMF_SERIAL_get(&contents, Alignment, 4, 1, U_LE); } - if(Flags & U_PD_CLData){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); - if(IS_MEM_UNSAFE(contents, U_PMF_LEN_FLOATDATA(contents), blimit))return(0); - U_PMF_PTRSAV_SHIFT( CmpndLineData, &contents, U_PMF_LEN_FLOATDATA(contents)); - } - if(Flags & U_PD_CustomStartCap){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); - if(IS_MEM_UNSAFE(contents, U_PMF_LEN_BYTEDATA(contents), blimit))return(0); - U_PMF_PTRSAV_SHIFT( CSCapData, &contents, U_PMF_LEN_BYTEDATA(contents)); - } - if(Flags & U_PD_CustomEndCap){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); - if(IS_MEM_UNSAFE(contents, U_PMF_LEN_BYTEDATA(contents), blimit))return(0); - U_PMF_PTRSAV_SHIFT( CECapData, &contents, U_PMF_LEN_BYTEDATA(contents)); - } - return(1); -} - -/** - \brief Get data from a U_PMF_POINT object - \return 1 on success, 0 on error - \param contents Record from which to extract data. On return position is offset by sizeof(U_PMF_POINT). - \param X X coordinate - \param Y Y coordinate - \param blimit one byte past the end of data - - EMF+ manual 2.2.2.35, Microsoft name: EmfPlusPoint Object -*/ -int U_PMF_POINT_get(const char **contents, U_FLOAT *X, U_FLOAT *Y, const char *blimit){ - if(!contents || !X || !Y || !blimit){ return(0); } - int16_t tmp; - if(IS_MEM_UNSAFE(*contents, 2*2, blimit))return(0); - U_PMF_SERIAL_get(contents, &tmp, 2, 1, U_LE); *X = tmp; - U_PMF_SERIAL_get(contents, &tmp, 2, 1, U_LE); *Y = tmp; - return(1); -} - -/** - \brief Get data from a U_PMF_POINTF object - \return 1 on success, 0 on error - \param contents Record from which to extract data. On return position is offset by sizeof(U_PMF_POINTF). - \param X X coordinate - \param Y Y coordinate - \param blimit one byte past the end of data - - EMF+ manual 2.2.2.36, Microsoft name: EmfPlusPointF Object -*/ -int U_PMF_POINTF_get(const char **contents, U_FLOAT *X, U_FLOAT *Y, const char *blimit){ - if(!contents || !X || !Y || !blimit){ return(0); } - if(IS_MEM_UNSAFE(*contents, 4*2, blimit))return(0); - U_PMF_SERIAL_get(contents, X, 4, 1, U_LE); - U_PMF_SERIAL_get(contents, Y, 4, 1, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMF_POINTR object - \return size in bytes traversed on success, 0 on error - \param contents Record from which to extract data. On return position is offset by returned size. - \param X X coordinate - \param Y Y coordinate - \param blimit one byte past the end of data - - EMF+ manual 2.2.2.37, Microsoft name: EmfPlusPointR Object -*/ -int U_PMF_POINTR_get(const char **contents, U_FLOAT *X, U_FLOAT *Y, const char *blimit){ - if(!contents || !*contents | !X || !Y || !blimit){ return(0); } - int size=0; - - if( U_PMF_INTEGER7_get( contents, X, blimit)){ size +=1; } - else if(U_PMF_INTEGER15_get(contents, X, blimit)){ size +=2; } - else { return(0); } - - if( U_PMF_INTEGER7_get( contents, Y, blimit)){ size +=1; } - else if(U_PMF_INTEGER15_get(contents, Y, blimit)){ size +=2; } - else { return(0); } - - return(size); -} - -/** - \brief Get data from a variable POINTS object, which may be U_PMF_POINTS, U_PMF_POINTF, or U_PMF_POINTR. - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Flags Record flags (bits U_PPF_C and U_PPF_P are referenced) - \param Elements Number of points to retrieve. - \param Points Caller must free. Array of U_PMF_POINTF coordinates. - \param blimit one byte past the end of data - - This function should never be called directly by end user code. -*/ -int U_PMF_VARPOINTS_get(const char *contents, uint16_t Flags, int Elements, U_PMF_POINTF **Points, const char *blimit){ - int status = 0; - if(!contents || !Points || !Elements || !blimit){ return(status); } - U_PMF_POINTF *pts = (U_PMF_POINTF *)malloc(Elements * sizeof(U_PMF_POINTF)); - if(!pts){ return(status); } - *Points = pts; - U_FLOAT XF, YF; - U_FLOAT XFS, YFS; - - if(Flags & U_PPF_P){ - for(XFS = YFS = 0.0; Elements; Elements--, pts++){ - if(!U_PMF_POINTR_get(&contents, &XF, &YF, blimit))return(0); /* this should never happen */ - XFS += XF; /* position relative to previous point, first point is always 0,0 */ - YFS += YF; - pts->X = XFS; - pts->Y = YFS; - } - } - else if(Flags & U_PPF_C){ - for(XF = YF = 0.0; Elements; Elements--, pts++){ - if(!U_PMF_POINT_get(&contents, &XF, &XF, blimit))break; /* this should never happen */ - pts->X = XF; - pts->Y = YF; - } - } - else { - for(XF = YF = 0.0; Elements; Elements--, pts++){ - (void) U_PMF_POINTF_get(&contents, &XF, &YF, blimit); - pts->X = XF; - pts->Y = YF; - } - } - if(Elements){ /* some error in the preceding */ - free(*Points); - *Points = NULL; - } - else { - status = 1; - } - return(status); -} - -/** - \brief Get data from a U_PMF_RECT object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param X UL X value - \param Y UL Y value - \param Width Width - \param Height Height - \param blimit one byte past the end of data - - EMF+ manual 2.2.2.38, Microsoft name: EmfPlusRect Object -*/ -int U_PMF_RECT_get(const char **contents, int16_t *X, int16_t *Y, int16_t *Width, int16_t *Height, const char *blimit){ - if(!contents || !X || !Y|| !Width || !Height){ return(0); } - if(IS_MEM_UNSAFE(*contents, 2*4, blimit))return(0); - U_PMF_SERIAL_get(contents, X, 2, 1, U_LE); - U_PMF_SERIAL_get(contents, Y, 2, 1, U_LE); - U_PMF_SERIAL_get(contents, Width, 2, 1, U_LE); - U_PMF_SERIAL_get(contents, Height, 2, 1, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMF_RECTF object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param X UL X value - \param Y UL Y value - \param Width Width - \param Height Height - \param blimit one byte past the end of data - - EMF+ manual 2.2.2.39, Microsoft name: EmfPlusRectF Object -*/ -int U_PMF_RECTF_get(const char **contents, U_FLOAT *X, U_FLOAT *Y, U_FLOAT *Width, U_FLOAT *Height, const char *blimit){ - if(!contents || !X || !Y|| !Width || !Height){ return(0); } - if(IS_MEM_UNSAFE(*contents, 4*4, blimit))return(0); - U_PMF_SERIAL_get(contents, X, 4, 1, U_LE); - U_PMF_SERIAL_get(contents, Y, 4, 1, U_LE); - U_PMF_SERIAL_get(contents, Width, 4, 1, U_LE); - U_PMF_SERIAL_get(contents, Height, 4, 1, U_LE); - return(1); -} - -/** - \brief Get data from a variable RECTS object, which may be U_PMF_RECT or U_PMF_RECTF - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Flags Record flags (bit U_PPF_C is referenced) - \param Elements Number of rects to retrieve. - \param Rects Caller must free. Array of U_PMF_RECTF coordinates. - \param blimit one byte past the end of data - - Rects in record may be either U_PMF_RECT or U_PMF_RECTF, but this function always - returns U_PMF_RECTF -*/ -int U_PMF_VARRECTS_get(const char **contents, uint16_t Flags, int Elements, U_PMF_RECTF **Rects, const char *blimit){ - int16_t X16, Y16, Width, Height; - if(!contents || !*contents || !Rects || !blimit){ return(0); } - U_PMF_RECTF *rts = (U_PMF_RECTF *)malloc(Elements * sizeof(U_PMF_RECTF)); - if(!rts){ - *Rects = NULL; - return(0); - } - - *Rects = rts; - if(Flags & U_PPF_C){ - if(IS_MEM_UNSAFE(*contents, Elements*sizeof(U_PMF_RECT), blimit)){ - free(rts); - return(0); - } - } - else { - if(IS_MEM_UNSAFE(*contents, Elements*sizeof(U_PMF_RECT), blimit)){ - free(rts); - return(0); - } - } - for(; Elements; Elements--, rts++){ - if(Flags & U_PPF_C){ - (void) U_PMF_RECT_get(contents, &X16, &Y16, &Width, &Height, blimit); - rts->X = X16; - rts->Y = Y16; - rts->Width = Width; - rts->Height = Height; - } - else { - (void) U_PMF_RECTF_get(contents, &(rts->X), &(rts->Y), &(rts->Width), &(rts->Height), blimit); - } - } - return(1); -} - -/** - \brief Get data from a U_PMF_REGIONNODE object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Type RegionNodeDataType - \param Data Depending on Type: U_PMF_REGIONNODEPATH, U_PMF_RECTF, or U_PMF_REGIONNODECHILDNODES - \param blimit one byte past the end of data - - EMF+ manual 2.2.2.40, Microsoft name: EmfPlusRegionNode Object - - Caller must check Data for possible memory access violations. -*/ -int U_PMF_REGIONNODE_get(const char *contents, uint32_t *Type, const char **Data, const char *blimit){ - if(!contents || !Type || !Data || !blimit){ return(0); } - /* Important! This only checks the constant part, the caller must check that returned data doesn't exceed blimit */ - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_REGIONNODE), blimit))return(0); - U_PMF_SERIAL_get(&contents, Type, 4, 1, U_LE); - if(contents >= blimit)return(0); // returned Data is variable size, this much at least must be true - U_PMF_PTRSAV_COND(Data, contents, !(*Type == U_RNDT_Empty || *Type == U_RNDT_Infinite )); - return(1); -} - -/** - There is no U_PMF_REGIONNODECHILDNODES_get! - - The Region object is recursive allowing U_PMF_REGIONNODECHILDNODES -> - U_PMF_REGIONNODE -> U_PMF_REGIONNODECHILDNODES etc. - So the data stored in each node must be handled as the tree is followed recursively. - - See U_PMF_REGIONNODECHILDNODES_print() and U_PMF_REGIONNODE_print() for an example. - - - EMF+ manual 2.2.2.41, Microsoft name: EmfPlusRegionNodeChildNodes Object -*/ - -/** - \brief Get data from a U_PMF_REGIONNODEPATH object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Size Bytes in Data - \param Data Boundary of region node - \param blimit one byte past the end of data - - EMF+ manual 2.2.2.42, Microsoft name: EmfPlusRegionNodePath Object -*/ -int U_PMF_REGIONNODEPATH_get(const char *contents, int32_t *Size, const char **Data, const char *blimit){ - if(!contents || !Size || !Data || !blimit){ return(0); } - /* Important! This only checks the constant part, the caller must check that returned data doesn't exceed blimit */ - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_REGIONNODEPATH), blimit))return(0); - U_PMF_SERIAL_get(&contents, Size, 4, 1, U_LE); - if(contents >= blimit)return(0); // returned Data is variable size, this much at least must be true - U_PMF_PTRSAV_SHIFT(Data, &contents, 0); - return(1); -} - -/** - \brief Get data from a U_PMF_SOLIDBRUSHDATA object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Color Color of brush - \param blimit one byte past the end of data - - EMF+ manual 2.2.2.43, Microsoft name: EmfPlusSolidBrushData Object -*/ -int U_PMF_SOLIDBRUSHDATA_get(const char *contents, U_PMF_ARGB *Color, const char *blimit){ - if(!contents || !Color || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_SOLIDBRUSHDATA), blimit))return(0); - U_PMF_SERIAL_get(&contents, Color, 4, 1, U_XE); - return(1); -} - -/** - \brief Get data from a U_PMF_STRINGFORMATDATA object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param TabStopCount Entries in TabStop array - \param RangeCount Entries in CharRange array - \param TabStops Array of tabstop locations - \param CharRange Array of character ranges in the text - \param blimit one byte past the end of data - - EMF+ manual 2.2.2.44, Microsoft name: EmfPlusStringFormatData Object -*/ -int U_PMF_STRINGFORMATDATA_get(const char *contents, uint32_t TabStopCount, uint32_t RangeCount, - const U_FLOAT **TabStops, const U_PMF_CHARACTERRANGE **CharRange, const char *blimit){ - if(!contents || !TabStops|| !CharRange || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, (TabStopCount + 2*RangeCount)*4, blimit))return(0); - *TabStops = NULL; - if(TabStopCount > 0){ U_PMF_SERIAL_get(&contents, TabStops, 4, TabStopCount, U_LE); } - *CharRange = NULL; - if(RangeCount > 0){ U_PMF_SERIAL_get(&contents, CharRange, 4, 2*RangeCount, U_LE); } - return(1); -} - -/** - \brief Get data from a U_PMF_TEXTUREBRUSHDATA object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Flags BrushData flags - \param WrapMode WrapMode enumeration - \param Data Optional texture data - \param blimit one byte past the end of data - - EMF+ manual 2.2.2.45, Microsoft name: EmfPlusTextureBrushData Object - - Caller must check Data for possible memory access violations. -*/ -int U_PMF_TEXTUREBRUSHDATA_get(const char *contents, uint32_t *Flags, int32_t *WrapMode, const char **Data, const char *blimit){ - if(!contents || !Flags || !WrapMode || !Data || !blimit){ return(0); } - /* Important! This only checks the constant part, the caller must check that returned data doesn't exceed blimit */ - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_TEXTUREBRUSHDATA), blimit))return(0); - U_PMF_SERIAL_get(&contents, Flags, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, WrapMode, 4, 1, U_LE); - if(contents >= blimit)return(0); // returned Data is variable size, this much at least must be true - U_PMF_PTRSAV_SHIFT(Data, &contents, 0); - return(1); -} - -/** - \brief Get data from a U_PMF_TEXTUREBRUSHOPTIONALDATA object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param HasImage True if this object has an Image - \param Matrix Transformation matrix, NULL if Flag BrushDataTransform is not set. - \param Image Image that contains the texture. - \param blimit one byte past the end of data - - EMF+ manual 2.2.2.46, Microsoft name: EmfPlusTextureBrushOptionalData Object - - Caller must check Image for possible memory access violations. -*/ -int U_PMF_TEXTUREBRUSHOPTIONALDATA_get(const char *contents, int HasImage, U_PMF_TRANSFORMMATRIX *Matrix, - const char **Image, const char *blimit){ - if(!contents || !Image || !blimit){ return(0); } - if(Matrix){ - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_TRANSFORMMATRIX), blimit))return(0); - U_PMF_SERIAL_get(&contents, Matrix, 4, 6, U_LE); - } - if(HasImage){ - if(contents >= blimit)return(0); // returned Data is variable size, this much at least must be true - U_PMF_PTRSAV_COND(Image, contents, HasImage); - } - return(1); -} - -/** - \brief Get data from a U_PMF_TRANSFORMMATRIX object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Matrix Transformation matrix, present if Flag BrushDataTransform is set. - \param blimit one byte past the end of data - - EMF+ manual 2.2.2.47, Microsoft name: EmfPlusTransformMatrix Object -*/ -int U_PMF_TRANSFORMMATRIX_get(const char *contents, U_PMF_TRANSFORMMATRIX *Matrix, const char *blimit){ - if(!contents || !Matrix || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_TRANSFORMMATRIX), blimit))return(0); - U_PMF_SERIAL_get(&contents, Matrix, 4, 6, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMF_IE_BLUR object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Radius Blur radius in pixels - \param ExpandEdge 1: expand bitmap by Radius; 0: bitmap size unchanged - \param blimit one byte past the end of data - - EMF+ manual 2.2.3.1, Microsoft name: BlurEffect Object -*/ -int U_PMF_IE_BLUR_get(const char *contents, U_FLOAT *Radius, uint32_t *ExpandEdge, const char *blimit){ - if(!contents || !Radius || !ExpandEdge || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_BLUR), blimit))return(0); - U_PMF_SERIAL_get(&contents, Radius, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, ExpandEdge, 4, 1, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMF_IE_BRIGHTNESSCONTRAST object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Brightness -255 to 255, 0 is unchanged, positive increases, negative decreases - \param Contrast -100 to 100, 0 is unchanged, positive increases, negative decreases - \param blimit one byte past the end of data - - EMF+ manual 2.2.3.2, Microsoft name: BrightnessContrastEffect Object -*/ -int U_PMF_IE_BRIGHTNESSCONTRAST_get(const char *contents, int32_t *Brightness, int32_t *Contrast, const char *blimit){ - if(!contents || !Brightness || !Contrast || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_BRIGHTNESSCONTRAST), blimit))return(0); - U_PMF_SERIAL_get(&contents, Brightness, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Contrast, 4, 1, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMF_IE_COLORBALANCE object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param CyanRed -100 to 100, 0 is unchanged, positive increases Red & decreases Cyan, negative is opposite - \param MagentaGreen -100 to 100, 0 is unchanged, positive increases Green & decreases Magenta, negative is opposite - \param YellowBlue -100 to 100, 0 is unchanged, positive increases Blue & decreases Yellow, negative is opposite - \param blimit one byte past the end of data - - EMF+ manual 2.2.3.3, Microsoft name: ColorBalanceEffect Object -*/ -int U_PMF_IE_COLORBALANCE_get(const char *contents, int32_t *CyanRed, int32_t *MagentaGreen, int32_t *YellowBlue, const char *blimit){ - if(!contents || !CyanRed || !MagentaGreen || !YellowBlue || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_COLORBALANCE), blimit))return(0); - U_PMF_SERIAL_get(&contents, CyanRed, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, MagentaGreen, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, YellowBlue, 4, 1, U_LE); - return(1); -} - - -/** - \brief Get data from a U_PMF_IE_COLORCURVE object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Adjust CurveAdjustment enumeration - \param Channel CurveChannel enumeration - \param Intensity adjustment to apply. "Adjust" determines what field this is and range values. - \param blimit one byte past the end of data - - EMF+ manual 2.2.3.4, Microsoft name: ColorCurveEffect Object -*/ -int U_PMF_IE_COLORCURVE_get(const char *contents, uint32_t *Adjust, uint32_t *Channel, int32_t *Intensity, const char *blimit){ - if(!contents || !Adjust || !Channel || !Intensity || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_COLORCURVE), blimit))return(0); - U_PMF_SERIAL_get(&contents, Adjust, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Channel, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Intensity, 4, 1, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMF_IE_COLORLOOKUPTABLE object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param BLUT Blue color lookup table - \param GLUT Green color lookup table - \param RLUT Red color lookup table - \param ALUT Alpha color lookup table - \param blimit one byte past the end of data - - EMF+ manual 2.2.3.5, Microsoft name: ColorLookupTableEffect Object -*/ -int U_PMF_IE_COLORLOOKUPTABLE_get(const char *contents, - const uint8_t **BLUT, const uint8_t **GLUT, const uint8_t **RLUT, const uint8_t **ALUT, const char *blimit){ - if(!contents || !BLUT || !GLUT || !RLUT || !ALUT || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_COLORLOOKUPTABLE) + 4 * 256, blimit))return(0); - U_PMF_PTRSAV_SHIFT((const char **)BLUT, &contents, 256); - U_PMF_PTRSAV_SHIFT((const char **)GLUT, &contents, 256); - U_PMF_PTRSAV_SHIFT((const char **)RLUT, &contents, 256); - U_PMF_PTRSAV_SHIFT((const char **)ALUT, &contents, 256); - return(1); -} - -/** - \brief Get data from a U_PMF_IE_COLORMATRIX object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Matrix 5 x 5 color transformation matrix, First 4 rows are [{4 multiplier values},0.0] for R,G,B,A, last Row is [{4 color translation valuess}, 1.0] - \param blimit one byte past the end of data - - EMF+ manual 2.2.3.6, Microsoft name: ColorMatrixEffect Object -*/ -int U_PMF_IE_COLORMATRIX_get(const char *contents, U_PMF_IE_COLORMATRIX *Matrix, const char *blimit){ - if(!contents || !Matrix || !blimit){ return(0); } - /* Important! This only checks the constant part, the caller must check that returned data doesn't exceed blimit */ - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_COLORMATRIX), blimit))return(0); - U_PMF_SERIAL_get(&contents, Matrix, 4, 5*5, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMF_IE_HUESATURATIONLIGHTNESS object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Hue -180 to 180, 0 is unchanged - \param Saturation -100 to 100, 0 is unchanged - \param Lightness -100 to 100, 0 is unchanged - \param blimit one byte past the end of data - - EMF+ manual 2.2.3.7, Microsoft name: HueSaturationLightnessEffect Object -*/ -int U_PMF_IE_HUESATURATIONLIGHTNESS_get(const char *contents, int32_t *Hue, int32_t *Saturation, int32_t *Lightness, const char *blimit){ - if(!contents || !Hue || !Saturation || !Lightness || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_HUESATURATIONLIGHTNESS), blimit))return(0); - U_PMF_SERIAL_get(&contents, Hue, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Saturation, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Lightness, 4, 1, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMF_IE_LEVELS object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Highlight 0 to 100, 100 is unchanged - \param Midtone -100 to 100, 0 is unchanged - \param Shadow 0 to 100, 0 is unchanged - \param blimit one byte past the end of data - - EMF+ manual 2.2.3.8, Microsoft name: LevelsEffect Object -*/ -int U_PMF_IE_LEVELS_get(const char *contents, int32_t *Highlight, int32_t *Midtone, int32_t *Shadow, const char *blimit){ - if(!contents || !Highlight || !Midtone || !Shadow || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_LEVELS), blimit))return(0); - U_PMF_SERIAL_get(&contents, Highlight, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Midtone, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Shadow, 4, 1, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMF_IE_REDEYECORRECTION object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Elements Number of members in Rects - \param Rects Caller must free. Pointer to memory holding an array of U_RECTL. - \param blimit one byte past the end of data - - EMF+ manual 2.2.3.9, Microsoft name: RedEyeCorrectionEffect Object -*/ -int U_PMF_IE_REDEYECORRECTION_get(const char *contents, int32_t *Elements, U_RECTL **Rects, const char *blimit){ - if(!contents || !Elements || !Rects || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_REDEYECORRECTION), blimit))return(0); - U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); - if(IS_MEM_UNSAFE(contents, *Elements * 4, blimit))return(0); - *Rects = (U_RECTL *) malloc(*Elements * sizeof(U_RECTL)); - if(!*Rects){ return(0); } - U_PMF_SERIAL_get(&contents, *Rects, 4, *Elements * 4, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMF_IE_SHARPEN object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Radius Sharpening radius in pixels - \param Sharpen 0 to 100, 0 is unchanged - \param blimit one byte past the end of data - - EMF+ manual 2.2.3.10, Microsoft name: SharpenEffect Object -*/ -int U_PMF_IE_SHARPEN_get(const char *contents, U_FLOAT *Radius, int32_t *Sharpen, const char *blimit){ - if(!contents || !Radius || !Sharpen || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_SHARPEN), blimit))return(0); - U_PMF_SERIAL_get(&contents, Radius, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Sharpen, 4, 1, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMF_IE_TINT object - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Hue -180 to 180, [positive==clockwise] rotation in degrees starting from blue - \param Amount -100 [add black] to 100[add white], 0 is unchanged. Change in hue on specified axis - \param blimit one byte past the end of data - - EMF+ manual 2.2.3.11, Microsoft name: TintEffect Object -*/ -int U_PMF_IE_TINT_get(const char *contents, int32_t *Hue, int32_t *Amount, const char *blimit){ - if(!contents || !Hue || !Amount || !blimit){ return(0); } - if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_TINT), blimit))return(0); - U_PMF_SERIAL_get(&contents, Hue, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Amount, 4, 1, U_LE); - return(1); -} - -/* - - end of U_PMF_*_get() functions - ===================================================================================== - start of U_PMR_*_get() functions - - These functions all assume that the size field in the common EMF+ header has already - been checked, so that the extent the record claims exists in the data read in for the file. - Consequently none of them takes a blimit parameter. They generate a new one from the - header size field and contents if needed. - -*/ - -int U_PMR_common_stack_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *StackID){ - if(!contents || !StackID){ return(0); } - - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_RESTORE))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - - U_PMF_SERIAL_get(&contents, StackID, 4, 1, U_LE); - return(1); -} - -/* for records that have a type but no associated flag bits or data */ -int U_PMR_common_header_get(const char *contents, U_PMF_CMN_HDR *Header){ - /* memory access safe, only uses the common header */ - if(!contents){ return(0); } - U_PMF_CMN_HDR_get(&contents, Header); - return(1); -} - -/** - \brief Get data from a U_PMR_OFFSETCLIP record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header (ignore flags) - \param dX horizontal translation offset to apply to clipping region - \param dY vertical translation offset to apply to clipping region - - EMF+ manual 2.3.1.1, Microsoft name: EmfPlusOffsetClip Record, Index 0x35 -*/ -int U_PMR_OFFSETCLIP_get(const char *contents, U_PMF_CMN_HDR *Header, - U_FLOAT *dX, U_FLOAT *dY){ - if(!contents){ return(0); } - - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_OFFSETCLIP))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - - U_PMF_SERIAL_get(&contents, dX, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, dY, 4, 1, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMR_RESETCLIP record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header (ignore flags) - - EMF+ manual 2.3.1.2, Microsoft name: EmfPlusResetClip Record, Index 0x31 -*/ -int U_PMR_RESETCLIP_get(const char *contents, U_PMF_CMN_HDR *Header){ - if(!contents){ return(0); } - U_PMF_CMN_HDR_get(&contents, Header); - return(1); -} - -/** - \brief Get data from a U_PMR_SETCLIPPATH record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param CMenum CombineMode enumeration.. - \param PathID U_PMF_PATH object in the EMF+ object table (0-63, inclusive) - - EMF+ manual 2.3.1.3, Microsoft name: EmfPlusSetClipPath Record, Index 0x33 -*/ -int U_PMR_SETCLIPPATH_get(const char *contents, U_PMF_CMN_HDR *Header, - uint32_t *PathID, int *CMenum){ - if(!contents || !PathID || !CMenum){ return(0); } - - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_SETCLIPPATH))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - - *CMenum = (lclHeader.Flags >> U_FF_SHFT_CM4) & U_FF_MASK_CM4; - *PathID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - return(1); -} - -/** - \brief Get data from a U_PMR_SETCLIPRECT record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header (ignore flags) - \param CMenum Combine mode enumeration. - \param Rect Rectangle used with CombineMode enumeration from Header.Flags - - EMF+ manual 2.3.1.4, Microsoft name: EmfPlusSetClipRect Record, Index 0x32 -*/ -int U_PMR_SETCLIPRECT_get(const char *contents, U_PMF_CMN_HDR *Header, - int *CMenum, - U_PMF_RECTF *Rect){ - if(!contents || !CMenum || !Rect ){ return(0); } - - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_SETCLIPRECT))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - - *CMenum = (lclHeader.Flags >> U_FF_SHFT_CM4) & U_FF_MASK_CM4; - U_PMF_SERIAL_get(&contents, Rect, 4, 4, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMR_SETCLIPREGION record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param CMenum CombineMode enumeration.. - \param PathID U_PMF_PATH object in the EMF+ object table (0-63, inclusive) - - EMF+ manual 2.3.1.5, Microsoft name: EmfPlusSetClipRegion Record, Index 0x34 -*/ -int U_PMR_SETCLIPREGION_get(const char *contents, U_PMF_CMN_HDR *Header, - uint32_t *PathID, int *CMenum){ - if(!contents || !PathID || !CMenum){ return(0); } - - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_SETCLIPREGION))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - - *CMenum = (lclHeader.Flags >> U_FF_SHFT_CM4) & U_FF_MASK_CM4; - *PathID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - return(1); -} - -/** - \brief Get data from a U_PMR_COMMENT record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header (ignore flags) - \param Data Private data, may be anything - - EMF+ manual 2.3.2.1, Microsoft name: EmfPlusComment Record, Index 0x03 - - Caller must check Data for possible memory access violations. -*/ -int U_PMR_COMMENT_get(const char *contents, U_PMF_CMN_HDR *Header, - const char **Data){ - if(!contents || !Data){ return(0); } - - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_COMMENT))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - - U_PMF_PTRSAV_SHIFT(Data, &contents, 0); - return(1); -} - -/** - \brief Get data from a U_PMR_ENDOFFILE record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header (ignore flags) - - EMF+ manual 2.3.3.1, Microsoft name: EmfPlusEndOfFile Record, Index 0x02 -*/ -int U_PMR_ENDOFFILE_get(const char *contents, U_PMF_CMN_HDR *Header){ - if(!contents){ return(0); } - U_PMF_CMN_HDR_get(&contents, Header); - return(1); -} - -/** - \brief Get data from a U_PMR_GETDC record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header (ignore flags) - - EMF+ manual 2.3.3.2, Microsoft name: EmfPlusGetDC Record, Index 0x04 -*/ -int U_PMR_GETDC_get(const char *contents, U_PMF_CMN_HDR *Header){ - if(!contents){ return(0); } - U_PMF_CMN_HDR_get(&contents, Header); - return(1); -} - -/** - \brief Get data from a U_PMR_HEADER record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header (ignore flags) - \param Version EmfPlusGraphicsVersion object - \param IsDual set = Dual-mode file, clear= EMF+ only file. - \param IsVideo set = video device, clear= printer. Ignore all other bits. - \param LogicalDpiX Horizontal resolution reference device in DPI - \param LogicalDpiY Vertical resolution reference device in DPI - - EMF+ manual 2.3.3.3, Microsoft name: EmfPlusHeader Record, Index 0x01 -*/ -int U_PMR_HEADER_get(const char *contents, U_PMF_CMN_HDR *Header, - U_PMF_GRAPHICSVERSION *Version, int *IsDual, int *IsVideo, uint32_t *LogicalDpiX, uint32_t *LogicalDpiY){ - if(!contents || !Version || !IsDual || !IsVideo || !LogicalDpiX || !LogicalDpiY){ return(0); } - uint32_t tmp; - - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_HEADER))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - - *IsDual = (lclHeader.Flags & U_PPF_DM ? 1 : 0 ); - U_PMF_SERIAL_get(&contents, Version, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, &tmp, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, LogicalDpiX, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, LogicalDpiY, 4, 1, U_LE); - *IsVideo = (tmp & U_PPF_VIDEO ? 1 : 0 ); - return(1); -} - -/** - \brief Get data from a U_PMR_CLEAR record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header (ignore flags) - \param Color Erase everything preceding, set background ARGB color. - - EMF+ manual 2.3.4.1, Microsoft name: EmfPlusClear Record, Index 0x09 -*/ -int U_PMR_CLEAR_get(const char *contents, U_PMF_CMN_HDR *Header, - U_PMF_ARGB *Color){ - if(!contents || !Color){ return(0); } - - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_CLEAR))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - - U_PMF_SERIAL_get(&contents, Color, 4, 1, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMR_DRAWARC record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive) - \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates - \param Start Start angle, >=0.0, degrees clockwise from 3:00 - \param Sweep Sweep angle, -360<= angle <=360, degrees clockwise from Start - \param Rect Caller must free. Bounding rectangle. Coordinate type set by ctype. - - EMF+ manual 2.3.4.2, Microsoft name: EmfPlusDrawArc Record, Index 0x12 -*/ -int U_PMR_DRAWARC_get(const char *contents, U_PMF_CMN_HDR *Header, - uint32_t *PenID, int *ctype, - U_FLOAT *Start, U_FLOAT *Sweep, - U_PMF_RECTF *Rect){ - if(!contents || !PenID || !ctype || !Start || !Sweep || !Rect){ return(0); } - - const char *blimit = contents; - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_DRAWARC))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - blimit += lclHeader.Size; - - *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); - *PenID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_SERIAL_get(&contents, Start, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Sweep, 4, 1, U_LE); - U_PMF_RECTF *Rects = NULL; - if(!U_PMF_VARRECTS_get(&contents, lclHeader.Flags, 1, &Rects, blimit))return(0); - memcpy(Rect,Rects,sizeof(U_PMF_RECTF)); - free(Rects); - return(1); -} - - -/** - \brief Get data from a U_PMR_DRAWBEZIERS record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive) - \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates - \param RelAbs Set: Coordinates are relative; Clear: Coordinates are absolute and their type is set by ctype - \param Elements Number of members in the Data array - \param Points Caller must free. Array of U_POINT_F = Sequence of points to connect. Coordinate type set by ctype and RelAbs. - - EMF+ manual 2.3.4.3, Microsoft name: EmfPlusDrawBeziers Record, Index 0x19 -*/ -int U_PMR_DRAWBEZIERS_get(const char *contents, U_PMF_CMN_HDR *Header, - uint32_t *PenID, int *ctype, int *RelAbs, - uint32_t *Elements, - U_PMF_POINTF **Points){ - if(!contents || !PenID || !ctype || !RelAbs || !Elements || !Points){ return(0); } - - const char *blimit = contents; - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_DRAWBEZIERS))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - blimit += lclHeader.Size; - - *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); - *RelAbs = (lclHeader.Flags & U_PPF_P ? 1 : 0 ); - *PenID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); - int status = U_PMF_VARPOINTS_get(contents, lclHeader.Flags, *Elements, Points, blimit ); - return(status); -} - -/** - \brief Get data from a U_PMR_DRAWCLOSEDCURVE record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive) - \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates - \param RelAbs Set: Coordinates are relative; Clear: Coordinates are absolute and their type is set by ctype - \param Tension Controls splines, 0 is straight line, >0 is curved - \param Elements Number of members in the Data array - \param Points Caller must free. Array of U_POINT_F = Sequence of points to connect. Coordinate type set by ctype and RelAbs. - - EMF+ manual 2.3.4.4, Microsoft name: EmfPlusDrawClosedCurve Record, Index 0x17 -*/ -int U_PMR_DRAWCLOSEDCURVE_get(const char *contents, U_PMF_CMN_HDR *Header, - uint32_t *PenID, int *ctype, int *RelAbs, - U_FLOAT *Tension, uint32_t *Elements, - U_PMF_POINTF **Points){ - if(!contents || !PenID || !ctype || !RelAbs || !Tension || !Elements || !Points){ return(0); } - - const char *blimit = contents; - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_DRAWCLOSEDCURVE))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - blimit += lclHeader.Size; - - *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); - *RelAbs = (lclHeader.Flags & U_PPF_P ? 1 : 0 ); - *PenID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_SERIAL_get(&contents, Tension, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); - U_PMF_VARPOINTS_get(contents, lclHeader.Flags, *Elements, Points, blimit); - return(1); -} - -/** - \brief Get data from a U_PMR_DRAWCURVE record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive) - \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates - \param Tension Controls splines, 0 is straight line, >0 is curved - \param Offset Element in Points that is the spline's starting point - \param NSegs Number of segments - \param Elements Number of members in Data array - \param Points Caller must free. Array of U_POINT_F = Sequence of points to connect. Coordinate type set by ctype and RelAbs. - - EMF+ manual 2.3.4.5, Microsoft name: EmfPlusDrawCurve Record, Index 0x18 -*/ -int U_PMR_DRAWCURVE_get(const char *contents, U_PMF_CMN_HDR *Header, - uint32_t *PenID, int *ctype, - U_FLOAT *Tension, uint32_t *Offset, uint32_t *NSegs, uint32_t *Elements, - U_PMF_POINTF **Points){ - if(!contents || !PenID || !ctype || !Tension || !Offset || !NSegs || !Elements || !Points){ return(0); } - - const char *blimit = contents; - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_DRAWCURVE))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - blimit += lclHeader.Size; - - *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); - *PenID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_SERIAL_get(&contents, Tension, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Offset, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, NSegs, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); - U_PMF_VARPOINTS_get(contents, lclHeader.Flags, *Elements, Points, blimit); - return(1); -} - -/** - \brief Get data from a U_PMR_DRAWDRIVERSTRING record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param FontID U_PMF_FONT object in the EMF+ object table (0-63, inclusive) - \param btype Set: BrushID is an U_PFM_ARGB; Clear: index of U_PMF_BRUSH object in EMF+ object table. - \param BrushID Color or index of U_PMF_BRUSH object in the EMF+ object table, depends on Flags bit0 - \param DSOFlags DriverStringOptions flags - \param HasMatrix If 1 record contains a TransformMatrix field, if 0 it does not. - \param Elements Number of members in Glyphs and Positions array - \param Glyphs Caller must free. If U_DSO_CmapLookup is set in DSOFlags this is an array of UTF16LE characters, otherwise, it is an array of indices into the U_PMF_FONT object indexed by Object_ID in flags. - \param Points Caller must free. Coordinates of each member of Glyphs. U_DSO_RealizedAdvance set in DSOFlags Relative then positions are calculated relative to the first glyph which is stored in Positions, otherwise, all glyph positions are stored in Positions. - \param Matrix Caller must free. Transformation to apply to Glyphs & Positions. Present if HasMatrix is 1 - - EMF+ manual 2.3.4.6, Microsoft name: EmfPlusDrawDriverString Record, Index 0x36 -*/ -int U_PMR_DRAWDRIVERSTRING_get(const char *contents, U_PMF_CMN_HDR *Header, - uint32_t *FontID, int *btype, - uint32_t *BrushID, uint32_t *DSOFlags, uint32_t *HasMatrix, uint32_t *Elements, - uint16_t **Glyphs, U_PMF_POINTF **Points, U_PMF_TRANSFORMMATRIX **Matrix){ - if(!contents || !FontID || !btype || !BrushID || - !DSOFlags || !HasMatrix || !Elements || !Glyphs || !Points || !Matrix){ return(0); } - - const char *blimit = contents; - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_DRAWDRIVERSTRING))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - blimit += lclHeader.Size; - - *btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 ); - *FontID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */ - U_PMF_SERIAL_get(&contents, DSOFlags, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, HasMatrix, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); - if(IS_MEM_UNSAFE(contents, *Elements*2 + *Elements*2*4 + 24, blimit))return(0); - if(!U_PMF_SERIAL_array_copy_get(&contents, (void **)Glyphs, 2, *Elements, U_LE, (*DSOFlags & U_DSO_CmapLookup))){ return(0); } - if(!U_PMF_SERIAL_array_copy_get(&contents, (void **)Points, 4, *Elements *2, U_LE, (*DSOFlags & U_DSO_RealizedAdvance))){ return(0); } - if(!U_PMF_SERIAL_array_copy_get(&contents, (void **)Matrix, 4, 6, U_LE, (*HasMatrix))){ return(0); } - return(1); -} - -/** - \brief Get data from a U_PMR_DRAWELLIPSE record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive) - \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates - \param Rect Caller must free. Bounding rectangle. Coordinate type set by ctype. - - EMF+ manual 2.3.4.7, Microsoft name: EmfPlusDrawEllipse Record, Index 0x0F -*/ -int U_PMR_DRAWELLIPSE_get(const char *contents, U_PMF_CMN_HDR *Header, - uint32_t *PenID, int *ctype, - U_PMF_RECTF *Rect){ - if(!contents || !PenID || !ctype || !Rect){ return(0); } - - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_DRAWELLIPSE))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - - *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); - *PenID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_SERIAL_get(&contents, Rect, 4, 4, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMR_DRAWIMAGE record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param ImgID U_PMF_IMAGE object in the EMF+ object table (0-63, inclusive) - \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates - \param ImgAttrID index of a U_PMF_IMAGEATTRIBUTES object in the object table - \param SrcUnit UnitType enumeration - \param SrcRect Region of image - \param DstRect Destination rectangle for image. Coordinate type set by ctype. - - EMF+ manual 2.3.4.8, Microsoft name: EmfPlusDrawImage Record, Index 0x1A -*/ -int U_PMR_DRAWIMAGE_get(const char *contents, U_PMF_CMN_HDR *Header, - uint32_t *ImgID, int *ctype, - uint32_t *ImgAttrID, int32_t *SrcUnit, U_PMF_RECTF *SrcRect, - U_PMF_RECTF *DstRect){ - if(!contents || !ImgID || !ctype || !ImgAttrID || !SrcUnit || !SrcRect || !DstRect){ return(0); } - - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_DRAWIMAGE))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - - *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); - *ImgID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_SERIAL_get(&contents, ImgAttrID, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, SrcUnit, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, SrcRect, 4, 4, U_LE); - U_PMF_SERIAL_get(&contents, DstRect, 4, 4, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMR_DRAWIMAGEPOINTS record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param ImgID U_PMF_IMAGE object in the EMF+ object table (0-63, inclusive) - \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates - \param etype Set: effect from previous U_PMR_SERIALIZABLEOBJECT record will be applied; Clear: no effect applied - \param RelAbs Set: Data is relative, Clear: if it is absolute - \param ImgAttrID EmfPlusImageAttributes object - \param SrcUnit UnitType enumeration - \param SrcRect Region of image - \param Elements Number of members in Points, must be 3 - \param Points Caller must free. 3 points of a parallelogram.. Coordinate type set by ctype and RelAbs. - - EMF+ manual 2.3.4.9, Microsoft name: EmfPlusDrawImagePoints Record, Index 0x1B -*/ -int U_PMR_DRAWIMAGEPOINTS_get(const char *contents, U_PMF_CMN_HDR *Header, - uint32_t *ImgID, int *ctype, int *etype, int *RelAbs, - uint32_t *ImgAttrID, int32_t *SrcUnit, U_PMF_RECTF *SrcRect, uint32_t *Elements, - U_PMF_POINTF **Points){ - if(!contents || !ImgID || !ctype || !etype || !RelAbs || !ImgAttrID || !SrcUnit || !Elements || !Points){ return(0); } - - const char *blimit = contents; - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_DRAWIMAGEPOINTS))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - blimit += lclHeader.Size; - - *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); - *etype = (lclHeader.Flags & U_PPF_E ? 1 : 0 ); - *RelAbs = (lclHeader.Flags & U_PPF_P ? 1 : 0 ); - *ImgID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_SERIAL_get(&contents, ImgAttrID, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, SrcUnit, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, SrcRect, 4, 4, U_LE); - U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); - U_PMF_VARPOINTS_get(contents, lclHeader.Flags, *Elements, Points, blimit); - return(1); -} - -/** - \brief Get data from a U_PMR_DRAWLINES record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive) - \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates - \param dtype Set: path must be closed, Clear: path is open - \param RelAbs Set: Coordinates are relative; Clear: Coordinates are absolute and their type is set by ctype - \param Elements Number of members in Points - \param Points Caller must free. Array of U_POINT_F = Sequence of points to connect. Coordinate type set by ctype and RelAbs. - - EMF+ manual 2.3.4.10, Microsoft name: EmfPlusDrawLines Record, Index 0x0D -*/ -int U_PMR_DRAWLINES_get(const char *contents, U_PMF_CMN_HDR *Header, - uint32_t *PenID, int *ctype, int *dtype, int *RelAbs, - uint32_t *Elements, - U_PMF_POINTF **Points){ - if(!contents || !PenID || !ctype || !dtype || !RelAbs || !Elements || !Points){ return(0); } - - const char *blimit = contents; - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_DRAWLINES))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - blimit += lclHeader.Size; - - *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); - *dtype = (lclHeader.Flags & U_PPF_D ? 1 : 0 ); - *RelAbs = (lclHeader.Flags & U_PPF_P ? 1 : 0 ); - *PenID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); - U_PMF_VARPOINTS_get(contents, lclHeader.Flags, *Elements, Points, blimit); - return(1); -} - -/** - \brief Get data from a U_PMR_DRAWPATH record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param PathID U_PMF_PATH object in the EMF+ object table (0-63, inclusive) - \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive) - - EMF+ manual 2.3.4.11, Microsoft name: EmfPlusDrawPath Record, Index 0x15 -*/ -int U_PMR_DRAWPATH_get(const char *contents, U_PMF_CMN_HDR *Header, - uint32_t *PathID, uint32_t *PenID){ - if(!contents || !PathID || !PenID){ return(0); } - - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_DRAWPATH))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - - *PathID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_SERIAL_get(&contents, PenID, 4, 1, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMR_DRAWPIE record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive) - \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates - \param Start Start angle, >=0.0, degrees clockwise from 3:00 - \param Sweep Sweep angle, -360<= angle <=360, degrees clockwise from Start - \param Rect Caller must free. Bounding rectangle. Coordinate type set by ctype. - - EMF+ manual 2.3.4.12, Microsoft name: EmfPlusDrawPie Record, Index 0x0D -*/ -int U_PMR_DRAWPIE_get(const char *contents, U_PMF_CMN_HDR *Header, - uint32_t *PenID, int *ctype, - U_FLOAT *Start, U_FLOAT *Sweep, - U_PMF_RECTF *Rect){ - if(!contents || !PenID || !ctype || !Start || !Sweep || !Rect){ return(0); } - - const char *blimit = contents; - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_DRAWPIE))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - blimit += lclHeader.Size; - - *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); - *PenID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_SERIAL_get(&contents, Start, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Sweep, 4, 1, U_LE); - U_PMF_RECTF *Rects = NULL; - if(!U_PMF_VARRECTS_get(&contents, lclHeader.Flags, 1, &Rects, blimit))return(0); - memcpy(Rect,Rects,sizeof(U_PMF_RECTF)); - free(Rects); - return(1); -} - -/** - \brief Get data from a U_PMR_DRAWRECTS record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive) - \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates - \param Elements Number of members in Rects - \param Rects Caller must free. Array of U_PMF_RECTF rectangles to draw. - - EMF+ manual 2.3.4.13, Microsoft name: EmfPlusDrawRects Record, Index 0x0B - - Rects in record may be either U_PMF_RECT or U_PMF_RECTF, but this function always - returns U_PMF_RECTF -*/ -int U_PMR_DRAWRECTS_get(const char *contents, U_PMF_CMN_HDR *Header, - uint32_t *PenID, int *ctype, - uint32_t *Elements, - U_PMF_RECTF **Rects){ - if(!contents || !PenID || !Elements || !Rects){ return(0); } - - const char *blimit = contents; - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_DRAWPIE))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - blimit += lclHeader.Size; - - *PenID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); - U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); - U_PMF_VARRECTS_get(&contents, lclHeader.Flags, *Elements, Rects, blimit); - return(1); -} - -/** - \brief Get data from a U_PMR_DRAWSTRING record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param FontID U_PMF_FONT object in the EMF+ object table (0-63, inclusive) - \param btype Set: BrushID is an U_PFM_ARGB; Clear: index of U_PMF_BRUSH object in EMF+ object table. - \param BrushID Color or index of U_PMF_BRUSH object in the EMF+ object table, depending on btype. - \param FormatID U_PMF_STRINGFORMAT object in EMF+ Object Table. - \param Elements Number of characters in the string. - \param Rect String's bounding box. - \param String Caller must free. Array of UFT-16LE unicode characters. - - EMF+ manual 2.3.4.14, Microsoft name: EmfPlusDrawString Record, Index 0x1C -*/ -int U_PMR_DRAWSTRING_get(const char *contents, U_PMF_CMN_HDR *Header, - uint32_t *FontID, int *btype, - uint32_t *BrushID, uint32_t *FormatID, uint32_t *Elements, U_PMF_RECTF *Rect, - uint16_t **String){ - if(!contents || !FontID || !btype || !BrushID || !FormatID || !Elements || !String){ return(0); } - - const char *blimit = contents; - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_DRAWPIE))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - blimit += lclHeader.Size; - - *btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 ); - *FontID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */ - U_PMF_SERIAL_get(&contents, FormatID, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Rect, 4, 4, U_LE); - if(IS_MEM_UNSAFE(contents, *Elements * 2, blimit))return(0); - if(!U_PMF_SERIAL_array_copy_get(&contents, (void **)String, 2, *Elements, U_XE, 1)){ return(0); } - return(1); -} - -/** - \brief Get data from a U_PMR_FILLCLOSEDCURVE record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param btype Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table. - \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates - \param ftype Set: winding fill; Clear: alternate fill - \param RelAbs Set: Coordinates are relative; Clear: Coordinates are absolute and their type is set by ctype - \param BrushID Color or index of U_PMF_BRUSH object in the EMF+ object table, depending on btype. - \param Tension Controls splines, 0 is straight line, >0 is curved - \param Elements Number of members in Points - \param Points Caller must free. Array of U_POINT_F = Sequence of points to connect. Coordinate type set by ctype and RelAbs. - - EMF+ manual 2.3.4.15, Microsoft name: EmfPlusFillClosedCurve Record, Index 0x16 -*/ -int U_PMR_FILLCLOSEDCURVE_get(const char *contents, U_PMF_CMN_HDR *Header, - int *btype, int *ctype, int *ftype, int *RelAbs, - uint32_t *BrushID, U_FLOAT *Tension, uint32_t *Elements, - U_PMF_POINTF **Points){ - if(!contents || !btype || !ctype || !ftype || !RelAbs || !BrushID || !Tension || !Elements || !Points){ return(0); } - - const char *blimit = contents; - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_DRAWLINES))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - blimit += lclHeader.Size; - - *btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 ); - *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); - *ftype = (lclHeader.Flags & U_PPF_F ? 1 : 0 ); - *RelAbs = (lclHeader.Flags & U_PPF_P ? 1 : 0 ); - U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */ - U_PMF_SERIAL_get(&contents, Tension, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); - U_PMF_VARPOINTS_get(contents, lclHeader.Flags, *Elements, Points, blimit); - return(1); -} - -/** - \brief Get data from a U_PMR_FILLELLIPSE record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param btype Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table. - \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates - \param BrushID Color or index of U_PMF_BRUSH object in the EMF+ object table, depending on btype. - \param Rect Caller must free. Bounding box for elliptical pie segment being drawn. Coordinate type set by ctype. - - EMF+ manual 2.3.4.16, Microsoft name: EmfPlusFillEllipse Record, Index 0x0E -*/ -int U_PMR_FILLELLIPSE_get(const char *contents, U_PMF_CMN_HDR *Header, - int *btype, int *ctype, - uint32_t *BrushID, - U_PMF_RECTF *Rect){ - if(!contents || !btype || !ctype || !BrushID || !Rect){ return(0); } - - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_FILLELLIPSE))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - - *btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 ); - *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); - U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */ - U_PMF_SERIAL_get(&contents, Rect, 4, 4, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMR_FILLPATH record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param btype Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table. - \param PathID U_PMF_PATH object in the EMF+ object table (0-63, inclusive) - \param BrushID Color or index of U_PMF_BRUSH object in the EMF+ object table, depending on btype. - - EMF+ manual 2.3.4.17, Microsoft name: EmfPlusFillPath Record, Index 0x14 - - Note: U_PMF_FILLPATHOBJ is the object, U_PMF_FILLPATH is the file record -*/ -int U_PMR_FILLPATH_get(const char *contents, U_PMF_CMN_HDR *Header, - uint32_t *PathID, int *btype, - uint32_t *BrushID){ - if(!contents || !PathID || !btype || !BrushID){ return(0); } - - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_FILLPATH))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - - *btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 ); - *PathID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */ - return(1); -} - -/** - \brief Get data from a U_PMR_FILLPIE record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param btype Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table. - \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates - \param BrushID Color or index of U_PMF_BRUSH object in the EMF+ object table, depending on btype. - \param Start Start angle, >=0.0, degrees clockwise from 3:00 - \param Sweep Sweep angle, -360<= angle <=360, degrees clockwise from Start - \param Rect Bounding box for elliptical pie segment being filled. Coordinate type set by ctype. - - EMF+ manual 2.3.4.18, Microsoft name: EmfPlusFillPie Record, Index 0x10 -*/ -int U_PMR_FILLPIE_get(const char *contents, U_PMF_CMN_HDR *Header, - int *btype, int *ctype, - uint32_t *BrushID, U_FLOAT *Start, U_FLOAT *Sweep, - U_PMF_RECTF *Rect){ - if(!contents || !btype || !ctype || !BrushID || !Start || !Sweep || !Rect){ return(0); } - - const char *blimit = contents; - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_FILLPIE))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - blimit += lclHeader.Size; - - *btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 ); - *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); - U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */ - U_PMF_SERIAL_get(&contents, Start, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Sweep, 4, 1, U_LE); - U_PMF_RECTF *Rects = NULL; - if(!U_PMF_VARRECTS_get(&contents, lclHeader.Flags, 1, &Rects, blimit))return(0); - memcpy(Rect,Rects,sizeof(U_PMF_RECTF)); - free(Rects); - return(1); -} - -/** - \brief Get data from a U_PMR_FILLPOLYGON record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param btype Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table. - \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates - \param RelAbs Set: U_PMF_PathPointTypeRLE and/or U_PMF_PathPointType objects; Clear: only U_PMF_PathPointType - \param BrushID Color or index of U_PMF_BRUSH object in the EMF+ object table, depending on btype. - \param Elements Number of members in Data. - \param Points Sequence of points to connect with line segments. Coordinate type set by ctype and RelAbs. - - EMF+ manual 2.3.4.19, Microsoft name: EmfPlusFillPolygon Record, Index 0x0C -*/ -int U_PMR_FILLPOLYGON_get(const char *contents, U_PMF_CMN_HDR *Header, - int *btype, int *ctype, int *RelAbs, - uint32_t *BrushID, uint32_t *Elements, - U_PMF_POINTF **Points){ - if(!contents || !btype || !ctype || !RelAbs || !BrushID || !Elements || !Points){ return(0); } - - const char *blimit = contents; - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_DRAWLINES))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - blimit += lclHeader.Size; - - *btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 ); - *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); - *RelAbs = (lclHeader.Flags & U_PPF_R ? 1 : 0 ); - U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */ - U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); - U_PMF_VARPOINTS_get(contents, lclHeader.Flags, *Elements, Points, blimit); - return(1); -} - -/** - \brief Get data from a U_PMR_FILLRECTS record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param btype Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table. - \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates - \param BrushID Color or index of U_PMF_BRUSH object in the EMF+ object table, depending on btype. - \param Elements Number of members in Data. - \param Rects Caller must free. Array of U_PMF_RECTF rectangles to draw. - - EMF+ manual 2.3.4.20, Microsoft name: EmfPlusFillRects Record, Index 0x0A - - EMF+ files have been encountered where BrushID must be a color, because it has a value like FFFF0000 but - the flags are set wrong, so that U_PPF_B is not set. Detect these by BrushID >63 for btype=0 and correct. - If the opposite problem occurs it cannot be reliably detected, so it cannot be corrected. - - Rects in record may be either U_PMF_RECT or U_PMF_RECTF, but this function always - returns U_PMF_RECTF -*/ -int U_PMR_FILLRECTS_get(const char *contents, U_PMF_CMN_HDR *Header, - int *btype, int *ctype, - uint32_t *BrushID, uint32_t *Elements, - U_PMF_RECTF **Rects){ - if(!contents || !btype || !ctype || !BrushID || !Elements || !Rects){ return(0); } - - const char *blimit = contents; - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_FILLRECTS))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - blimit += lclHeader.Size; - - *btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 ); - *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); - U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */ - U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); - U_PMF_VARRECTS_get(&contents, lclHeader.Flags, *Elements, Rects, blimit); - /* correct btype, if necessary, for invalid EMF+ input */ - if((*BrushID > 63) & !*btype)*btype=1; - return(1); -} - - -/** - \brief Get data from a U_PMR_FILLREGION record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param RgnID U_PMF_REGION object in the EMF+ object table (0-63, inclusive) - \param btype Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table. - \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates - \param BrushID Color or index of U_PMF_BRUSH object in the EMF+ object table, depending on btype. - - EMF+ manual 2.3.4.21, Microsoft name: EmfPlusFillRegion Record, Index 0x13 -*/ -int U_PMR_FILLREGION_get(const char *contents, U_PMF_CMN_HDR *Header, - uint32_t *RgnID, int *btype, int *ctype, - uint32_t *BrushID){ - if(!contents || !RgnID || !btype || !ctype || !BrushID){ return(0); } - - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_FILLREGION))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - - *btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 ); - *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); - *RgnID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */ - return(1); -} - -/** - \brief Get data from a U_PMR_OBJECT record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param ObjID Index for this object in the EMF+ object table (0-63, inclusive) - \param otype ObjectType enumeration - \param ntype Set: object definition continue bit is set - \param TSize If ntype is set, holds the total number of data bytes split across multiple records. If ntype is clear, has no meaning. - \param Data Object's data. Type from otype. - - EMF+ manual 2.3.5.1, Microsoft name: EmfPlusObject Record, Index 0x13 - - Caller must check Data for possible memory access violations. - - OTHER NOTES: - All objects are to be stored in the same table and retrieved by index. - Documentation indicates that this table contains only 64 slots, although the index - field which references it can code for values 0-127. - If a new object has the same index as an existing object the old one is deleted and - the new one goes into its storage slot. - The continuation bit (U_PPF_N) is documented as indicating that the object is continued into - the next record. Examination of emf+ records in emf files produced by PowerPoint 2003 - show that changing the ObjID also serves as a continued record terminator, and that it apparently - overrides the value for the continue bit. That is, even though the preceding records said - that it was continued, the change of ObjID terminates that preceding record without adding - any more data to it. In one example the sequential emf+ records were: - ObjID type size continue - 0 5 65008 Y - 0 5 65008 Y - 0 5 63104 Y - 1 8 24 N - A DrawImagePoints record followed that referenced ObjID 0. - Examination of the records with continue set showed that data in each - was preceded by a uint32_t size value equivalent to the size of the - data that had been split across multiple records, in this case - 0x0002F254 = 193108. It is not clear at present if this size value - will also be present at the end of a continued series that terminates - by not using the continue bit, rather than changing the ObjID. -*/ -int U_PMR_OBJECT_get(const char *contents, U_PMF_CMN_HDR *Header, - uint32_t *ObjID, int *otype, int *ntype, uint32_t *TSize, - const char **Data){ - if(!contents || !ObjID || !otype || !ntype || !Data){ return(0); } - - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_OBJECT))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - - *ntype = (lclHeader.Flags & U_PPF_N ? 1 : 0 ); - *ObjID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - *otype = (lclHeader.Flags >> U_FF_SHFT_OT) & U_FF_MASK_OT; - if(*ntype){ U_PMF_SERIAL_get(&contents, TSize, 4, 1, U_LE); } - else { *TSize = 0; } - U_PMF_PTRSAV_SHIFT(Data, &contents, 0); - return(1); -} - -/** - \brief Get data from a U_PMR_SERIALIZABLEOBJECT record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param GUID ImageEffects identifier. - \param Size Bytes in Data. - \param Data "Serialized image effects parameter block". One of the ImageEffects objects. - - EMF+ manual 2.3.5.2, Microsoft name: EmfPlusSerializableObject Record, Index 0x38 - - Caller must check Data for possible memory access violations. -*/ -int U_PMR_SERIALIZABLEOBJECT_get(const char *contents, U_PMF_CMN_HDR *Header, - uint8_t *GUID, uint32_t *Size, - const char **Data){ - if(!contents || !GUID || !Size || !Data){ return(0); } - - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_SERIALIZABLEOBJECT))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - - U_PMF_SERIAL_get(&contents, GUID, 1, 16, U_XE); - U_PMF_SERIAL_get(&contents, Size, 4, 1, U_LE); - U_PMF_PTRSAV_SHIFT(Data, &contents, 0); - return(1); -} - -/** - \brief Get data from a U_PMR_SETANTIALIASMODE record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param SMenum SmoothingMode enumeration - \param aatype Set: anti-aliasing on; Clear: anti-aliasing off - - EMF+ manual 2.3.6.1, Microsoft name: EmfPlusSetAntiAliasMode Record, Index 0x1E -*/ -int U_PMR_SETANTIALIASMODE_get(const char *contents, U_PMF_CMN_HDR *Header, - int *SMenum, int *aatype){ - if(!contents || !SMenum || !aatype){ return(0); } - - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_SETANTIALIASMODE))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - - *aatype = (lclHeader.Flags & U_PPF_AA ? 1 : 0 ); - *SMenum = (lclHeader.Flags >> U_FF_SHFT_AA) & U_FF_MASK_AA; - return(1); -} - -/** - \brief Get data from a U_PMR_SETCOMPOSITINGMODE record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param CMenum CompositingMode enumeration - - EMF+ manual 2.3.6.2, Microsoft name: EmfPlusSetCompositingMode Record, Index 0x23 -*/ -int U_PMR_SETCOMPOSITINGMODE_get(const char *contents, U_PMF_CMN_HDR *Header, - int *CMenum){ - /* memory access safe, only uses the common header */ - if(!contents || !CMenum){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *CMenum = (Flags >> U_FF_SHFT_CM) & U_FF_MASK_CM; - U_PMF_CMN_HDR_get(&contents, Header); - return(1); -} - -/** - \brief Get data from a U_PMR_SETCOMPOSITINGQUALITY record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param CQenum CompositingQuality enumeration - - EMF+ manual 2.3.6.3, Microsoft name: EmfPlusSetCompositingQuality Record, Index 0x24 -*/ -int U_PMR_SETCOMPOSITINGQUALITY_get(const char *contents, U_PMF_CMN_HDR *Header, - int *CQenum){ - /* memory access safe, only uses the common header */ - if(!contents || !CQenum){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *CQenum = (Flags >> U_FF_SHFT_CQ) & U_FF_MASK_CQ; - U_PMF_CMN_HDR_get(&contents, Header); - return(1); -} - -/** - \brief Get data from a U_PMR_SETINTERPOLATIONMODE record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param IMenum InterpolationMode enumeration - - EMF+ manual 2.3.6.4, Microsoft name: EmfPlusSetInterpolationMode Record, Index 0x21 -*/ -int U_PMR_SETINTERPOLATIONMODE_get(const char *contents, U_PMF_CMN_HDR *Header, - int *IMenum){ - /* memory access safe, only uses the common header */ - if(!contents || !IMenum){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *IMenum = (Flags >> U_FF_SHFT_IM) & U_FF_MASK_IM; - U_PMF_CMN_HDR_get(&contents, Header); - return(1); -} - -/** - \brief Get data from a U_PMR_SETPIXELOFFSETMODE record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param POMenum PixelOffsetMode enumeration. - - EMF+ manual 2.3.6.5, Microsoft name: EmfPlusSetPixelOffsetMode Record, Index 0x22 -*/ -int U_PMR_SETPIXELOFFSETMODE_get(const char *contents, U_PMF_CMN_HDR *Header, - int *POMenum){ - /* memory access safe, only uses the common header */ - if(!contents || !POMenum){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *POMenum = (Flags >> U_FF_SHFT_PxOffM) & U_FF_MASK_PxOffM; - U_PMF_CMN_HDR_get(&contents, Header); - return(1); -} - -/** - \brief Get data from a U_PMR_SETRENDERINGORIGIN record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header. - \param X X coordinate of rendering origin. - \param Y Y coordinate of rendering origin. - - EMF+ manual 2.3.6.6, Microsoft name: EmfPlusSetRenderingOrigin Record, Index 0x1D -*/ -int U_PMR_SETRENDERINGORIGIN_get(const char *contents, U_PMF_CMN_HDR *Header, - int32_t *X, int32_t *Y){ - if(!contents || !X || !Y){ return(0); } - - U_PMF_CMN_HDR lclHeader; - if(!U_PMF_CMN_HDR_get(&contents, &lclHeader))return(0); - if(lclHeader.Size < sizeof(U_PMF_SETRENDERINGORIGIN))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - - U_PMF_SERIAL_get(&contents, X, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Y, 4, 1, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMR_SETTEXTCONTRAST record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header. - \param TGC Text Gamma correction value (x 1000). - - EMF+ manual 2.3.6.7, Microsoft name: EmfPlusSetTextContrast Record, Index 0x20 -*/ -int U_PMR_SETTEXTCONTRAST_get(const char *contents, U_PMF_CMN_HDR *Header, - int *TGC){ - /* memory access safe, only uses the common header */ - if(!contents || !TGC){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *TGC = (Flags >> U_FF_SHFT_TGC) & U_FF_MASK_TGC; - U_PMF_CMN_HDR_get(&contents, Header); - return(1); -} - -/** - \brief Get data from a U_PMR_SETTEXTRENDERINGHINT record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header. - \param TRHenum TextRenderingHint enumeration - - EMF+ manual 2.3.6.8, Microsoft name: EmfPlusSetTextRenderingHint Record, Index 0x1F -*/ -int U_PMR_SETTEXTRENDERINGHINT_get(const char *contents, U_PMF_CMN_HDR *Header, - int *TRHenum){ - /* memory access safe, only uses the common header */ - if(!contents || !TRHenum){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *TRHenum = (Flags >> U_FF_SHFT_TRH) & U_FF_MASK_TRH; - U_PMF_CMN_HDR_get(&contents, Header); - return(1); -} - -/** - \brief Get data from a U_PMR_BEGINCONTAINER record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param UTenum UnitType enumeration - \param DstRect with SrcRect specifies a transformation - \param SrcRect with DstRect specifies a transformation - \param StackID EMF+ Object Stack Index to use for this graphics container - - EMF+ manual 2.3.7.1, Microsoft name: EmfPlusBeginContainer Record, Index 0x27 -*/ -int U_PMR_BEGINCONTAINER_get(const char *contents, U_PMF_CMN_HDR *Header, - int *UTenum, - U_PMF_RECTF *DstRect, U_PMF_RECTF *SrcRect, uint32_t *StackID){ - if(!contents || !UTenum || !DstRect || !SrcRect || !StackID){ return(0); } - - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_SETCLIPREGION))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - - *UTenum = (lclHeader.Flags >> U_FF_SHFT_UT) & U_FF_MASK_UT; - U_PMF_SERIAL_get(&contents, DstRect, 4, 4, U_LE); - U_PMF_SERIAL_get(&contents, SrcRect, 4, 4, U_LE); - U_PMF_SERIAL_get(&contents, StackID, 4, 1, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMR_BEGINCONTAINERNOPARAMS record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param StackID EMF+ Object Stack Index to use for this graphics container - - EMF+ manual 2.3.7.2, Microsoft name: EmfPlusBeginContainerNoParams Record, Index 0x28 -*/ -int U_PMR_BEGINCONTAINERNOPARAMS_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *StackID){ - return(U_PMR_common_stack_get(contents, Header, StackID)); -} - -/** - \brief Get data from a U_PMR_ENDCONTAINER record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param StackID EMF+ Object Stack Index of this graphics container - - EMF+ manual 2.3.7.3, Microsoft name: EmfPlusEndContainer Record, Index 0x29 -*/ -int U_PMR_ENDCONTAINER_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *StackID){ - return(U_PMR_common_stack_get(contents, Header, StackID)); -} - -/** - \brief Get data from a U_PMR_RESTORE record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param StackID State (level) to restore from the EMF+ Graphics Stack. Must have been put on the GS with a U_PMR_SAVE. - - EMF+ manual 2.3.7.4, Microsoft name: EmfPlusRestore Record, Index 0x26 -*/ -int U_PMR_RESTORE_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *StackID){ - return(U_PMR_common_stack_get(contents, Header, StackID)); -} - -/** - \brief Get data from a U_PMR_SAVE record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param StackID State (level) to save.on the EMF+ Graphics Stack - - EMF+ manual 2.3.7.5, Microsoft name: EmfPlusSave Record, Index 0x25 -*/ -int U_PMR_SAVE_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *StackID){ - return(U_PMR_common_stack_get(contents, Header, StackID)); -} - -/** - \brief Get data from a U_PMR_SETTSCLIP record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates - \param Elements Number of members in Data. - \param Rects Caller must free. Array of rectangles to draw. Coordinate type set by ctype. - - EMF+ manual 2.3.8.1, Microsoft name: EmfPlusSetTSClip Record, Index 0x3A -*/ -int U_PMR_SETTSCLIP_get(const char *contents, U_PMF_CMN_HDR *Header, - int *ctype, uint32_t *Elements, - U_PMF_RECTF **Rects){ - if(!contents || !ctype || !Elements || !Rects){ return(0); } - - const char *blimit = contents; - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_SETTSCLIP))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - blimit += lclHeader.Size; - - *ctype = (lclHeader.Flags & U_PPF_K ? 1 : 0 ); - *Elements = (lclHeader.Flags >> U_FF_SHFT_TSC) & U_FF_MASK_TSC; - U_PMF_VARRECTS_get(&contents, lclHeader.Flags, *Elements, Rects, blimit); - return(1); -} - -/** - \brief Get data from a U_PMR_SETTSGRAPHICS record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param vgatype Set: Palette is VGA basic colors; Clear: Palette is ??? - \param pptype Set: Palette is present; Clear: Palette is absent. - \param AntiAliasMode SmoothingMode enumeration - \param TextRenderHint TextRenderingHint enumeration - \param CompositingMode CompositingMode enumeration - \param CompositingQuality CompositingQuality enumeration - \param RenderOriginX Origin X for halftoning and dithering - \param RenderOriginY Origin Y for halftoning and dithering - \param TextContrast Gamma correction, range 0 to 12 - \param FilterType FilterType enumeraton - \param PixelOffset PixelOffsetMode enumeration - \param WorldToDevice world to device transform - \param Data Palette (optional) - - EMF+ manual 2.3.8.2, Microsoft name: EmfPlusSetTSGraphics Record, Index 0x39 - - Caller must check Data for possible memory access violations. -*/ -int U_PMR_SETTSGRAPHICS_get(const char *contents, U_PMF_CMN_HDR *Header, - int *vgatype, int *pptype, - uint8_t *AntiAliasMode, uint8_t *TextRenderHint, uint8_t *CompositingMode, uint8_t *CompositingQuality, - int16_t *RenderOriginX, int16_t *RenderOriginY, uint16_t *TextContrast, uint8_t *FilterType, - uint8_t *PixelOffset, U_PMF_TRANSFORMMATRIX *WorldToDevice, - const char **Data){ - if(!contents || !vgatype || !pptype || - !AntiAliasMode || !TextRenderHint || !CompositingMode || !CompositingQuality || - !RenderOriginX || !RenderOriginY || !TextContrast || !FilterType || - !PixelOffset || !WorldToDevice || !Data){ return(0); } - - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_SETTSGRAPHICS))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - - *vgatype = (lclHeader.Flags & U_PPF_VGA ? 1 : 0 ); - *pptype = (lclHeader.Flags & U_PPF_PP ? 1 : 0 ); - U_PMF_SERIAL_get(&contents, AntiAliasMode, 1, 1, U_XE); - U_PMF_SERIAL_get(&contents, TextRenderHint, 1, 1, U_XE); - U_PMF_SERIAL_get(&contents, CompositingMode, 1, 1, U_XE); - U_PMF_SERIAL_get(&contents, CompositingQuality, 1, 1, U_XE); - U_PMF_SERIAL_get(&contents, RenderOriginX, 2, 1, U_LE); - U_PMF_SERIAL_get(&contents, RenderOriginY, 2, 1, U_LE); - U_PMF_SERIAL_get(&contents, TextContrast, 2, 1, U_LE); - U_PMF_SERIAL_get(&contents, FilterType, 1, 1, U_XE); - U_PMF_SERIAL_get(&contents, WorldToDevice, 4, 6, U_LE); - U_PMF_PTRSAV_COND(Data, contents, *pptype); - return(1); -} - -/** - \brief Get data from a U_PMR_MULTIPLYWORLDTRANSFORM record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param xmtype Set: Post multiply; Clear: Pre multiply - \param Matrix Transformation matrix - - EMF+ manual 2.3.9.1, Microsoft name: EmfPlusMultiplyWorldTransform Record, Index 0x2C -*/ -int U_PMR_MULTIPLYWORLDTRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header, - int *xmtype, - U_PMF_TRANSFORMMATRIX *Matrix){ - if(!contents || !xmtype || !Matrix){ return(0); } - - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_MULTIPLYWORLDTRANSFORM))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - - *xmtype = (lclHeader.Flags & U_PPF_XM ? 1 : 0 ); - U_PMF_SERIAL_get(&contents, Matrix, 4, 6, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMR_RESETWORLDTRANSFORM record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - - EMF+ manual 2.3.9.2, Microsoft name: EmfPlusResetWorldTransform Record, Index 0x2B -*/ -int U_PMR_RESETWORLDTRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header){ - return( U_PMR_common_header_get(contents,Header)); -} - -/** - \brief Get data from a U_PMR_ROTATEWORLDTRANSFORM record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param xmtype Set: Post multiply; Clear: Pre multiply - \param Angle Rotation angle, in degrees - - EMF+ manual 2.3.9.3, Microsoft name: EmfPlusRotateWorldTransform Record, Index 0x2F -*/ -int U_PMR_ROTATEWORLDTRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header, - int *xmtype, - U_FLOAT *Angle){ - if(!contents || !xmtype || !Angle){ return(0); } - - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_ROTATEWORLDTRANSFORM))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - - *xmtype = (lclHeader.Flags & U_PPF_XM ? 1 : 0 ); - U_PMF_SERIAL_get(&contents, Angle, 4, 1, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMR_SCALEWORLDTRANSFORM record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param xmtype Set: Post multiply; Clear: Pre multiply. - \param Sx X scale factor. - \param Sy Y scale factor. - - EMF+ manual 2.3.9.4, Microsoft name: EmfPlusScaleWorldTransform Record, Index 0x2E -*/ -int U_PMR_SCALEWORLDTRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header, - int *xmtype, - U_FLOAT *Sx, U_FLOAT *Sy){ - if(!contents || !xmtype || !Sx || !Sy){ return(0); } - - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_SCALEWORLDTRANSFORM))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - - *xmtype = (lclHeader.Flags & U_PPF_XM ? 1 : 0 ); - U_PMF_SERIAL_get(&contents, Sx, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Sy, 4, 1, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMR_SETPAGETRANSFORM record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param PUenum Page Unit, UnitType enumeration - \param Scale Scale factor to convert page space to device space - - EMF+ manual 2.3.9.5, Microsoft name: EmfPlusSetPageTransform Record, Index 0x30 -*/ -int U_PMR_SETPAGETRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header, - int *PUenum, - U_FLOAT *Scale){ - if(!contents || !PUenum || !Scale){ return(0); } - - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_SETPAGETRANSFORM))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - - *PUenum = (lclHeader.Flags >> U_FF_SHFT_PU) & U_FF_MASK_PU; - U_PMF_SERIAL_get(&contents, Scale, 4, 1, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMR_SETWORLDTRANSFORM record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param Matrix Transformation matrix - - EMF+ manual 2.3.9.6, Microsoft name: EmfPlusSetWorldTransform Record, Index 0x2A -*/ -int U_PMR_SETWORLDTRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header, - U_PMF_TRANSFORMMATRIX *Matrix){ - if(!contents || !Matrix){ return(0); } - - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_SETWORLDTRANSFORM))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - - U_PMF_SERIAL_get(&contents, Matrix, 4, 6, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMR_TRANSLATEWORLDTRANSFORM record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header - \param xmtype Set: Post multiply; Clear: Pre multiply - \param Dx X offset - \param Dy Y offset - - EMF+ manual 2.3.9.7, Microsoft name: EmfPlusTranslateWorldTransform Record, Index 0x2D -*/ -int U_PMR_TRANSLATEWORLDTRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header, - int *xmtype, - U_FLOAT *Dx, U_FLOAT *Dy){ - if(!contents || !xmtype || !Dx || !Dy){ return(0); } - - U_PMF_CMN_HDR lclHeader; - U_PMF_CMN_HDR_get(&contents, &lclHeader); - if(lclHeader.Size < sizeof(U_PMF_TRANSLATEWORLDTRANSFORM))return(0); - if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } - - *xmtype = (lclHeader.Flags & U_PPF_XM ? 1 : 0 ); - U_PMF_SERIAL_get(&contents, Dx, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Dy, 4, 1, U_LE); - return(1); -} - -/** - \brief Get data from a U_PMR_STROKEFILLPATH record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header (ignore flags) - - - EMF+ manual mentioned in 2.1.1.1, not otherwise documented, Microsoft name: EmfPlusStrokeFillPath Record, Index 0x37 - - "This record closes any open figures in a path, strokes the outline of - the path by using the current pen, and fills its interior by using the current brush." -*/ -int U_PMR_STROKEFILLPATH_get(const char *contents, U_PMF_CMN_HDR *Header){ - return( U_PMR_common_header_get(contents,Header)); -} - -/** - \brief Get data from a U_PMR_MULTIFORMATSTART record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header (ignore flags) - - EMF+ manual mentioned in 2.1.1.1, reserved, not otherwise documented, Microsoft name: EmfPlusMultiFormatStart Record, Index 0x05 -*/ -int U_PMR_MULTIFORMATSTART_get(const char *contents, U_PMF_CMN_HDR *Header){ - return( U_PMR_common_header_get(contents,Header)); -} - -/** - \brief Get data from a U_PMR_MULTIFORMATSECTION record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header (ignore flags) - - EMF+ manual mentioned in 2.1.1.1, reserved, not otherwise documented, Microsoft name: EmfPlusMultiFormatSection Record, Index 0x06 -*/ -int U_PMR_MULTIFORMATSECTION_get(const char *contents, U_PMF_CMN_HDR *Header){ - return( U_PMR_common_header_get(contents,Header)); -} - -/** - \brief Get data from a U_PMR_MULTIFORMATEND record - \return 1 on success, 0 on error - \param contents Record from which to extract data - \param Header Common header (ignore flags) - - EMF+ manual mentioned in 2.1.1.1, reserved, not otherwise documented, Microsoft name: EmfPlusMultiFormatEnd Record, Index 0x06 -*/ -int U_PMR_MULTIFORMATEND_get(const char *contents, U_PMF_CMN_HDR *Header){ - return( U_PMR_common_header_get(contents,Header)); -} - - -#ifdef __cplusplus -} -#endif |
