4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico @brief Functions for manipulating EMF+ files and structures.
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico EMF+ is much more object based than is EMF or WMF, so the U_PMR_*_set and most U_PMF_*_set functions
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico return a pointer to a PseudoObject. PseudoObjects are structs that contain a data field to hold the
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico object in EMF+ file byte order, size information, and some type information. This is sufficient to allow
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico complex records to be built up from the various sorts of nested objects which they normally contain.
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico If something goes wrong a NULL pointer is returned and recsize is set to 0.
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico EMF+ does not use a separate set of endian functions, _get and _set routines convert from/to
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico the EMF+ file byte order on the fly.
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico WARNING: Microsoft's EMF+ documentation is little-endian for everything EXCEPT
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico bitfields, which are big-endian. See EMF+ manual section 1.3.2
107e00c8104649437b9520d0ba298dba659e7cd7JazzyNico That documentation also uses 0 as the MOST significant bit, N-1 as the least.
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico This code is little-endian throughout, and 0 is the LEAST significant bit
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapennerVersion: 0.0.12
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapennerDate: 26-JAN-2016
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapennerAuthor: David Mathog, Biology Division, Caltech
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenneremail: mathog@caltech.edu
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapennerCopyright: 2016 David Mathog and California Institute of Technology (Caltech)
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapennerextern "C" {
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico#include <math.h> // for sin, cos, tan2, use U_ROUND() instead of roundf()
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico#include <windef.h> //Not actually used, looking for collisions
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico#include <winnt.h> //Not actually used, looking for collisions
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico#include <wingdi.h> //Not actually used, looking for collisions
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico/// things Doxygen should not process
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico/* remove this after debugging is completed */
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico/* Prototypes for functions used here and defined in uemf_endian.c, but which are not supposed
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNicoto be used in end user code. */
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico \brief Utility function for writing one or more EMF+ records in a PseudoObject to the EMF output file
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico \return 1 on success, 0 on error.
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico \param po U_PSEUDO_OBJ to write, it is deleted after it is written
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico \param sum U_PSEUDO_OBJ to use for scratch space
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico \param et EMFTRACK used to write records to EMF file
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNicoint U_PMR_write(U_PSEUDO_OBJ *po, U_PSEUDO_OBJ *sum, EMFTRACK *et){
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico sum->Used = 0; /* clean it out, retaining allocated memory */
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico sum = U_PO_append(sum, "EMF+", 4); /* indicates that this comment holds an EMF+ record */
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico sum = U_PO_append(sum, po->Data, po->Used); /* the EMF+ record itself */
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico rec = U_EMRCOMMENT_set(sum->Used, sum->Data); /* stuff it into the EMF comment */
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico if(!emf_append((PU_ENHMETARECORD)rec, et, 1))goto end; /* write it to the EMF file, delete the record, check status */
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico \brief Utility function to draw a line.
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico \return 1 on success, 0 on error.
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico \param PenID Index of U_PMF_PEN object to use in the EMF+ object table (0-63, inclusive)
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico \param PathID Index of U_PMF_PATH object to use in the EMF+ object table (0-63, inclusive)
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \param Start U_PMF_POINTF coordinates of start of line.
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \param End U_PMF_POINTF coordinates of end of line.
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \param Dashed Set if the line is dashed, clear if it is not.
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \param sum PseudoObject used for scratch space
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \param et EMFTRACK used to write records to EMF file
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapennerint 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){
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner int PTP_value = ( Dashed ? U_PTP_DashMode : U_PTP_None);
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner dpath = U_PATH_create(0, NULL, 0, 0); /* create an empty path*/
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner if(U_PATH_moveto(dpath, Start, PTP_value) && U_PATH_lineto(dpath, End, PTP_value)){
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner poPath = U_PMF_PATH_set2(U_PMF_GRAPHICSVERSIONOBJ_set(2), dpath);
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \brief Utility function for drawing strings onto the baseline in one call.
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \return 1 on success, 0 on error.
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \param string Text to draw in UTF-8 format
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \param Vpos StringAlignment Enumeration. Always drawn on baseline, but using one of these three modes.
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \param FontID Index of U_PMF_FONT object to use in the EMF+ object table (0-63, inclusive)
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \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)
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \param FormatID index of U_PMF_STRINGFORMAT object to use in the EMF+ Object Table.
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \param Sfs StringFormat structure. Ignored values: StringAlignment, LineAlign, Flags
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \param FontName Name of font to draw with
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \param Height Height of font in pixels (positive)
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \param fip U_FontInfoParams (ascent, descent, and so forth)
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \param FontFlags FontStyle Flags
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \param x X position in pixels of left side of EM box of first character
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \param y Y position in pixels of baseline of first character
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \param sum PseudoObject used for scratch space
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \param et EMFTRACK used to write records to EMF file
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner EMF+ manual 2.3.4.14, Microsoft name: EmfPlusDrawString Record, Index 0x1C
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner For most fonts Ascent and Descent are used to adjust the bounding box to properly position the
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner baseline. Some fonts, like Verdana, are strange and they position the baseline on the bottom of
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner the bounding box if that box has the same height as the font. For those fonts specify 0.0 for
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner both Ascent and Descent.
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapennerint U_PMR_drawstring( const char *string, int Vpos, uint32_t FontID, const U_PSEUDO_OBJ *BrushID, uint32_t FormatID,
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner U_PMF_STRINGFORMAT Sfs, const char *FontName, U_FLOAT Height, U_FontInfoParams *fip, uint32_t FontFlags,
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner U_FLOAT x, U_FLOAT y, U_PSEUDO_OBJ *sum, EMFTRACK *et){
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner poFont = U_PMF_FONT_set(U_PMF_GRAPHICSVERSIONOBJ_set(2), Height, U_UT_World, FontFlags, slen, UFontName);
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner po = U_PMR_OBJECT_PO_set(FontID, poFont); /* font to use */
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner rw = 4*Height*slen; /* This could probably be any value */
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner if(fip->LineGap > -fip->Descent){ aval = fip->yMax; } // sylfaen, palatino
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner if(fip->LineGap && (fip->LineGap < -fip->Descent)){ dval = ((double) (fip->Descent - fip->LineGap)) / ((double) fip->EmSize); } //shruti and some others
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner else { dval = ((double) fip->Descent ) / ((double) fip->EmSize); }
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner rd = 0.5 * ( Height * aval / ((double) fip->EmSize) + Height * ( 1.0 + dval));
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner ry = y - rd; /* draw from upper left corner, which is shifted to put baseline on y */
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner(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);
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner(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);
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner(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);
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner(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);
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner(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);
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner(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);
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner(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);
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner(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);
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner po = U_PMR_DRAWSTRING_set(FontID, BrushID, FormatID, slen, poRect, Text16);
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \brief Allocate and construct an array of U_POINT16 objects from a set of U_PMF_POINTF objects, endianness in and out is LE
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \returns pointer to an array of U_POINT16 structures.
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \param points pointer to the source U_POINT structures
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \param count number of members in points
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner If a coordinate is out of range it saturates at boundary.
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapennerU_PMF_POINT *POINTF_To_POINT16_LE(U_PMF_POINTF *points, int count){
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner newpts = (U_PMF_POINT *) malloc(count * sizeof(U_PMF_POINT));
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner for(i=0; i<count; i++){
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner if(U_BYTE_SWAP){ U_swap4(&ptfl,2); } /* on BE platforms swap going in and coming out */
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \brief Look up the name of the EMR+ record by type. Returns U_EMR_INVALID if out of range.
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \return name of the PMR record, "U_EMR_INVALID" if out of range.
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner \param idx PMR record type WITHOUT the U_PMR_RECFLAG bit.
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner "U_PMR_INVALID",
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner "U_PMR_Header",
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner "U_PMR_EndOfFile",
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner "U_PMR_Comment",
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner "U_PMR_GetDC",
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner "U_PMR_MultiFormatStart",
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner "U_PMR_MultiFormatSection",
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner "U_PMR_MultiFormatEnd",
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner "U_PMR_Object",
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner "U_PMR_Clear",
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner "U_PMR_FillRects",
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner "U_PMR_DrawRects",
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner "U_PMR_FillPolygon",
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner "U_PMR_DrawLines",
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner "U_PMR_FillEllipse",
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner "U_PMR_DrawEllipse",
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner "U_PMR_FillPie",
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner "U_PMR_DrawPie",
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner "U_PMR_DrawArc",
ffbd2f8fa3a83d1d4ad8cd672cf738ffaa5cdfeeapenner "U_PMR_FillRegion",
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico "U_PMR_FillPath",
4a7ebbf91a516d588a7dcc45921c17a896b65f62JazzyNico "U_PMR_DrawPath",
return(otype);
return(otype);
return(otype);
return(otype);
if( OID==U_PMF_REGIONNODECHILDNODES_OID ){ otype = U_RNDT_Kids; } /* there are 5 types, which must be specified separately */
return(otype);
if(!newaccum){
\param Data Data to copy into the PseudoObject's data. If NULL, space is allocated, but is cleared instead of filled.
if(po){
return(po);
\param Data Data to copy into the PseudoObject's data. If NULL, space is allocated (if necessary) and cleared instead of filled.
/* 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(!newData){
return(po);
if((StripE && (Src->Used == 4)) || !Src->Used){ return(po); } /* appending nothing is not an error */
if(!ipo){
if(ipo){
if(!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 */
return(ipo);
if(!po)return(0);
Each U_SERIAL_DESC element in List consists of Data fields and a description of that data. List is terminated
if a Ptr is NOT NULL, and Units * Reps is not zero, then the data is stored in the indicated byte order.
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,
if(po){
return(po);
\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.
U_DPSEUDO_OBJ *U_PATH_create(int Elements, const U_PMF_POINTF *Points, uint8_t First, uint8_t Others){
if(Elements){
U_DPSEUDO_OBJ *Path = (U_DPSEUDO_OBJ *)calloc(sizeof(U_DPSEUDO_OBJ),1); /* make poTypes and poPoints NULL */
if(Path){
if(!Elements){
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*/
return(Path);
if(!dpo){ return(0); }
if(!dpo){ return(0); }
\param Flags Flags may be (U_PTP_None, U_PTP_DashMode, U_PTP_PathMarker, U_PTP_NoBit, U_PTP_CloseSubpath)
if(!Path){ return(0); }
if(!tpo){ return(0); }
if(!tpo2)return(0);
if(!tpo){ return(0); }
if(!tpo2)return(0);
\param Flags Flags may be (U_PTP_None, U_PTP_DashMode, U_PTP_PathMarker, U_PTP_NoBit, U_PTP_CloseSubpath)
if(Path->poTypes->Data[Path->Elements - 1] & U_PTP_CloseSubpath){ return(0); } /* cannot extend a closed subpath */
if(!tpo){ return(0); }
if(!tpo2)return(0);
if(!tpo){ return(0); }
if(!tpo2)return(0);
\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.
int U_PATH_polylineto(U_DPSEUDO_OBJ *Path, uint32_t Elements, const U_PMF_POINTF *Points, uint8_t Flags, uint8_t StartSeg){
if(!tpo2)return(0);
if(!tpo){ return(0); }
if(!tpo2)return(0);
\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.
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(!Elements){
if(!tpo2)return(0);
if(!tpo){ return(0); }
if(!tpo2)return(0);
\param Flags Flags (U_PTP_None, U_PTP_DashMode, U_PTP_PathMarker, U_PTP_NoBit, but NOT U_PTP_CloseSubpath)
int U_PATH_polygon(U_DPSEUDO_OBJ *Path, uint32_t Elements, const U_PMF_POINTF *Points, uint8_t Flags){
if(status){
return(status);
return(point);
return(point);
return(Alpha);
U_PMF_POINTF U_qparam(double Alpha, double a, double b, U_PMF_POINTF *Point, double Ang, double Theta, int mode){
\brief Append an "arcto" set of points to a path (Bezier points are calculated, and these are appended
\param Rot Rotation angle to apply to coordinate system (Start and Rect), positive is degrees clockwise
\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.
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){
if(!Path){ 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. */
while(!done){
if(Sweep < 0){
else {done = 0; }
else {done = 0; }
if(!fpoint){
\brief Allocate and construct an array of U_PMF_POINTF objects which have been subjected to a U_XFORM
if(newpts){
for(i=0; i<count; i++){
X = points[i].X;
Y = points[i].Y;
return(newpts);
\brief Allocate and construct an array of U_PMF_RECTF objects which have been subjected to a U_XFORM
if(newRects){
for(i=0; i<Count; i++){
return(newRects);
\brief Utility function calculate the transformation matrix needed to make a gradient run precisely corner to corner of a rectangle
\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){
#define CLOSE_TO_IS_REALLY_ZERO(A) ((A) > 1.0e-10 || (A) < -1.0e-10 ? (A) : 0.0) //! \hideinitializer
The numberator of scale is the max of the four dot product values of the rotated X basis unit vector with (w,h),
to the opposite corner. The one most parallel to the rotated unit vector will have both terms positive.
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.
return tm;
\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)
if(po){
return(po);
U_XE no change (this is used when the data has already been set to the proper orientation or it is not known)
\param Dst Caller must free. Where the pointer to the data will be stored. Reps * Units bytes will be allocated,
U_XE no change (this is used when the data has already been set to the proper orientation or it is not known)
int U_PMF_SERIAL_array_copy_get(const char **Src, void **Dst, size_t Units, size_t Reps, int SE, int Cond){
if(!Cond){
\brief Calculate the length in bytes of a relative path object composed of U_PMF_INTEGER7 and U_PMF_INTER15 values
return(length);
\brief Calculate the length in bytes of objects which are a 4 byte Count followed by Count * float bytes
return(Size);
return(Size);
Text form is Data1-Data2-Data3-Data4, the first 3 are stored as little endian integers, the last as a string (big endian).
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}",
return(string);
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; }
return(status);
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,
if(hold){
goto bye;
goto bye;
bye:
return(hold);
else if(OID == U_PMF_IE_BRIGHTNESSCONTRAST_OID ){ lf = U_LOAD_GUID("D3A1DBE18EC44C179F4CEA97AD1C343D"); }
else if(OID == U_PMF_IE_COLORLOOKUPTABLE_OID ){ lf = U_LOAD_GUID("A7CE72A90F7F40D7B3CCD0C02D5C3212"); }
else if(OID == U_PMF_IE_HUESATURATIONLIGHTNESS_OID){ lf = U_LOAD_GUID("8B2DD6C3EB074D87A5F07108E26A9C5F"); }
else if(OID == U_PMF_IE_REDEYECORRECTION_OID ){ lf = U_LOAD_GUID("74D29D0569A4426695493CC52836B632"); }
return(lf);
if(*Src){
if(!Dst){ return(0); }
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);
if(!contents){ return(0); }
U_PMF_SERIAL_get(&contents, Flags, 2, 1, U_LE); /* EMF+ manual documents it as BE, but this code implements it as LE*/
if(Header){
U_PMF_SERIAL_get(contents, &(Header->Flags), 2, 1, U_LE); /* EMF+ manual documents it as BE, but this code implements it as LE*/
if(!contents){ return(0); }
return(Size);
return(length);
return(length);
return(po);
return(po);
return(po);
return(po);
U_PSEUDO_OBJ *U_PMF_IMAGEATTRIBUTES_set(uint32_t Version, uint32_t WrapMode, uint32_t ClampColor, uint32_t ObjectClamp){
return(po);
\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)
U_PSEUDO_OBJ *U_PMF_PATH_set(uint32_t Version, const U_PSEUDO_OBJ *Points, const U_PSEUDO_OBJ *Types){
if(Points){
else { return(NULL); }
else { return(NULL); }
if(Types){
else { return(NULL); }
else { return(NULL); }
{NULL, pad, (pad ? 1 : 0), (pad ? U_XE : U_XX)}, /* if no padding is needed the Units will be zero and nothing will happen */
return(po);
{NULL, pad, (pad ? 1 : 0), (pad ? U_XE : U_XX)}, /* if no padding is needed the Units will be zero and nothing will happen */
return(po);
{NULL, pad, (pad ? 1 : 0), (pad ? U_XE : U_XX)}, /* if no padding is needed the Units will be zero and nothing will happen */
return(po);
U_PSEUDO_OBJ *U_PMF_PEN_set(uint32_t Version, const U_PSEUDO_OBJ *PenData, const U_PSEUDO_OBJ *Brush){
return(po);
\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)
return(po);
if(Sfd){
if((!Sfs->TabStopCount && !Sfs->RangeCount) || (Sfd->Type != U_PMF_STRINGFORMATDATA_OID))return(NULL);
return(po);
return(po);
return(po);
\return Pointer to PseudoObject containing the count, followed by the array of colors, NULL on error
return(po);
return(argb);
uint32_t Pad = UP4(Bm->Used) - Bm->Used; /* undocumented padding, must be present for at least PNG */
return(po);
\param Bm An array of bytes, meaning depends on fields in U_PMF_BITMAP object and the PixelFormat enumeration.
return(po);
\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
U_PSEUDO_OBJ *U_PMF_BLENDCOLORS_set(uint32_t Elements, const U_FLOAT *Positions, const U_PSEUDO_OBJ *Colors){
return(po);
U_PSEUDO_OBJ *U_PMF_BLENDCOLORS_linear_set(uint32_t Elements, U_PMF_ARGB StartColor, U_PMF_ARGB EndColor){
if(!Colors){
return(NULL);
P = StartPos;
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;
B += dB;
G += dG;
R += dR;
A += dA;
return(po);
\param Positions positions along gradient line. The first position MUST be 0.0 and the last MUST be 1.0.
U_PSEUDO_OBJ *U_PMF_BLENDFACTORS_set(uint32_t Elements, const U_FLOAT *Positions, const U_FLOAT *Factors){
return(po);
U_PSEUDO_OBJ *U_PMF_BLENDFACTORS_linear_set(uint32_t Elements, U_FLOAT StartFactor, U_FLOAT EndFactor){
if(!Factors){
return(NULL);
P = StartPos;
F = StartFactor;
for(i=0;i<Elements;i++){ /* hopefully the rounding errors are not a problem, used doubles to minimize that */
return(po);
return(po);
return(po);
return(po);
return(po);
return(po);
return(po);
return(po);
return(po);
U_PSEUDO_OBJ *U_PMF_CUSTOMLINECAPOPTIONALDATA_set(const U_PSEUDO_OBJ *Fill, const U_PSEUDO_OBJ *Line){
return(po);
return(po);
return(po);
\brief Utility function to create and set a U_PMF_DASHEDLINEDATA PseudoObject from one of a predefined set of patterns
uint8_t *p;
return(po);
\brief Utility function to create and set a U_PMF_DASHEDLINEDATA PseudoObject from the bits that are set in a uint32_t
\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.
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 */
Lengths[0]=0;
if(j & BitPat){
if(!lastType){
if(lastType){
if(newType){
Lengths[i]=0;
Elements++;
newType = 0;
return(po);
return(po);
return(po);
return(po);
return(tmp);
U_PSEUDO_OBJ *U_PMF_HATCHBRUSHDATA_set(uint32_t Style, const U_PSEUDO_OBJ *Fg, const U_PSEUDO_OBJ *Bg){
return(po);
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);
return(po);
utmp32 = ((SubLId & U_FF_MASK_SUBLID) << U_FF_SHFT_SUBLID) | ((PriLId & U_FF_MASK_PRILID) << U_FF_SHFT_PRILID);
return(utmp32);
return(po);
\param Lgbod U_PSEUDO_OBJ containing a U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA object (variable part of a U_PMF_LINEARGRADIENTBRUSHDATA object)
U_PSEUDO_OBJ *U_PMF_LINEARGRADIENTBRUSHDATA_set(const U_PMF_LINEARGRADIENTBRUSHDATA *Lgbd, const U_PSEUDO_OBJ *Lgbod){
{(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 */
return(po);
\param Flags Bits are set that indicate which of the following were included. The caller must clear before passing it in.
\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.)
The rectangular gradients repeat in a tiled pattern. Tm can rotate and offset the gradient within each tile.
return(po);
return(po);
return(NULL);
return(po);
\param Boundary U_PSEUDO_OBJ containing a U_PMF_BOUNDARYPATHDATA or U_PMF_BOUNDARYPOINTDATA object. (Boundary Data)
U_PSEUDO_OBJ *U_PMF_PATHGRADIENTBRUSHDATA_set(uint32_t Flags, int32_t WrapMode, U_PMF_ARGB CenterColor,
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);
return(po);
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);
return(po);
\param Ppt Array of unsigned bytes, lower 4 bits hold the PathPointType flag upper 4 bits hold the PathPointType enumeration.
return(po);
\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.
return(po);
\return Pointer to PseudoObject containing first the number of elements, then an array of U_PMF_PATHPOINTTYPERLE, NULL on error
U_PSEUDO_OBJ *U_PMF_PATHPOINTTYPERLE_set(uint32_t Elements, const uint8_t *Bz, const uint8_t *RL, const uint8_t *Ppte){
U_PSEUDO_OBJ *po = U_PO_create(NULL, 4 + 2*Elements, 0, U_PMF_PATHPOINTTYPERLE_OID | U_PMF_ARRAY_OID);
if(po){
end:
return(holdpo);
\param Pod U_PSEUDO_OBJ containing first the PenData flags then a U_PMF_PENOPTIONALDATA object (the second part
return(po);
\return Pointer to PseudoObject, NULL on error. Returned PO contains first the Flags, then the PO proper.
\param CmpndLineData U_PSEUDO_OBJ containing a U_PMF_COMPOUNDLINEDATA object Compount Line (parallel lines drawn instead of one)
U_PSEUDO_OBJ *U_PMF_PENOPTIONALDATA_set(uint32_t Flags, U_PSEUDO_OBJ *Tm, int32_t StartCap, int32_t EndCap, uint32_t Join,
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);
{((Flags & U_PD_StartCap ) ? (char *)&StartCap : NULL), ((Flags & U_PD_StartCap ) ? 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_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},
return(po);
return(po);
return(po);
\param Coords Array of X,Y pairs. These are absolute coordinates, they are converted to Relative here.
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 */
/* Because the values stored were some unpredictable combination of 1 and 2 bytes, the last byte may not end
if(residual){
end:
return(holdpo);
return(po);
return(po);
\return Pointer to PseudoObject, NULL on error. PseudoObject contains Elements followed by the array of U_PMF_RECT objects.
return(po);
return(po);
return(po);
\return Pointer to PseudoObject, NULL on error. PseudoObject contains Elements followed by the array of U_PMF_RECTF objects.
return(po);
\param Rnd (optional) U_PSEUDO_OBJ containing a U_PMF_REGIONNODEPATH, U_PMF_RECTF, or U_PMF_REGIONNODECHILDNODES object (Region Node Data)
if(Rnd){
if((pType == 0) &&
){ return(NULL); }
return(po);
return(po);
return(po);
return(po);
U_PSEUDO_OBJ *U_PMF_STRINGFORMATDATA_set(uint32_t TabStopCount, U_FLOAT *TabStops, const U_PSEUDO_OBJ *Ranges){
return(po);
U_PSEUDO_OBJ *U_PMF_TEXTUREBRUSHDATA_set(uint32_t Flags, uint32_t WrapMode, const U_PSEUDO_OBJ *Tbod){
return(po);
U_PSEUDO_OBJ *U_PMF_TEXTUREBRUSHOPTIONALDATA_set(const U_PSEUDO_OBJ *Tm, const U_PSEUDO_OBJ *Image){
return(po);
return(po);
return(po);
return(po);
\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
return(po);
return(po);
U_PSEUDO_OBJ *U_PMF_IE_COLORLOOKUPTABLE_set(const uint8_t *BLUT, const uint8_t *GLUT, const uint8_t *RLUT, const uint8_t *ALUT){
return(po);
\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]
return(po);
U_PSEUDO_OBJ *U_PMF_IE_HUESATURATIONLIGHTNESS_set(int32_t Hue, int32_t Saturation, int32_t Lightness){
return(po);
return(po);
return(po);
return(po);
return(po);
The type is something like U_PMR_OFFSETCLIP (the record type, NOT the U_PMR_OFFSETCLIP_OID PseudoObject Type!).
uint32_t Size = 12 + UP4(DataSize); /* The header itself is always 12, PMR records must be a multiple of 4 */
{&Flags, 2, 1, U_LE}, /* Microsoft EMF+ manual is BE, but this field in this implementation is LE */
return(po);
EMF+ manual mentioned in 2.1.1.1, not otherwise documented, Microsoft name: EmfPlusStrokeFillPath Record, Index 0x37
return(po);
return(po);
return(po);
uint16_t utmp16 = ((PathID & U_FF_MASK_OID8) << U_FF_SHFT_OID8) | ((CMenum & U_FF_MASK_CM4) << U_FF_SHFT_CM4);
return(po);
\param Rect U_PSEUDO_OBJ containing an U_PMF_RECTF object or an array of U_PMF_RECTF objects (the first is used)
if(Rect){
return(po);
uint16_t utmp16 = ((PathID & U_FF_MASK_OID8) << U_FF_SHFT_OID8) | ((CMenum & U_FF_MASK_CM4) << U_FF_SHFT_CM4);
return(po);
return(po);
return(po);
return(po);
return(po);
return(po);
U_PSEUDO_OBJ *U_PMR_DRAWARC_set(uint32_t PenID, U_FLOAT Start, U_FLOAT Sweep, const U_PSEUDO_OBJ *Rect){
else { return(NULL); }
return(po);
\param Points U_PSEUDO_OBJ containing first Elements, then a U_PMF_POINT, U_PMF_POINTR or U_PMF_POINTF object
if(Points){
else { return(NULL); }
else { return(NULL); }
uint16_t utmp16 = (ctype ? U_PPF_C : 0) | (RelAbs ? U_PPF_P : 0) |(PenID & U_FF_MASK_OID8) << U_FF_SHFT_OID8;
return(po);
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){
if(Points){
else { return(NULL); }
else { return(NULL); }
uint16_t utmp16 = (ctype ? U_PPF_C : 0) | (RelAbs ? U_PPF_P : 0) |(PenID & U_FF_MASK_OID8) << U_FF_SHFT_OID8;
return(po);
\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
Curve is a cardinal spline, using doubled terminator points to generate curves for the terminal segments.
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){
else { return(NULL); }
uint32_t Elements = (Points->Used - 4)/(ctype ? 4 : 8); /* This way do not need to worry about byte order */
return(po);
\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 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 Tm U_PSEUDO_OBJ containing a U_PMF_TRANSFORMMATRIX object. Apply to Glyphs & Positions. Present if HasMatrix is 1
if(BrushID){
else { return(NULL); }
else { return(NULL); }
if(HasMatrix){
return(po);
else { return(NULL); }
return(po);
else { return(NULL); }
return(po);
\param etype Set: effect from previous U_PMR_SERIALIZABLEOBJECT record will be applied; Clear: no effect applied
\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.
WARNING! Windows XP Preview does not show filter effects, whether or not U_PPF_E is set. They are visible if the EMF+
if(Points){
else { return(NULL); }
else { return(NULL); }
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;
return(po);
\param Points U_PSEUDO_OBJ containing an array of 3 U_PMF_POINT, U_PMF_POINTR, or U_PMF_POINTF objects
if(Points){
else { return(NULL); }
else { return(NULL); }
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;
return(po);
return(po);
else { return(NULL); }
return(po);
\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
uint32_t Elements=1; /* only used when a single rect is passed in, not an array, not even an array with one member*/
if(Rects){
else { return(NULL); }
else { return(NULL); }
{(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 */
return(po);
\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)
if(BrushID){
else { return(NULL); }
else { return(NULL); }
return(po);
\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_FILLCLOSEDCURVE_set(int ftype, U_FLOAT Tension, const U_PSEUDO_OBJ *BrushID, const U_PSEUDO_OBJ *Points){
if(BrushID){
else { return(NULL); }
else { return(NULL); }
if(Points){
else { return(NULL); }
else { return(NULL); }
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);
return(po);
\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)
if(BrushID){
else { return(NULL); }
else { return(NULL); }
if(Rect){
else { return(NULL); }
else { return(NULL); }
return(po);
\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)
if(BrushID){
else { return(NULL); }
else { return(NULL); }
return(po);
\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_FILLPIE_set(U_FLOAT Start, U_FLOAT Sweep, const U_PSEUDO_OBJ *BrushID, const U_PSEUDO_OBJ *Rect){
if(BrushID){
else { return(NULL); }
else { return(NULL); }
else { return(NULL); }
return(po);
\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
if(BrushID){
else { return(NULL); }
else { return(NULL); }
if(Points){
else { return(NULL); }
else { return(NULL); }
return(po);
\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
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){
else { return(NULL); }
else { return(NULL); }
if(Rects){
else { return(NULL); }
else { return(NULL); }
int Size = BrushID->Used + Rects->Used + (just1 ? 4 : 0); /* Elements in Rects for array, not for single */
{(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 */
return(po);
\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)
if(BrushID){
else { return(NULL); }
else { return(NULL); }
return(po);
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);
\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.
U_PMR_OBJECT records can only hold a maximum of 65020 bytes of data. If the object is larger than that
happens each record has cbData following ph, and the ntype flag is set. If all of the data is less than 65020
U_PSEUDO_OBJ *U_PMR_OBJECT_set(uint32_t ObjID, int otype, int ntype, uint32_t TSize, size_t cbData, const char *Data){
if(po){
while(cbData){
if(!pot)break;
if(!newpo)break;
{NULL, (Pad ? Pad : 0), (Pad ? 1 : 0), (Pad ? U_XE : U_XX)}, /* Either 1-3 pad bytes or a terminator */
return(po);
\param Siepb U_PSEUDO_OBJ containing a "Serialized image effects parameter block". One of the ImageEffects objects.
record that is encountered. The image effect is "consumed" by that EmfPlusDrawImagePoints record, resetting
WARNING! Windows XP Preview does not show filter effects, whether or not U_PPF_E is set. They are visible if the EMF+
return(po);
return(po);
return(po);
return(po);
return(po);
return(po);
return(po);
return(po);
return(po);
\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
U_PSEUDO_OBJ *U_PMR_BEGINCONTAINER_set(int UTenum, U_PSEUDO_OBJ *DstRect, U_PSEUDO_OBJ *SrcRect, uint32_t StackID){
return(po);
return(po);
return(po);
\param StackID EMF+ Graphics State Stack to restore from. Must have been put on the GSS with a U_PMR_SAVE.
return(po);
\param StackID EMF+ Graphics State Stack to restore from. Must have been put on the GSS with a U_PMR_SAVE.
return(po);
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); }
return(po);
U_PSEUDO_OBJ *U_PMR_SETTSGRAPHICS_set(int vgatype, U_PMF_SETTSGRAPHICS *Tsg, U_PSEUDO_OBJ *Palette){
return(po);
return(po);
return(po);
return(po);
return(po);
return(po);
return(po);
return(po);
These functions all take a blimit value so that they can check if the data description in the fields
int U_PMF_CORE1_get(const char *contents, void *v1, void *v2, void *v3, void *v4, void *v5, void *v6, const char **vR){
int U_PMF_BRUSH_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **Data, const char *blimit){
int U_PMF_CUSTOMLINECAP_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **Data, const char *blimit){
if(!contents || !Version || !EmSize || !SizeUnit || !FSFlags || !Length || !Data || !blimit){ return(0); }
int U_PMF_IMAGE_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **Data, const char *blimit){
int U_PMF_IMAGEATTRIBUTES_get(const char *contents, uint32_t *Version, uint32_t *WrapMode, uint32_t *ClampColor,
Caller must check Types for possible memory access violations if type can be U_PMF_PATHPOINTTYPERLE.
int U_PMF_PEN_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **PenData, const char **Brush, const char *blimit){
\param Count Number of CHILD nodes. This is one less than the total number of U_PMF_REGIONNODE objects in Nodes.
int U_PMF_REGION_get(const char *contents, uint32_t *Version, uint32_t *Count, const char **Nodes, const char *blimit){
int U_PMF_STRINGFORMAT_get(const char *contents, U_PMF_STRINGFORMAT *Sfs, const char **Data, const char *blimit){
int U_PMF_ARGB_get(const char *contents, uint8_t *Blue, uint8_t *Green, uint8_t *Red, uint8_t *Alpha, const char *blimit){
int U_PMF_BITMAP_get(const char *contents, U_PMF_BITMAP *Bs, const char **Data, const char *blimit){
\param Data An array of bytes, meaning depends on fields in U_PMF_BITMAP object and the PixelFormat enumeration.
int U_PMF_BITMAPDATA_get(const char *contents, U_PMF_PALETTE *Ps, const char **Colors, const char **Data, const char *blimit){
\param Colors Caller must NOT free memory, Pointer to memory holding colors at positions on gradient line.
int U_PMF_BLENDCOLORS_get(const char *contents, uint32_t *Elements, U_FLOAT **Positions, const char **Colors, const char *blimit){
\param Factors Caller must free. Pointer to memory holding blending factors, 0.0->1.0 values, inclusive along gradient line.
int U_PMF_BLENDFACTORS_get(const char *contents, uint32_t *Elements, U_FLOAT **Positions, U_FLOAT **Factors, const char *blimit){
if(!U_PMF_SERIAL_array_copy_get(&contents, (void **)Positions, 4, *Elements, U_LE, 1)){ return(0); }
int U_PMF_BOUNDARYPATHDATA_get(const char *contents, int32_t *Size, const char **Data, const char *blimit){
\param Points Caller must free. Pointer to memory holding points along gradient line. Boundary of the brush.
int U_PMF_BOUNDARYPOINTDATA_get(const char *contents, int32_t *Elements, U_PMF_POINTF **Points, const char *blimit){
if(!U_PMF_SERIAL_array_copy_get(&contents, (void **)Points, 4, *Elements * 2, U_LE, 1)){ return(0); }
int U_PMF_CHARACTERRANGE_get(const char *contents, int32_t *First, int32_t *Length, const char *blimit){
\param Widths Caller must free. Pointer to memory holding Line or gap widths (0.0 <-> 1.0, fraction of total line width ).
int U_PMF_COMPOUNDLINEDATA_get(const char *contents, int32_t *Elements, U_FLOAT **Widths, const char *blimit){
if(!*Widths){ return(0); }
This function does not do anything useful, but it is included so that all objects have a corresponding _get().
int U_PMF_CUSTOMENDCAPDATA_get(const char *contents, int32_t *Size, const char **Data, const char *blimit){
int U_PMF_CUSTOMLINECAPARROWDATA_get(const char *contents, U_PMF_CUSTOMLINECAPARROWDATA *Ccad, const char *blimit){
int U_PMF_CUSTOMLINECAPDATA_get(const char *contents, U_PMF_CUSTOMLINECAPDATA *Clcd, const char **Data, const char *blimit){
\return on success 3,5, or 7 (for varying combinations of data present) or 1 (no data is present), 0 on error
int U_PMF_CUSTOMLINECAPOPTIONALDATA_get(const char *contents, uint32_t Flags, const char **FillData, const char **LineData, const char *blimit){
if(!FillData){ return(0); }
if(!LineData){ return(0); }
return(status);
int U_PMF_CUSTOMSTARTCAPDATA_get(const char *contents, int32_t *Size, const char **Data, const char *blimit){
int U_PMF_DASHEDLINEDATA_get(const char *contents, int32_t *Elements, U_FLOAT **Lengths, const char *blimit){
if(!*Lengths){ return(0); }
int U_PMF_FILLPATHOBJ_get(const char *contents, int32_t *Size, const char **Data, const char *blimit){
int U_PMF_FOCUSSCALEDATA_get(const char *contents, uint32_t *Count, U_FLOAT *ScaleX, U_FLOAT *ScaleY, const char *blimit){
int U_PMF_GRAPHICSVERSION_get(const char *contents, int *Signature, int *GrfVersion, const char *blimit){
int U_PMF_HATCHBRUSHDATA_get(const char *contents, uint32_t *Style, U_PMF_ARGB *Foreground, U_PMF_ARGB *Background, const char *blimit){
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_LINEARGRADIENTBRUSHDATA_get(const char *contents, U_PMF_LINEARGRADIENTBRUSHDATA *Lgbd, const char **Data, const char *blimit){
U_PMF_SERIAL_get(&contents, &(Lgbd->StartColor), 4, 4, U_XE); /* StartColor, EndColor, Reserved1 & 2 */
\param BfV U_PMF_BLENDFACTORS (V) object or NULL (WARNING, GDI+ defines this field but does not render it. DO NOT USE.)
int U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA_get(const char *contents, uint32_t Flags, U_PMF_TRANSFORMMATRIX *Tm,
U_PMF_PTRSAV_SHIFT(BfH, &contents, 4 + (Elements * 2 * sizeof(U_FLOAT))); /* 4 byte count + 2 * 4bytes * Elements */
int U_PMF_METAFILE_get(const char *contents, uint32_t *Type, uint32_t *Size, const char **Data, const char *blimit){
int U_PMF_PALETTE_get(const char *contents, uint32_t *Flags, uint32_t *Elements, const char **Colors, const char *blimit){
\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
int U_PMF_PATHGRADIENTBRUSHDATA_get(const char *contents, U_PMF_PATHGRADIENTBRUSHDATA *Pgbd, const char **Gradient,
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_Transform |U_BD_PresetColors | U_BD_BlendFactorsH| U_BD_FocusScales)){ // optional data present
int U_PMF_PATHGRADIENTBRUSHOPTIONALDATA_get(const char *contents, uint32_t Flags, U_PMF_TRANSFORMMATRIX *Matrix,
int U_PMF_PATHPOINTTYPERLE_get(const char *contents, int *Bezier, int *RL, int *Ppt, const char *blimit){
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 >= blimit)return(0); // variable data will extend farther, but this much at least must be true
const char *contents,
const char **DLData,
const char **CmpndLineData,
const char **CSCapData,
const char **CECapData,
const char *blimit){
if(!contents ||
\param contents Record from which to extract data. On return position is offset by sizeof(U_PMF_POINT).
\param contents Record from which to extract data. On return position is offset by sizeof(U_PMF_POINTF).
return(size);
\brief Get data from a variable POINTS object, which may be U_PMF_POINTS, U_PMF_POINTF, or U_PMF_POINTR.
int U_PMF_VARPOINTS_get(const char *contents, uint16_t Flags, int Elements, U_PMF_POINTF **Points, const char *blimit){
return(status);
int U_PMF_RECT_get(const char **contents, int16_t *X, int16_t *Y, int16_t *Width, int16_t *Height, const char *blimit){
int U_PMF_RECTF_get(const char **contents, U_FLOAT *X, U_FLOAT *Y, U_FLOAT *Width, U_FLOAT *Height, const char *blimit){
int U_PMF_VARRECTS_get(const char **contents, uint16_t Flags, int Elements, U_PMF_RECTF **Rects, const char *blimit){
if(!rts){
int U_PMF_REGIONNODE_get(const char *contents, uint32_t *Type, const char **Data, const char *blimit){
/* Important! This only checks the constant part, the caller must check that returned data doesn't exceed blimit */
int U_PMF_REGIONNODEPATH_get(const char *contents, int32_t *Size, const char **Data, const char *blimit){
/* Important! This only checks the constant part, the caller must check that returned data doesn't exceed blimit */
int U_PMF_TEXTUREBRUSHDATA_get(const char *contents, uint32_t *Flags, int32_t *WrapMode, const char **Data, const char *blimit){
/* Important! This only checks the constant part, the caller must check that returned data doesn't exceed blimit */
int U_PMF_TEXTUREBRUSHOPTIONALDATA_get(const char *contents, int HasImage, U_PMF_TRANSFORMMATRIX *Matrix,
if(Matrix){
if(HasImage){
int U_PMF_TRANSFORMMATRIX_get(const char *contents, U_PMF_TRANSFORMMATRIX *Matrix, const char *blimit){
int U_PMF_IE_BLUR_get(const char *contents, U_FLOAT *Radius, uint32_t *ExpandEdge, const char *blimit){
int U_PMF_IE_BRIGHTNESSCONTRAST_get(const char *contents, int32_t *Brightness, int32_t *Contrast, const char *blimit){
\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
int U_PMF_IE_COLORBALANCE_get(const char *contents, int32_t *CyanRed, int32_t *MagentaGreen, int32_t *YellowBlue, const char *blimit){
int U_PMF_IE_COLORCURVE_get(const char *contents, uint32_t *Adjust, uint32_t *Channel, int32_t *Intensity, const char *blimit){
const uint8_t **BLUT, const uint8_t **GLUT, const uint8_t **RLUT, const uint8_t **ALUT, const char *blimit){
\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]
int U_PMF_IE_COLORMATRIX_get(const char *contents, U_PMF_IE_COLORMATRIX *Matrix, const char *blimit){
/* Important! This only checks the constant part, the caller must check that returned data doesn't exceed blimit */
int U_PMF_IE_HUESATURATIONLIGHTNESS_get(const char *contents, int32_t *Hue, int32_t *Saturation, int32_t *Lightness, const char *blimit){
int U_PMF_IE_LEVELS_get(const char *contents, int32_t *Highlight, int32_t *Midtone, int32_t *Shadow, const char *blimit){
int U_PMF_IE_REDEYECORRECTION_get(const char *contents, int32_t *Elements, U_RECTL **Rects, const char *blimit){
if(!*Rects){ return(0); }
int U_PMF_IE_SHARPEN_get(const char *contents, U_FLOAT *Radius, int32_t *Sharpen, const char *blimit){
if(!contents){ return(0); }
if(!contents){ return(0); }
if(!contents){ return(0); }
int *CMenum,
const char **Data){
if(!contents){ return(0); }
if(!contents){ return(0); }
U_PMF_GRAPHICSVERSION *Version, int *IsDual, int *IsVideo, uint32_t *LogicalDpiX, uint32_t *LogicalDpiY){
\param RelAbs Set: Coordinates are relative; Clear: Coordinates are absolute and their type is set by ctype
\param Points Caller must free. Array of U_POINT_F = Sequence of points to connect. Coordinate type set by ctype and RelAbs.
return(status);
\param RelAbs Set: Coordinates are relative; Clear: Coordinates are absolute and their type is set by ctype
\param Points Caller must free. Array of U_POINT_F = Sequence of points to connect. Coordinate type set by ctype and RelAbs.
\param Points Caller must free. Array of U_POINT_F = Sequence of points to connect. Coordinate type set by ctype and RelAbs.
if(!contents || !PenID || !ctype || !Tension || !Offset || !NSegs || !Elements || !Points){ return(0); }
\param btype Set: BrushID is an U_PFM_ARGB; Clear: index of U_PMF_BRUSH object in EMF+ object table.
\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
U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */
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); }
\param etype Set: effect from previous U_PMR_SERIALIZABLEOBJECT record will be applied; Clear: no effect applied
\param Points Caller must free. 3 points of a parallelogram.. Coordinate type set by ctype and RelAbs.
if(!contents || !ImgID || !ctype || !etype || !RelAbs || !ImgAttrID || !SrcUnit || !Elements || !Points){ return(0); }
\param RelAbs Set: Coordinates are relative; Clear: Coordinates are absolute and their type is set by ctype
\param Points Caller must free. Array of U_POINT_F = Sequence of points to connect. Coordinate type set by ctype and RelAbs.
\param btype Set: BrushID is an U_PFM_ARGB; Clear: index of U_PMF_BRUSH object in EMF+ object table.
U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */
\param btype Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table.
\param RelAbs Set: Coordinates are relative; Clear: Coordinates are absolute and their type is set by ctype
\param Points Caller must free. Array of U_POINT_F = Sequence of points to connect. Coordinate type set by ctype and RelAbs.
if(!contents || !btype || !ctype || !ftype || !RelAbs || !BrushID || !Tension || !Elements || !Points){ return(0); }
U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */
\param btype Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table.
\param Rect Caller must free. Bounding box for elliptical pie segment being drawn. Coordinate type set by ctype.
U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */
\param btype Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table.
U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */
\param btype Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table.
U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */
\param btype Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table.
\param RelAbs Set: U_PMF_PathPointTypeRLE and/or U_PMF_PathPointType objects; Clear: only U_PMF_PathPointType
\param Points Sequence of points to connect with line segments. Coordinate type set by ctype and RelAbs.
U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */
\param btype Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table.
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.
U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */
\param btype Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table.
U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */
\param TSize If ntype is set, holds the total number of data bytes split across multiple records. If ntype is clear, has no meaning.
const char **Data){
else { *TSize = 0; }
const char **Data){
int *CMenum){
int *CQenum){
int *IMenum){
int *POMenum){
if(!contents || !X || !Y){ return(0); }
int *TGC){
int *TRHenum){
int *UTenum,
int U_PMR_BEGINCONTAINERNOPARAMS_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *StackID){
\param StackID State (level) to restore from the EMF+ Graphics Stack. Must have been put on the GS with a U_PMR_SAVE.
uint8_t *AntiAliasMode, uint8_t *TextRenderHint, uint8_t *CompositingMode, uint8_t *CompositingQuality,
const char **Data){
int *xmtype,
int *xmtype,
int *xmtype,
int *PUenum,
int *xmtype,
EMF+ manual mentioned in 2.1.1.1, not otherwise documented, Microsoft name: EmfPlusStrokeFillPath Record, Index 0x37
EMF+ manual mentioned in 2.1.1.1, reserved, not otherwise documented, Microsoft name: EmfPlusMultiFormatStart Record, Index 0x05
EMF+ manual mentioned in 2.1.1.1, reserved, not otherwise documented, Microsoft name: EmfPlusMultiFormatSection Record, Index 0x06
EMF+ manual mentioned in 2.1.1.1, reserved, not otherwise documented, Microsoft name: EmfPlusMultiFormatEnd Record, Index 0x06
#ifdef __cplusplus