summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/libuemf/uemf.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/3rdparty/libuemf/uemf.c5606
1 files changed, 5606 insertions, 0 deletions
diff --git a/src/3rdparty/libuemf/uemf.c b/src/3rdparty/libuemf/uemf.c
new file mode 100644
index 0000000..fa7689b
--- /dev/null
+++ b/src/3rdparty/libuemf/uemf.c
@@ -0,0 +1,5606 @@
+/**
+ @file uemf.c
+
+ @brief Functions for manipulating EMF files and structures.
+
+ [U_EMR]_set all take data and return a pointer to memory holding the constructed record.
+ The size of that record is also returned in recsize.
+ It is also in the second int32 in the record, but may have been byte swapped and so not usable.
+ If something goes wrong a NULL pointer is returned and recsize is set to 0.
+
+ Compile with "U_VALGRIND" defined defined to enable code which lets valgrind check each record for
+ uninitialized data.
+
+ Compile with "SOL8" defined for Solaris 8 or 9 (Sparc).
+*/
+
+/*
+File: uemf.c
+Version: 0.0.31
+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 U_ROUND()
+#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 "uemf.h"
+
+//! \cond
+/* one prototype from uemf_endian. Put it here because end user should never need to see it, so
+not in uemf.h or uemf_endian.h */
+void U_swap2(void *ul, unsigned int count);
+//! \endcond
+
+/**
+ \brief Look up the name of the EMR record by type. Returns U_EMR_INVALID if out of range.
+
+ \return name of the EMR record, "U_EMR_INVALID" if out of range.
+ \param idx EMR record type.
+
+*/
+char *U_emr_names(unsigned int idx){
+ if(idx<U_EMR_MIN || idx > U_EMR_MAX){ idx = 0; }
+ static char *U_EMR_NAMES[U_EMR_MAX+1]={
+ "U_EMR_INVALID",
+ "U_EMR_HEADER",
+ "U_EMR_POLYBEZIER",
+ "U_EMR_POLYGON",
+ "U_EMR_POLYLINE",
+ "U_EMR_POLYBEZIERTO",
+ "U_EMR_POLYLINETO",
+ "U_EMR_POLYPOLYLINE",
+ "U_EMR_POLYPOLYGON",
+ "U_EMR_SETWINDOWEXTEX",
+ "U_EMR_SETWINDOWORGEX",
+ "U_EMR_SETVIEWPORTEXTEX",
+ "U_EMR_SETVIEWPORTORGEX",
+ "U_EMR_SETBRUSHORGEX",
+ "U_EMR_EOF",
+ "U_EMR_SETPIXELV",
+ "U_EMR_SETMAPPERFLAGS",
+ "U_EMR_SETMAPMODE",
+ "U_EMR_SETBKMODE",
+ "U_EMR_SETPOLYFILLMODE",
+ "U_EMR_SETROP2",
+ "U_EMR_SETSTRETCHBLTMODE",
+ "U_EMR_SETTEXTALIGN",
+ "U_EMR_SETCOLORADJUSTMENT",
+ "U_EMR_SETTEXTCOLOR",
+ "U_EMR_SETBKCOLOR",
+ "U_EMR_OFFSETCLIPRGN",
+ "U_EMR_MOVETOEX",
+ "U_EMR_SETMETARGN",
+ "U_EMR_EXCLUDECLIPRECT",
+ "U_EMR_INTERSECTCLIPRECT",
+ "U_EMR_SCALEVIEWPORTEXTEX",
+ "U_EMR_SCALEWINDOWEXTEX",
+ "U_EMR_SAVEDC",
+ "U_EMR_RESTOREDC",
+ "U_EMR_SETWORLDTRANSFORM",
+ "U_EMR_MODIFYWORLDTRANSFORM",
+ "U_EMR_SELECTOBJECT",
+ "U_EMR_CREATEPEN",
+ "U_EMR_CREATEBRUSHINDIRECT",
+ "U_EMR_DELETEOBJECT",
+ "U_EMR_ANGLEARC",
+ "U_EMR_ELLIPSE",
+ "U_EMR_RECTANGLE",
+ "U_EMR_ROUNDRECT",
+ "U_EMR_ARC",
+ "U_EMR_CHORD",
+ "U_EMR_PIE",
+ "U_EMR_SELECTPALETTE",
+ "U_EMR_CREATEPALETTE",
+ "U_EMR_SETPALETTEENTRIES",
+ "U_EMR_RESIZEPALETTE",
+ "U_EMR_REALIZEPALETTE",
+ "U_EMR_EXTFLOODFILL",
+ "U_EMR_LINETO",
+ "U_EMR_ARCTO",
+ "U_EMR_POLYDRAW",
+ "U_EMR_SETARCDIRECTION",
+ "U_EMR_SETMITERLIMIT",
+ "U_EMR_BEGINPATH",
+ "U_EMR_ENDPATH",
+ "U_EMR_CLOSEFIGURE",
+ "U_EMR_FILLPATH",
+ "U_EMR_STROKEANDFILLPATH",
+ "U_EMR_STROKEPATH",
+ "U_EMR_FLATTENPATH",
+ "U_EMR_WIDENPATH",
+ "U_EMR_SELECTCLIPPATH",
+ "U_EMR_ABORTPATH",
+ "U_EMR_UNDEF69",
+ "U_EMR_COMMENT",
+ "U_EMR_FILLRGN",
+ "U_EMR_FRAMERGN",
+ "U_EMR_INVERTRGN",
+ "U_EMR_PAINTRGN",
+ "U_EMR_EXTSELECTCLIPRGN",
+ "U_EMR_BITBLT",
+ "U_EMR_STRETCHBLT",
+ "U_EMR_MASKBLT",
+ "U_EMR_PLGBLT",
+ "U_EMR_SETDIBITSTODEVICE",
+ "U_EMR_STRETCHDIBITS",
+ "U_EMR_EXTCREATEFONTINDIRECTW",
+ "U_EMR_EXTTEXTOUTA",
+ "U_EMR_EXTTEXTOUTW",
+ "U_EMR_POLYBEZIER16",
+ "U_EMR_POLYGON16",
+ "U_EMR_POLYLINE16",
+ "U_EMR_POLYBEZIERTO16",
+ "U_EMR_POLYLINETO16",
+ "U_EMR_POLYPOLYLINE16",
+ "U_EMR_POLYPOLYGON16",
+ "U_EMR_POLYDRAW16",
+ "U_EMR_CREATEMONOBRUSH",
+ "U_EMR_CREATEDIBPATTERNBRUSHPT",
+ "U_EMR_EXTCREATEPEN",
+ "U_EMR_POLYTEXTOUTA",
+ "U_EMR_POLYTEXTOUTW",
+ "U_EMR_SETICMMODE",
+ "U_EMR_CREATECOLORSPACE",
+ "U_EMR_SETCOLORSPACE",
+ "U_EMR_DELETECOLORSPACE",
+ "U_EMR_GLSRECORD",
+ "U_EMR_GLSBOUNDEDRECORD",
+ "U_EMR_PIXELFORMAT",
+ "U_EMR_DRAWESCAPE",
+ "U_EMR_EXTESCAPE",
+ "U_EMR_UNDEF107",
+ "U_EMR_SMALLTEXTOUT",
+ "U_EMR_FORCEUFIMAPPING",
+ "U_EMR_NAMEDESCAPE",
+ "U_EMR_COLORCORRECTPALETTE",
+ "U_EMR_SETICMPROFILEA",
+ "U_EMR_SETICMPROFILEW",
+ "U_EMR_ALPHABLEND",
+ "U_EMR_SETLAYOUT",
+ "U_EMR_TRANSPARENTBLT",
+ "U_EMR_UNDEF117",
+ "U_EMR_GRADIENTFILL",
+ "U_EMR_SETLINKEDUFIS",
+ "U_EMR_SETTEXTJUSTIFICATION",
+ "U_EMR_COLORMATCHTOTARGETW",
+ "U_EMR_CREATECOLORSPACEW"
+ };
+ return(U_EMR_NAMES[idx]);
+}
+
+
+
+/* **********************************************************************************************
+These definitions are for code pieces that are used many times in the following implementation. These
+definitions are not needed in end user code, so they are here rather than in uemf.h.
+*********************************************************************************************** */
+
+//! @cond
+
+// this one may also be used A=Msk,B=MskBmi and F=cbMsk
+#define SET_CB_FROM_PXBMI(A,B,C,D,E,F) /* A=Px, B=Bmi, C=cbImage, D=cbImage4, E=cbBmi, F=cbPx */ \
+ if(A){\
+ if(!B)return(NULL); /* size is derived from U_BITMAPINFO, but NOT from its size field, go figure*/ \
+ C = F;\
+ D = UP4(C); /* pixel array might not be a multiples of 4 bytes*/ \
+ E = sizeof(U_BITMAPINFOHEADER) + 4 * get_real_color_count((const char *) &(B->bmiHeader)); /* bmiheader + colortable*/ \
+ }\
+ else { C = 0; D = 0; E=0; }
+
+// variable "off" must be declared in the function
+
+#define APPEND_PXBMISRC(A,B,C,D,E,F,G) /* A=record, B=U_EMR,C=cbBmi, D=Bmi, E=Px, F=cbImage, G=cbImage4 */ \
+ if(C){\
+ memcpy(A + off, D, C);\
+ ((B *) A)->offBmiSrc = off;\
+ ((B *) A)->cbBmiSrc = C;\
+ off += C;\
+ memcpy(A + off, E, F);\
+ ((B *) A)->offBitsSrc = off;\
+ ((B *) A)->cbBitsSrc = F;\
+ if(G - F){ \
+ off += F;\
+ memset(A + off, 0, G - F); \
+ }\
+ }\
+ else {\
+ ((B *) A)->offBmiSrc = 0;\
+ ((B *) A)->cbBmiSrc = 0;\
+ ((B *) A)->offBitsSrc = 0;\
+ ((B *) A)->cbBitsSrc = 0;\
+ }
+
+// variable "off" must be declared in the function
+
+#define APPEND_MSKBMISRC(A,B,C,D,E,F,G) /* A=record, B=U_EMR*,C=cbMskBmi, D=MskBmi, E=Msk, F=cbMskImage, G=cbMskImage4 */ \
+ if(C){\
+ memcpy(A + off, D, C);\
+ ((B *) A)->offBmiMask = off;\
+ ((B *) A)->cbBmiMask = C;\
+ off += C;\
+ memcpy(A + off, Msk, F);\
+ ((B *) A)->offBitsMask = off;\
+ ((B *) A)->cbBitsMask = F;\
+ if(G - F){ memset(A + off, 0, G - F); }\
+ }\
+ else {\
+ ((B *) A)->offBmiMask = 0;\
+ ((B *) A)->cbBmiMask = 0;\
+ ((B *) A)->offBitsMask = 0;\
+ ((B *) A)->cbBitsMask = 0;\
+ }
+
+//! @endcond
+
+/* **********************************************************************************************
+These functions are used for development and debugging and should be be includied in production code.
+*********************************************************************************************** */
+
+/**
+ \brief Debugging utility, used with valgrind to find uninitialized values. Not for use in production code.
+ \param buf memory area to examine !
+ \param size length in bytes of buf!
+*/
+int memprobe(
+ const void *buf,
+ size_t size
+ ){
+ int sum=0;
+ char *ptr=(char *)buf;
+ for(;size;size--,ptr++){ sum += *ptr; } // read all bytes, trigger valgrind warning if any uninitialized
+ return(sum);
+}
+
+/**
+ \brief Dump an EMFHANDLES structure. Not for use in production code.
+ \param string Text to output before dumping eht structure
+ \param handle Handle
+ \param eht EMFHANDLES structure to dump
+*/
+void dumpeht(
+ char *string,
+ unsigned int *handle,
+ EMFHANDLES *eht
+ ){
+ uint32_t i;
+ printf("%s\n",string);
+ printf("sptr: %d peak: %d top: %d\n",eht->sptr,eht->peak,eht->top);
+ if(handle){
+ printf("handle: %d \n",*handle);
+ }
+ for(i=0;i<=5;i++){
+ printf("table[%d]: %d\n",i,eht->table[i]);
+ }
+ for(i=1;i<=5;i++){
+ printf("stack[%d]: %d\n",i,eht->stack[i]);
+ }
+}
+
+/* **********************************************************************************************
+These functions are used for Image conversions and other
+utility operations. Character type conversions are in uemf_utf.c
+*********************************************************************************************** */
+
+/**
+ \brief Make up an approximate dx array to pass to emrtext_set(), based on character height and weight.
+
+ Take abs. value of character height, get width by multiplying by 0.6, and correct weight
+ approximately, with formula (measured on screen for one text line of Arial).
+ Caller is responsible for free() on the returned pointer.
+
+ \return pointer to dx array
+ \param height character height (absolute value will be used)
+ \param weight LF_Weight Enumeration (character weight)
+ \param members Number of entries to put into dx
+
+*/
+uint32_t *dx_set(
+ int32_t height,
+ uint32_t weight,
+ uint32_t members
+ ){
+ uint32_t i, width, *dx;
+ dx = (uint32_t *) malloc(members * sizeof(uint32_t));
+ if(dx){
+ if(U_FW_DONTCARE == weight)weight=U_FW_NORMAL;
+ width = (uint32_t) U_ROUND(((float) (height > 0 ? height : -height)) * 0.6 * (0.00024*(float) weight + 0.904));
+ for ( i = 0; i < members; i++ ){ dx[i] = width; }
+ }
+ return(dx);
+}
+
+/**
+ \brief Look up the properties (a bit map) of a type of EMR record.
+ Bits that may be set are defined in "Draw Properties" in uemf.h, they are U_DRAW_NOTEMPTY, etc..
+
+ \return bitmap of EMR record properties, or U_EMR_INVALID on error or release of all memory
+ \param type EMR record type. If U_EMR_INVALID release memory. (There is no U_EMR_INVALID EMR record type)
+
+*/
+uint32_t emr_properties(uint32_t type){
+ static uint32_t *table=NULL;
+ uint32_t result = U_EMR_INVALID; // initialized to indicate an error (on a lookup) or nothing (on a memory release)
+ if(type == U_EMR_INVALID){
+ if(table)free(table);
+ table=NULL;
+ }
+ else if(type>=1 && type<U_EMR_MAX){
+ if(!table){
+ table = (uint32_t *) malloc(sizeof(uint32_t)*(1 + U_EMR_MAX));
+ if(!table)return(result);
+ // 0x80 0x40 0x20 0x10 0x08 0x04 0x02 0x01
+ // Path properties (U_DRAW_*) TEXT ALTERS ONLYTO VISIBLE
+ // PATH FORCE CLOSED NOTEMPTY
+ table[ 0] = 0x00; // Does not map to any EMR record
+ table[ 1] = 0x80; // U_EMRHEADER 1 0 0 0 0 0 0 0
+ table[ 2] = 0x83; // U_EMRPOLYBEZIER 1 0 0 0 0 0 1 1
+ table[ 3] = 0x87; // U_EMRPOLYGON 1 0 0 0 0 1 1 1
+ table[ 4] = 0x83; // U_EMRPOLYLINE 1 0 0 0 0 0 1 1
+ table[ 5] = 0x8B; // U_EMRPOLYBEZIERTO 1 0 0 0 1 0 1 1
+ table[ 6] = 0x8B; // U_EMRPOLYLINETO 1 0 0 0 1 0 1 1
+ table[ 7] = 0x83; // U_EMRPOLYPOLYLINE 1 0 0 0 0 0 1 1
+ table[ 8] = 0x87; // U_EMRPOLYPOLYGON 1 0 0 0 0 1 1 1
+ table[ 9] = 0xA0; // U_EMRSETWINDOWEXTEX 1 0 1 0 0 0 0 0
+ table[ 10] = 0xA0; // U_EMRSETWINDOWORGEX 1 0 1 0 0 0 0 0
+ table[ 11] = 0xA0; // U_EMRSETVIEWPORTEXTEX 1 0 1 0 0 0 0 0
+ table[ 12] = 0xA0; // U_EMRSETVIEWPORTORGEX 1 0 1 0 0 0 0 0
+ table[ 13] = 0xA0; // U_EMRSETBRUSHORGEX 1 0 1 0 0 0 0 0
+ table[ 14] = 0x82; // U_EMREOF 1 0 1 0 0 0 0 0 Force out any pending draw
+ table[ 15] = 0x82; // U_EMRSETPIXELV 1 0 0 0 0 0 1 0
+ table[ 16] = 0xA0; // U_EMRSETMAPPERFLAGS 1 0 1 0 0 0 0 0
+ table[ 17] = 0xA0; // U_EMRSETMAPMODE 1 0 1 0 0 0 0 0
+ table[ 18] = 0x20; // U_EMRSETBKMODE 0 0 1 0 0 0 0 0
+ table[ 19] = 0xA0; // U_EMRSETPOLYFILLMODE 1 0 1 0 0 0 0 0
+ table[ 20] = 0xA0; // U_EMRSETROP2 1 0 1 0 0 0 0 0
+ table[ 21] = 0xA0; // U_EMRSETSTRETCHBLTMODE 1 0 1 0 0 0 0 0
+ table[ 22] = 0x20; // U_EMRSETTEXTALIGN 0 0 1 0 0 0 0 0
+ table[ 23] = 0xA0; // U_EMRSETCOLORADJUSTMENT 1 0 1 0 0 0 0 0
+ table[ 24] = 0x20; // U_EMRSETTEXTCOLOR 0 0 1 0 0 0 0 0
+ table[ 25] = 0x20; // U_EMRSETBKCOLOR 0 0 1 0 0 0 0 0
+ table[ 26] = 0xA0; // U_EMROFFSETCLIPRGN 1 0 1 0 0 0 0 0
+ table[ 27] = 0x89; // U_EMRMOVETOEX 1 0 0 0 1 0 0 1
+ table[ 28] = 0xA0; // U_EMRSETMETARGN 1 0 1 0 0 0 0 0
+ table[ 29] = 0xA0; // U_EMREXCLUDECLIPRECT 1 0 1 0 0 0 0 0
+ table[ 30] = 0xA0; // U_EMRINTERSECTCLIPRECT 1 0 1 0 0 0 0 0
+ table[ 31] = 0xA0; // U_EMRSCALEVIEWPORTEXTEX 1 0 1 0 0 0 0 0
+ table[ 32] = 0xA0; // U_EMRSCALEWINDOWEXTEX 1 0 1 0 0 0 0 0
+ table[ 33] = 0xA0; // U_EMRSAVEDC 1 0 1 0 0 0 0 0
+ table[ 34] = 0xA0; // U_EMRRESTOREDC 1 0 1 0 0 0 0 0
+ table[ 35] = 0xA0; // U_EMRSETWORLDTRANSFORM 1 0 1 0 0 0 0 0
+ table[ 36] = 0xA0; // U_EMRMODIFYWORLDTRANSFORM 1 0 1 0 0 0 0 0
+ table[ 37] = 0x20; // U_EMRSELECTOBJECT 0 0 1 0 0 0 0 0
+ table[ 38] = 0x20; // U_EMRCREATEPEN 0 0 1 0 0 0 0 0
+ table[ 39] = 0x20; // U_EMRCREATEBRUSHINDIRECT 0 0 1 0 0 0 0 0
+ table[ 40] = 0x20; // U_EMRDELETEOBJECT 0 0 1 0 0 0 0 0
+ table[ 41] = 0x83; // U_EMRANGLEARC 1 0 0 0 0 0 1 1
+ table[ 42] = 0x87; // U_EMRELLIPSE 1 0 0 0 0 1 1 1
+ table[ 43] = 0x87; // U_EMRRECTANGLE 1 0 0 0 0 1 1 1
+ table[ 44] = 0x87; // U_EMRROUNDRECT 1 0 0 0 0 1 1 1
+ table[ 45] = 0x83; // U_EMRARC 1 0 0 0 0 0 1 1
+ table[ 46] = 0x87; // U_EMRCHORD 1 0 0 0 0 1 1 1
+ table[ 47] = 0x87; // U_EMRPIE 1 0 0 0 0 1 1 1
+ table[ 48] = 0xA0; // U_EMRSELECTPALETTE 1 0 1 0 0 0 0 0
+ table[ 49] = 0xA0; // U_EMRCREATEPALETTE 1 0 1 0 0 0 0 0
+ table[ 50] = 0xA0; // U_EMRSETPALETTEENTRIES 1 0 1 0 0 0 0 0
+ table[ 51] = 0xA0; // U_EMRRESIZEPALETTE 1 0 1 0 0 0 0 0
+ table[ 52] = 0xA0; // U_EMRREALIZEPALETTE 1 0 1 0 0 0 0 0
+ table[ 53] = 0x82; // U_EMREXTFLOODFILL 1 0 0 0 0 0 1 0
+ table[ 54] = 0x8B; // U_EMRLINETO 1 0 0 0 1 0 1 1
+ table[ 55] = 0x8B; // U_EMRARCTO 1 0 0 0 1 0 1 1
+ table[ 56] = 0x83; // U_EMRPOLYDRAW 1 0 0 0 0 0 1 1
+ table[ 57] = 0xA0; // U_EMRSETARCDIRECTION 1 0 1 0 0 0 0 0
+ table[ 58] = 0xA0; // U_EMRSETMITERLIMIT 1 0 1 0 0 0 0 0
+ table[ 59] = 0xE0; // U_EMRBEGINPATH 1 1 1 0 0 0 0 0
+ table[ 60] = 0x80; // U_EMRENDPATH 1 0 0 0 0 0 0 0
+ table[ 61] = 0x84; // U_EMRCLOSEFIGURE 1 0 0 0 0 1 0 0
+ table[ 62] = 0x94; // U_EMRFILLPATH 1 0 0 1 0 1 0 0
+ table[ 63] = 0x94; // U_EMRSTROKEANDFILLPATH 1 0 0 1 0 1 0 0
+ table[ 64] = 0x90; // U_EMRSTROKEPATH 1 0 0 1 0 0 0 0
+ table[ 65] = 0xA0; // U_EMRFLATTENPATH 1 0 1 0 0 0 0 0
+ table[ 66] = 0xA0; // U_EMRWIDENPATH 1 0 1 0 0 0 0 0
+ table[ 67] = 0x80; // U_EMRSELECTCLIPPATH 1 0 0 0 0 0 0 0 consumes the path, draws nothing
+ table[ 68] = 0xA0; // U_EMRABORTPATH 1 0 1 0 0 0 0 0
+ table[ 69] = 0xA0; // U_EMRUNDEF69 1 0 1 0 0 0 0 0
+ table[ 70] = 0x00; // U_EMRCOMMENT 0 0 0 0 0 0 0 0
+ table[ 71] = 0x82; // U_EMRFILLRGN 1 0 0 0 0 0 1 0
+ table[ 72] = 0x82; // U_EMRFRAMERGN 1 0 0 0 0 0 1 0
+ table[ 73] = 0x82; // U_EMRINVERTRGN 1 0 0 0 0 0 1 0
+ table[ 74] = 0x82; // U_EMRPAINTRGN 1 0 0 0 0 0 1 0
+ table[ 75] = 0xA0; // U_EMREXTSELECTCLIPRGN 1 0 1 0 0 0 0 0
+ table[ 76] = 0x82; // U_EMRBITBLT 1 0 0 0 0 0 1 0
+ table[ 77] = 0x82; // U_EMRSTRETCHBLT 1 0 0 0 0 0 1 0
+ table[ 78] = 0x82; // U_EMRMASKBLT 1 0 0 0 0 0 1 0
+ table[ 79] = 0x82; // U_EMRPLGBLT 1 0 0 0 0 0 1 0
+ table[ 80] = 0xA0; // U_EMRSETDIBITSTODEVICE 1 0 1 0 0 0 0 0
+ table[ 81] = 0xA0; // U_EMRSTRETCHDIBITS 1 0 1 0 0 0 0 0
+ table[ 82] = 0x20; // U_EMREXTCREATEFONTINDIRECTW 0 0 1 0 0 0 0 0
+ table[ 83] = 0x02; // U_EMREXTTEXTOUTA 0 0 0 0 0 0 1 0
+ table[ 84] = 0x02; // U_EMREXTTEXTOUTW 0 0 0 0 0 0 1 0
+ table[ 85] = 0x83; // U_EMRPOLYBEZIER16 1 0 0 0 0 0 1 1
+ table[ 86] = 0x83; // U_EMRPOLYGON16 1 0 0 0 0 0 1 1
+ table[ 87] = 0x83; // U_EMRPOLYLINE16 1 0 0 0 0 0 1 1
+ table[ 88] = 0x8B; // U_EMRPOLYBEZIERTO16 1 0 0 0 1 0 1 1
+ table[ 89] = 0x8B; // U_EMRPOLYLINETO16 1 0 0 0 1 0 1 1
+ table[ 90] = 0x83; // U_EMRPOLYPOLYLINE16 1 0 0 0 0 0 1 1
+ table[ 91] = 0x87; // U_EMRPOLYPOLYGON16 1 0 0 0 0 1 1 1
+ table[ 92] = 0x83; // U_EMRPOLYDRAW16 1 0 0 0 0 0 1 1
+ table[ 93] = 0x80; // U_EMRCREATEMONOBRUSH 1 0 0 0 0 0 0 0 Not selected yet, so no change in drawing conditions
+ table[ 94] = 0x80; // U_EMRCREATEDIBPATTERNBRUSHPT 1 0 0 0 0 0 0 0 "
+ table[ 95] = 0x00; // U_EMREXTCREATEPEN 0 0 0 0 0 0 0 0 "
+ table[ 96] = 0x02; // U_EMRPOLYTEXTOUTA 0 0 0 0 0 0 1 0
+ table[ 97] = 0x02; // U_EMRPOLYTEXTOUTW 0 0 0 0 0 0 1 0
+ table[ 98] = 0xA0; // U_EMRSETICMMODE 1 0 1 0 0 0 0 0
+ table[ 99] = 0xA0; // U_EMRCREATECOLORSPACE 1 0 1 0 0 0 0 0
+ table[100] = 0xA0; // U_EMRSETCOLORSPACE 1 0 1 0 0 0 0 0
+ table[101] = 0xA0; // U_EMRDELETECOLORSPACE 1 0 1 0 0 0 0 0
+ table[102] = 0xA0; // U_EMRGLSRECORD 1 0 1 0 0 0 0 0
+ table[103] = 0xA0; // U_EMRGLSBOUNDEDRECORD 1 0 1 0 0 0 0 0
+ table[104] = 0xA0; // U_EMRPIXELFORMAT 1 0 1 0 0 0 0 0
+ table[105] = 0xA0; // U_EMRDRAWESCAPE 1 0 1 0 0 0 0 0
+ table[106] = 0xA0; // U_EMREXTESCAPE 1 0 1 0 0 0 0 0
+ table[107] = 0xA0; // U_EMRUNDEF107 1 0 1 0 0 0 0 0
+ table[108] = 0x02; // U_EMRSMALLTEXTOUT 0 0 0 0 0 0 1 0
+ table[109] = 0xA0; // U_EMRFORCEUFIMAPPING 1 0 1 0 0 0 0 0
+ table[110] = 0xA0; // U_EMRNAMEDESCAPE 1 0 1 0 0 0 0 0
+ table[111] = 0xA0; // U_EMRCOLORCORRECTPALETTE 1 0 1 0 0 0 0 0
+ table[112] = 0xA0; // U_EMRSETICMPROFILEA 1 0 1 0 0 0 0 0
+ table[113] = 0xA0; // U_EMRSETICMPROFILEW 1 0 1 0 0 0 0 0
+ table[114] = 0x82; // U_EMRALPHABLEND 1 0 0 0 0 0 1 0
+ table[115] = 0xA0; // U_EMRSETLAYOUT 1 0 1 0 0 0 0 0
+ table[116] = 0x82; // U_EMRTRANSPARENTBLT 1 0 0 0 0 0 1 0
+ table[117] = 0xA0; // U_EMRUNDEF117 1 0 1 0 0 0 0 0
+ table[118] = 0x82; // U_EMRGRADIENTFILL 1 0 1 0 0 0 1 0
+ table[119] = 0xA0; // U_EMRSETLINKEDUFIS 1 0 1 0 0 0 0 0
+ table[120] = 0x20; // U_EMRSETTEXTJUSTIFICATION 0 0 1 0 0 0 0 0
+ table[121] = 0xA0; // U_EMRCOLORMATCHTOTARGETW 1 0 1 0 0 0 0 0
+ table[122] = 0xA0; // U_EMRCREATECOLORSPACEW 1 0 1 0 0 0 0 0
+ }
+ result = table[type];
+ }
+ return(result);
+}
+
+/**
+ \brief Derive from bounding rect, start and end radials, for arc, chord, or pie, the center, start, and end points, and the bounding rectangle.
+
+ \return 0 on success, other values on errors.
+ \param rclBox bounding rectangle
+ \param ArcStart start of arc
+ \param ArcEnd end of arc
+ \param f1 1 if rotation angle >= 180, else 0
+ \param f2 Rotation direction, 1 if counter clockwise, else 0
+ \param center Center coordinates
+ \param start Start coordinates (point on the ellipse defined by rect)
+ \param end End coordinates (point on the ellipse defined by rect)
+ \param size W,H of the x,y axes of the bounding rectangle.
+*/
+int emr_arc_points_common(
+ PU_RECTL rclBox,
+ PU_POINTL ArcStart,
+ PU_POINTL ArcEnd,
+ int *f1,
+ int f2,
+ PU_PAIRF center,
+ PU_PAIRF start,
+ PU_PAIRF end,
+ PU_PAIRF size
+ ){
+ U_PAIRF estart; // EMF start position, defines a radial
+ U_PAIRF eend; // EMF end position, defines a radial
+ U_PAIRF vec_estart; // define a unit vector from the center to estart
+ U_PAIRF vec_eend; // define a unit vector from the center to eend
+ U_PAIRF radii; // x,y radii of ellipse
+ U_PAIRF ratio; // intermediate value
+ float scale, cross;
+ center->x = ((float)(rclBox->left + rclBox->right ))/2.0;
+ center->y = ((float)(rclBox->top + rclBox->bottom))/2.0;
+ size->x = (float)(rclBox->right - rclBox->left );
+ size->y = (float)(rclBox->bottom - rclBox->top );
+ estart.x = (float)(ArcStart->x);
+ estart.y = (float)(ArcStart->y);
+ eend.x = (float)(ArcEnd->x);
+ eend.y = (float)(ArcEnd->y);
+ radii.x = size->x/2.0;
+ radii.y = size->y/2.0;
+
+ vec_estart.x = (estart.x - center->x); // initial vector, not unit length
+ vec_estart.y = (estart.y - center->y);
+ scale = sqrt(vec_estart.x*vec_estart.x + vec_estart.y*vec_estart.y);
+ if(!scale)return(1); // bogus record, has start at center
+ vec_estart.x /= scale; // now a unit vector
+ vec_estart.y /= scale;
+
+ vec_eend.x = (eend.x - center->x); // initial vector, not unit length
+ vec_eend.y = (eend.y - center->y);
+ scale = sqrt(vec_eend.x*vec_eend.x + vec_eend.y*vec_eend.y);
+ if(!scale)return(2); // bogus record, has end at center
+ vec_eend.x /= scale; // now a unit vector
+ vec_eend.y /= scale;
+
+
+ // Find the intersection of the vectors with the ellipse. With no loss of generality
+ // we can translate the ellipse to the origin, then we just need to find tu (t a factor, u the unit vector)
+ // that also satisfies (x/Rx)^2 + (y/Ry)^2 = 1. x is t*(ux), y is t*(uy), where ux,uy are the x,y components
+ // of the unit vector. Substituting gives:
+ // (t*(ux)/Rx)^2 + (t*(uy)/Ry)^2 = 1
+ // t^2 = 1/( (ux/Rx)^2 + (uy/Ry)^2 )
+ // t = sqrt(1/( (ux/Rx)^2 + (uy/Ry)^2 ))
+
+ ratio.x = vec_estart.x/radii.x;
+ ratio.y = vec_estart.y/radii.y;
+ ratio.x *= ratio.x; // we only use the square
+ ratio.y *= ratio.y;
+ scale = 1.0/sqrt(ratio.x + ratio.y);
+ start->x = center->x + scale * vec_estart.x;
+ start->y = center->y + scale * vec_estart.y;
+
+ ratio.x = vec_eend.x/radii.x;
+ ratio.y = vec_eend.y/radii.y;
+ ratio.x *= ratio.x; // we only use the square
+ ratio.y *= ratio.y;
+ scale = 1.0/sqrt(ratio.x + ratio.y);
+ end->x = center->x + scale * vec_eend.x;
+ end->y = center->y + scale * vec_eend.y;
+
+ //lastly figure out if the swept angle is >180 degrees or not, based on the direction of rotation
+ //and the two unit vectors.
+
+ cross = vec_estart.x * vec_eend.y - vec_estart.y * vec_eend.x;
+ if(!f2){ // counter clockwise rotation
+ if(cross >=0){ *f1 = 1; }
+ else { *f1 = 0; }
+ }
+ else {
+ if(cross >=0){ *f1 = 0; }
+ else { *f1 = 1; }
+ }
+
+
+ return(0);
+}
+
+/**
+ \brief Derive from an EMF arc, chord, or pie the center, start, and end points, and the bounding rectangle.
+
+ \return 0 on success, other values on errors.
+ \param record U_EMRPIE, U_EMRCHORD, or _EMRARC record
+ \param f1 1 if rotation angle >= 180, else 0
+ \param f2 Rotation direction, 1 if counter clockwise, else 0
+ \param center Center coordinates
+ \param start Start coordinates (point on the ellipse defined by rect)
+ \param end End coordinates (point on the ellipse defined by rect)
+ \param size W,H of the x,y axes of the bounding rectangle.
+*/
+int emr_arc_points(
+ PU_ENHMETARECORD record,
+ int *f1,
+ int f2,
+ PU_PAIRF center,
+ PU_PAIRF start,
+ PU_PAIRF end,
+ PU_PAIRF size
+ ){
+ PU_EMRARC pEmr = (PU_EMRARC) (record);
+ return emr_arc_points_common(&(pEmr->rclBox), &(pEmr->ptlStart), &(pEmr->ptlEnd), f1, f2, center, start, end, size );
+}
+
+/**
+ \brief Convert a U_RGBA 32 bit pixmap to one of many different types of DIB pixmaps.
+
+ Conversions to formats using color tables assume that the color table can hold every color
+ in the input image. If that assumption is false then the conversion will fail. Conversion
+ from 8 bit color to N bit colors (N<8) do so by shifting the appropriate number of bits.
+
+ \return 0 on success, other values on errors.
+ \param px DIB pixel array
+ \param cbPx DIB pixel array size in bytes
+ \param ct DIB color table
+ \param numCt DIB color table number of entries
+ \param rgba_px U_RGBA pixel array (32 bits)
+ \param w Width of pixel array
+ \param h Height of pixel array
+ \param stride Row stride of input pixel array in bytes
+ \param colortype DIB BitCount Enumeration
+ \param use_ct If true use color table (only for 1-16 bit DIBs).
+ \param invert If DIB rows are in opposite order from RGBA rows
+*/
+int RGBA_to_DIB(
+ char **px,
+ uint32_t *cbPx,
+ PU_RGBQUAD *ct,
+ int *numCt,
+ const char *rgba_px,
+ int w,
+ int h,
+ int stride,
+ uint32_t colortype,
+ int use_ct,
+ int invert
+ ){
+ int bs;
+ int pad;
+ int i,j,k;
+ int istart, iend, iinc;
+ uint8_t r,g,b,a,tmp8;
+ char *pxptr;
+ const char *rptr;
+ int found;
+ int usedbytes;
+ U_RGBQUAD color;
+ PU_RGBQUAD lct;
+ int32_t index;
+
+ *px=NULL;
+ *ct=NULL;
+ *numCt=0;
+ *cbPx=0;
+ // sanity checking
+ if(!w || !h || !stride || !colortype || !rgba_px)return(1);
+ if(use_ct && colortype >= U_BCBM_COLOR16)return(2); //color tables not used above 16 bit pixels
+ if(!use_ct && colortype < U_BCBM_COLOR16)return(3); //color tables mandatory for < 16 bit
+
+ bs = colortype/8;
+ if(bs<1){
+ usedbytes = (w*colortype + 7)/8; // width of line in fully and partially occupied bytes
+ }
+ else {
+ usedbytes = w*bs;
+ }
+ pad = UP4(usedbytes) - usedbytes; // DIB rows must be aligned on 4 byte boundaries, they are padded at the end to accomplish this.;
+ *cbPx = h * (usedbytes + pad); // Rows must start on a 4 byte boundary!
+ *px = (char *) malloc(*cbPx);
+ if(!px)return(4);
+ if(use_ct){
+ *numCt = 1<< colortype;
+ if(*numCt >w*h)*numCt=w*h;
+ lct = (PU_RGBQUAD) malloc(*numCt * sizeof(U_RGBQUAD));
+ if(!lct)return(5);
+ *ct = lct;
+ }
+
+ if(invert){
+ istart = h-1;
+ iend = -1;
+ iinc = -1;
+ }
+ else {
+ istart = 0;
+ iend = h;
+ iinc = 1;
+ }
+
+ found = 0;
+ tmp8 = 0;
+ pxptr = *px;
+ for(i=istart; i!=iend; i+=iinc){
+ rptr= rgba_px + i*stride;
+ for(j=0; j<w; j++){
+ r = *rptr++;
+ g = *rptr++;
+ b = *rptr++;
+ a = *rptr++;
+ if(use_ct){
+ color = U_BGRA(r,g,b,a); // color has order in memory: b,g,r,a, same as EMF+ ARGB
+ index = -1;
+ for(lct = *ct, k=0; k<found; k++,lct++){ // Is this color in the table (VERY inefficient if there are a lot of colors!!!)
+ if(*(uint32_t *)lct != *(uint32_t *) &color)continue;
+ index =k;
+ break;
+ }
+ if(index==-1){ // add a color
+ found++;
+ if(found > *numCt){ // More colors found than are supported by the color table
+ free(*ct);
+ free(*px);
+ *numCt=0;
+ *cbPx=0;
+ return(6);
+ }
+ index = found - 1;
+ *lct = color;
+ }
+ switch(colortype){
+ case U_BCBM_MONOCHROME: // 2 colors. bmiColors array has two entries
+ tmp8 = tmp8 >> 1; // This seems wrong, as it fills from the top of each byte. But it works.
+ tmp8 |= index << 7;
+ if(!((j+1) % 8)){
+ *pxptr++ = tmp8;
+ tmp8 = 0;
+ }
+ break;
+ case U_BCBM_COLOR4: // 2^4 colors. bmiColors array has 16 entries
+ tmp8 = tmp8 << 4;
+ tmp8 |= index;
+ if(!((j+1) % 2)){
+ *pxptr++ = tmp8;
+ tmp8 = 0;
+ }
+ break;
+ case U_BCBM_COLOR8: // 2^8 colors. bmiColors array has 256 entries
+ tmp8 = index;
+ *pxptr++ = tmp8;
+ break;
+ case U_BCBM_COLOR16: // 2^16 colors. (Several different color methods))
+ case U_BCBM_COLOR24: // 2^24 colors. bmiColors is not used. Pixels are U_RGBTRIPLE.
+ case U_BCBM_COLOR32: // 2^32 colors. bmiColors is not used. Pixels are U_RGBQUAD.
+ case U_BCBM_EXPLICIT: // Derinved from JPG or PNG compressed image or ?
+ default:
+ return(7); // This should not be possible, but might happen with memory corruption
+ }
+ }
+ else {
+ switch(colortype){
+ case U_BCBM_COLOR16: // 2^16 colors. (Several different color methods))
+ b /= 8; g /= 8; r /= 8;
+ // Do it in this way so that the bytes are always stored Little Endian
+ tmp8 = b;
+ tmp8 |= g<<5; // least significant 3 bits of green
+ *pxptr++ = tmp8;
+ tmp8 = g>>3; // most significant 2 bits of green (there are only 5 bits of data)
+ tmp8 |= r<<2;
+ *pxptr++ = tmp8;
+ break;
+ case U_BCBM_COLOR24: // 2^24 colors. bmiColors is not used. Pixels are U_RGBTRIPLE.
+ *pxptr++ = b;
+ *pxptr++ = g;
+ *pxptr++ = r;
+ break;
+ case U_BCBM_COLOR32: // 2^32 colors. bmiColors is not used. Pixels are U_RGBQUAD.
+ *pxptr++ = b;
+ *pxptr++ = g;
+ *pxptr++ = r;
+ *pxptr++ = a;
+ break;
+ case U_BCBM_MONOCHROME: // 2 colors. bmiColors array has two entries
+ case U_BCBM_COLOR4: // 2^4 colors. bmiColors array has 16 entries
+ case U_BCBM_COLOR8: // 2^8 colors. bmiColors array has 256 entries
+ case U_BCBM_EXPLICIT: // Derinved from JPG or PNG compressed image or ?
+ default:
+ return(7); // This should not be possible, but might happen with memory corruption
+ }
+ }
+ }
+ if( use_ct && colortype == U_BCBM_MONOCHROME && (j % 8) ){
+ *pxptr++ = tmp8; // Write last few indices
+ tmp8 = 0;
+ }
+ if( use_ct && colortype == U_BCBM_COLOR4 && (j % 2) ){
+ *pxptr++ = tmp8; // Write last few indices
+ tmp8 = 0;
+ }
+ if(pad){
+ memset(pxptr,0,pad); // not strictly necessary, but set all bytes so that we can find important unset ones with valgrind
+ pxptr += pad;
+ }
+ }
+ return(0);
+}
+
+/**
+ \brief Get the actual number of colors in the color table from the BitMapInfoHeader.
+ \return Number of entries in the color table.
+ \param Bmih char * pointer to the U_BITMAPINFOHEADER
+
+ BitmapInfoHeader may list 0 for some types which implies the maximum value.
+ If the image is big enough, that is set by the bit count, as in 256 for an 8
+ bit image.
+ If the image is smaller it is set by width * height.
+ Note, this may be called by WMF code, so it is not safe to assume the data is aligned.
+*/
+int get_real_color_count(
+ const char *Bmih
+ ){
+ int Colors, BitCount, Width, Height;
+ uint32_t utmp4;
+ uint16_t utmp2;
+ int32_t tmp4;
+ char *cBmih = (char *) Bmih;
+ memcpy(&utmp4, cBmih + offsetof(U_BITMAPINFOHEADER,biClrUsed), 4); Colors = utmp4;
+ memcpy(&utmp2, cBmih + offsetof(U_BITMAPINFOHEADER,biBitCount), 2); BitCount = utmp2;
+ memcpy(&tmp4, cBmih + offsetof(U_BITMAPINFOHEADER,biWidth), 4); Width = tmp4;
+ memcpy(&tmp4, cBmih + offsetof(U_BITMAPINFOHEADER,biHeight), 4); Height = tmp4;
+ return(get_real_color_icount(Colors, BitCount, Width, Height));
+}
+
+/**
+ \brief Get the actual number of colors in the color table from the ClrUsed, BitCount, Width, and Height.
+ \return Number of entries in the color table.
+ \param Colors Number of colors in the table.
+ \param BitCount BitCount Enumeration
+ \param Width bitmap width
+ \param Height bitmap height
+*/
+int get_real_color_icount(
+ int Colors,
+ int BitCount,
+ int Width,
+ int Height
+ ){
+ int area = Width * Height;
+ if(area < 0){ area = -area; } /* Height might be negative */
+ if(Colors == 0){
+ if( BitCount == U_BCBM_MONOCHROME){ Colors = 2; }
+ else if(BitCount == U_BCBM_COLOR4 ){ Colors = 16; }
+ else if(BitCount == U_BCBM_COLOR8 ){ Colors = 256; }
+ if(Colors > area){ Colors = area; }
+ }
+ return(Colors);
+}
+
+
+/**
+ \brief Get the DIB parameters from the BMI of the record for use by DBI_to_RGBA()
+
+ \return BI_Compression Enumeration. For anything other than U_BI_RGB values other than px may not be valid.
+ \param record pointer to EMR record that has a U_BITMAPINFO and bitmap
+ \param offBitsSrc Offset to the bitmap
+ \param offBmiSrc Offset to the U_BITMAPINFO
+ \param px pointer to DIB pixel array in pEmr
+ \param ct pointer to DIB color table in pEmr
+ \param numCt DIB color table number of entries, for PNG or JPG returns the number of bytes in the image
+ \param width Width of pixel array
+ \param height Height of pixel array (always returned as a positive number)
+ \param colortype DIB BitCount Enumeration
+ \param invert If DIB rows are in opposite order from RGBA rows
+*/
+int get_DIB_params(
+ const char *record,
+ uint32_t offBitsSrc,
+ uint32_t offBmiSrc,
+ const char **px,
+ const U_RGBQUAD **ct,
+ uint32_t *numCt,
+ uint32_t *width,
+ uint32_t *height,
+ uint32_t *colortype,
+ uint32_t *invert
+ ){
+ uint32_t bic;
+ PU_BITMAPINFO Bmi = (PU_BITMAPINFO)(record + offBmiSrc);
+ PU_BITMAPINFOHEADER Bmih = &(Bmi->bmiHeader);
+ /* if biCompression is not U_BI_RGB some or all of the following might not hold real values */
+ bic = Bmih->biCompression;
+ *width = Bmih->biWidth;
+ *colortype = Bmih->biBitCount;
+ if(Bmih->biHeight < 0){
+ *height = -Bmih->biHeight;
+ *invert = 1;
+ }
+ else {
+ *height = Bmih->biHeight;
+ *invert = 0;
+ }
+ if(bic == U_BI_RGB){
+ *numCt = get_real_color_count((const char *) Bmih);
+ if( numCt){ *ct = (PU_RGBQUAD) ((char *)Bmi + sizeof(U_BITMAPINFOHEADER)); }
+ else { *ct = NULL; }
+ }
+ else if(bic == U_BI_BITFIELDS){ /* to date only encountered once, for 32 bit, from PPT*/
+ *numCt = 0;
+ *ct = NULL;
+ bic = U_BI_RGB; /* there seems to be no difference, at least for the 32 bit images */
+ }
+ else {
+ *numCt = Bmih->biSizeImage;
+ *ct = NULL;
+ }
+ *px = record + offBitsSrc;
+ return(bic);
+}
+
+/**
+ \brief Convert one of many different types of DIB pixmaps to an RGBA 32 bit pixmap.
+
+ \return 0 on success, other values on errors.
+ \param px DIB pixel array
+ \param ct DIB color table
+ \param numCt DIB color table number of entries
+ \param rgba_px U_RGBA pixel array (32 bits), created by this routine, caller must free.
+ \param w Width of pixel array in the record
+ \param h Height of pixel array in the record
+ \param colortype DIB BitCount Enumeration
+ \param use_ct Kept for symmetry with RGBA_to_DIB, should be set to numCt
+ \param invert If DIB rows are in opposite order from RGBA rows
+*/
+int DIB_to_RGBA(
+ const char *px,
+ const U_RGBQUAD *ct,
+ int numCt,
+ char **rgba_px,
+ int w,
+ int h,
+ uint32_t colortype,
+ int use_ct,
+ int invert
+ ){
+ uint32_t cbRgba_px;
+ int stride;
+ int bs;
+ int pad;
+ int i,j;
+ int istart, iend, iinc;
+ uint8_t r,g,b,a,tmp8;
+ const char *pxptr;
+ char *rptr;
+ int usedbytes;
+ U_RGBQUAD color;
+ int32_t index;
+
+ // sanity checking
+ if(!w || !h || !colortype || !px)return(1);
+ if(use_ct && colortype >= U_BCBM_COLOR16)return(2); //color tables not used above 16 bit pixels
+ if(!use_ct && colortype < U_BCBM_COLOR16)return(3); //color tables mandatory for < 16 bit
+ if(use_ct && !numCt)return(4); //color table not adequately described
+
+ stride = w * 4;
+ cbRgba_px = stride * h;
+ bs = colortype/8;
+ if(bs<1){
+ usedbytes = (w*colortype + 7)/8; // width of line in fully and partially occupied bytes
+ }
+ else {
+ usedbytes = w*bs;
+ }
+ pad = UP4(usedbytes) - usedbytes; // DIB rows must be aligned on 4 byte boundaries, they are padded at the end to accomplish this.;
+ *rgba_px = (char *) malloc(cbRgba_px);
+ if(!rgba_px)return(4);
+
+ if(invert){
+ istart = h-1;
+ iend = -1;
+ iinc = -1;
+ }
+ else {
+ istart = 0;
+ iend = h;
+ iinc = 1;
+ }
+
+ pxptr = px;
+ tmp8 = 0; // silences a compiler warning, tmp8 always sets when j=0, so never used uninitialized
+ for(i=istart; i!=iend; i+=iinc){
+ rptr= *rgba_px + i*stride;
+ for(j=0; j<w; j++){
+ if(use_ct){
+ switch(colortype){
+ case U_BCBM_MONOCHROME: // 2 colors. bmiColors array has two entries
+ if(!(j % 8)){ tmp8 = *pxptr++; }
+ index = 0x80 & tmp8; // This seems wrong, as lowest position is top bit, but it works.
+ index = index >> 7;
+ tmp8 = tmp8 << 1;
+ break;
+ case U_BCBM_COLOR4: // 2^4 colors. bmiColors array has 16 entries
+ if(!(j % 2)){ tmp8 = *pxptr++; }
+ index = 0xF0 & tmp8;
+ index = index >> 4;
+ tmp8 = tmp8 << 4;
+ break;
+ case U_BCBM_COLOR8: // 2^8 colors. bmiColors array has 256 entries
+ index = (uint8_t) *pxptr++;;
+ break;
+ case U_BCBM_COLOR16: // 2^16 colors. (Several different color methods))
+ case U_BCBM_COLOR24: // 2^24 colors. bmiColors is not used. Pixels are U_RGBTRIPLE.
+ case U_BCBM_COLOR32: // 2^32 colors. bmiColors is not used. Pixels are U_RGBQUAD.
+ case U_BCBM_EXPLICIT: // Derinved from JPG or PNG compressed image or ?
+ default:
+ return(7); // This should not be possible, but might happen with memory corruption
+ }
+ color = ct[index];
+ b = U_BGRAGetB(color);
+ g = U_BGRAGetG(color);
+ r = U_BGRAGetR(color);
+ a = U_BGRAGetA(color);
+ }
+ else {
+ switch(colortype){
+ case U_BCBM_COLOR16: // 2^16 colors. (Several different color methods))
+ // Do it in this way because the bytes are always stored Little Endian
+ tmp8 = *pxptr++;
+ b = (0x1F & tmp8) <<3; // 5 bits of b into the top 5 of 8
+ g = tmp8 >> 5; // least significant 3 bits of green
+ tmp8 = *pxptr++;
+ r = (0x7C & tmp8) << 1; // 5 bits of r into the top 5 of 8
+ g |= (0x3 & tmp8) << 3; // most significant 2 bits of green (there are only 5 bits of data)
+ g = g << 3; // restore intensity (have lost 3 bits of accuracy)
+ a = 0;
+ break;
+ case U_BCBM_COLOR24: // 2^24 colors. bmiColors is not used. Pixels are U_RGBTRIPLE.
+ b = *pxptr++;
+ g = *pxptr++;
+ r = *pxptr++;
+ a = 0;
+ break;
+ case U_BCBM_COLOR32: // 2^32 colors. bmiColors is not used. Pixels are U_RGBQUAD.
+ b = *pxptr++;
+ g = *pxptr++;
+ r = *pxptr++;
+ a = *pxptr++;
+ break;
+ case U_BCBM_MONOCHROME: // 2 colors. bmiColors array has two entries
+ case U_BCBM_COLOR4: // 2^4 colors. bmiColors array has 16 entries
+ case U_BCBM_COLOR8: // 2^8 colors. bmiColors array has 256 entries
+ case U_BCBM_EXPLICIT: // Derinved from JPG or PNG compressed image or ?
+ default:
+ return(7); // This should not be possible, but might happen with memory corruption
+ }
+ }
+ *rptr++ = r;
+ *rptr++ = g;
+ *rptr++ = b;
+ *rptr++ = a;
+ }
+ for(j=0; j<pad; j++){ pxptr++; } // DIB rows are all 4 byte aligned
+ }
+ return(0);
+}
+
+/**
+ \brief Extract a subset of an RGBA bitmap array.
+ Frees the incoming bitmap array IF a subset is extracted, otherwise it is left alone.
+ If the entire array is extracted it just returns the incoming pointer.
+ If the subset requested is partially outside of the bitmap the region is clipped to the
+ bitmap boundaries and extracted. This seems to be a (very) grey area in EMF files, and
+ even different Microsoft applications do not always do the same thing. For instance,
+ XP Preview gives some different images for EMR_BITBLT records than does the "import image"
+ (but not unpacked) view in PowerPoint. Since all of these states are probably best viewed
+ as undefined or errors we can only try to do something reasonable and not blow up when
+ encountering one.
+
+ \return Pointer to the sub array on success, NULL otherwise.
+ \param rgba_px U_RGBA pixel array (32 bits), created by this routine, caller must free.
+ \param w Width of pixel array in the record
+ \param h Height of pixel array in the record
+ \param sl start left position in the pixel array in the record to start extracting
+ \param st start top position in the pixel array in the record to start extracting
+ \param eew Width of pixel array to extract
+ \param eeh Height of pixel array to extract
+*/
+char *RGBA_to_RGBA(
+ char *rgba_px,
+ int w,
+ int h,
+ int sl,
+ int st,
+ int *eew,
+ int *eeh
+ ){
+ int i;
+ char *sub;
+ char *sptr;
+ int ew = *eew;
+ int eh = *eeh;
+
+ // sanity checking
+ if(w<=0 || h<=0 || ew<=0 || eh<=0 || !rgba_px)return(NULL);
+
+ if(sl>w || st >h)return(NULL); // This is hopeless, the start point is outside of the array.
+ if(sl<0){
+ if(sl+ew<=0)return(NULL); // This is hopeless, the start point is outside of the array.
+ ew += sl;
+ sl = 0;
+ }
+ if(st<0){
+ if(st+eh<=0)return(NULL); // This is hopeless, the start point is outside of the array.
+ eh += st;
+ st = 0;
+ }
+ if(sl+ew > w)ew=w-sl;
+ if(st+eh > h)eh=h-st;
+ if(!sl && !st && (ew == w) && (eh == h)){
+ sub = rgba_px;
+ }
+ else {
+ sptr = sub = malloc(ew*eh*4);
+ if(!sub)return(NULL);
+ for(i=st; i<st+eh; i++){
+ memcpy(sptr,rgba_px + i*w*4 + sl*4,4*ew);
+ sptr += 4*ew;
+ }
+ free(rgba_px);
+ }
+ *eeh = eh;
+ *eew = ew;
+ return(sub);
+ }
+
+
+/* **********************************************************************************************
+These functions are for setting up, appending to, and then tearing down an EMF structure, including
+writing the final data structure out to a file.
+*********************************************************************************************** */
+
+/**
+ \brief Duplicate an EMR record.
+ \param emr record to duplicate
+*/
+char *emr_dup(
+ const char *emr
+ ){
+ char *dup;
+ int irecsize;
+
+ if(!emr)return(NULL);
+ irecsize = ((PU_EMR)emr)->nSize;
+ dup=malloc(irecsize);
+ if(dup){ memcpy(dup,emr,irecsize); }
+ return(dup);
+}
+
+
+/**
+ \brief Start constructing an emf in memory. Supply the file name and initial size.
+ \return 0 for success, >=0 for failure.
+ \param name EMF filename (will be opened)
+ \param initsize Initialize EMF in memory to hold this many bytes
+ \param chunksize When needed increase EMF in memory by this number of bytes
+ \param et EMF in memory
+
+
+*/
+int emf_start(
+ const char *name,
+ const uint32_t initsize,
+ const uint32_t chunksize,
+ EMFTRACK **et
+ ){
+ FILE *fp;
+ EMFTRACK *etl=NULL;
+
+ if(initsize < 1)return(1);
+ if(chunksize < 1)return(2);
+ if(!name)return(3);
+ etl = (EMFTRACK *) malloc(sizeof(EMFTRACK));
+ if(!etl)return(4);
+ etl->buf = malloc(initsize); // no need to zero the memory
+ if(!etl->buf){
+ free(etl);
+ return(5);
+ }
+ fp=emf_fopen(name,U_WRITE);
+ if(!fp){
+ free(etl->buf);
+ free(etl);
+ return(6);
+ }
+ etl->fp = fp;
+ etl->allocated = initsize;
+ etl->used = 0;
+ etl->records = 0;
+ etl->PalEntries = 0;
+ etl->chunk = chunksize;
+ *et=etl;
+ return(0);
+}
+
+/**
+ \brief Finalize the emf in memory and write it to the file.
+ \return 0 on success, >=1 on failure
+ \param et EMF in memory
+ \param eht EMF handle table (peak handle number needed)
+*/
+int emf_finish(
+ EMFTRACK *et,
+ EMFHANDLES *eht
+ ){
+ U_EMRHEADER *record;
+
+ if(!et->fp)return(1); // This could happen if something stomps on memory, otherwise should be caught in emf_start
+
+ // Set the header fields which were unknown up until this point
+
+ record = (U_EMRHEADER *)et->buf;
+ record->nBytes = et->used;
+ record->nRecords = et->records;
+ record->nHandles = eht->peak + 1;
+ record->nPalEntries = et->PalEntries;
+
+#if U_BYTE_SWAP
+ //This is a Big Endian machine, EMF data must be Little Endian
+ U_emf_endian(et->buf,et->used,1);
+#endif
+
+ if(1 != fwrite(et->buf,et->used,1,et->fp))return(2);
+ (void) fclose(et->fp);
+ et->fp=NULL;
+ return(0);
+}
+
+/**
+ \brief Release memory for an emf structure in memory. Call this after emf_finish().
+ \return 0 on success, >=1 on failure
+ \param et EMF in memory
+*/
+int emf_free(
+ EMFTRACK **et
+ ){
+ EMFTRACK *etl;
+ if(!et)return(1);
+ etl=*et;
+ if(!etl)return(2);
+ free(etl->buf);
+ free(etl);
+ *et=NULL;
+ return(0);
+}
+
+/**
+ \brief wrapper for fopen, works on any platform
+ \return 0 on success, >=1 on failure
+ \param filename file to open (either ASCII or UTF-8)
+ \param mode U_READ or U_WRITE (these map to "rb" and "wb")
+*/
+FILE *emf_fopen(
+ const char *filename,
+ const int mode
+ ){
+ FILE *fp = NULL;
+#ifdef WIN32
+ uint16_t *fn16;
+ uint16_t *md16;
+ if(mode == U_READ){ md16 = U_Utf8ToUtf16le("rb", 0, NULL); }
+ else { md16 = U_Utf8ToUtf16le("wb", 0, NULL); }
+ fn16 = U_Utf8ToUtf16le(filename, 0, NULL);
+ fp = _wfopen(fn16,md16);
+ free(fn16);
+ free(md16);
+#else
+ if(mode == U_READ){ fp = fopen(filename,"rb"); }
+ else { fp = fopen(filename,"wb"); }
+#endif
+ return(fp);
+}
+
+/**
+ \brief Retrieve contents of an EMF file by name.
+ \return 0 on success, >=1 on failure
+ \param filename Name of file to open, including the path
+ \param contents Contents of the file. Buffer must be free()'d by caller.
+ \param length Number of bytes in Contents
+*/
+int emf_readdata(
+ const char *filename,
+ char **contents,
+ size_t *length
+ ){
+ FILE *fp;
+ int status=0;
+
+ *contents=NULL;
+ fp=emf_fopen(filename,U_READ);
+ if(!fp){ status = 1; }
+ else {
+ // read the entire file into memory
+ fseek(fp, 0, SEEK_END); // move to end
+ *length = ftell(fp);
+ rewind(fp);
+ *contents = (char *) malloc(*length);
+ if(!*contents){
+ status = 2;
+ }
+ else {
+ size_t inbytes = fread(*contents,*length,1,fp);
+ if(inbytes != 1){
+ free(*contents);
+ status = 3;
+ }
+ else {
+#if U_BYTE_SWAP
+ //This is a Big Endian machine, EMF data is Little Endian
+ U_emf_endian(*contents,*length,0); // LE to BE
+#endif
+ }
+ }
+ fclose(fp);
+ }
+ return(status);
+}
+
+
+/**
+ \brief Append an EMF record to an emf in memory. This may reallocate buf memory.
+ \return 0 for success, >=1 for failure.
+ \param rec Record to append to EMF in memory
+ \param et EMF in memory
+ \param freerec If true, free rec after append
+*/
+int emf_append(
+ U_ENHMETARECORD *rec,
+ EMFTRACK *et,
+ int freerec
+ ){
+ size_t deficit;
+
+#ifdef U_VALGRIND
+ printf("\nbefore \n");
+ printf(" probe %d\n",memprobe(rec, U_EMRSIZE(rec)));
+ printf("after \n");
+#endif
+ if(!rec)return(1);
+ if(!et)return(2);
+ if(rec->nSize + et->used > et->allocated){
+ deficit = rec->nSize + et->used - et->allocated;
+ if(deficit < et->chunk)deficit = et->chunk;
+ et->allocated += deficit;
+ et->buf = realloc(et->buf,et->allocated);
+ if(!et->buf)return(3);
+ }
+ memcpy(et->buf + et->used, rec, rec->nSize);
+ et->used += rec->nSize;
+ et->records++;
+ if(rec->iType == U_EMR_EOF){ et->PalEntries = ((U_EMREOF *)rec)->cbPalEntries; }
+ if(freerec){ free(rec); }
+ return(0);
+}
+
+/**
+ \brief Create a handle table. Entries filled with 0 are empty, entries >0 hold a handle.
+ \return 0 for success, >=1 for failure.
+ \param initsize Initialize with space for this number of handles
+ \param chunksize When needed increase space by this number of handles
+ \param eht EMF handle table
+*/
+int emf_htable_create(
+ uint32_t initsize,
+ uint32_t chunksize,
+ EMFHANDLES **eht
+ ){
+ EMFHANDLES *ehtl;
+ unsigned int i;
+
+ if(initsize<1)return(1);
+ if(chunksize<1)return(2);
+ ehtl = (EMFHANDLES *) malloc(sizeof(EMFHANDLES));
+ if(!ehtl)return(3);
+ ehtl->table = malloc(initsize * sizeof(uint32_t));
+ if(!ehtl->table){
+ free(ehtl);
+ return(4);
+ }
+ ehtl->stack = malloc(initsize * sizeof(uint32_t));
+ if(!ehtl->stack){
+ free(ehtl->table);
+ free(ehtl);
+ return(5);
+ }
+ memset(ehtl->table , 0, initsize * sizeof(uint32_t)); // zero all slots in the table
+ for(i=1; i<initsize; i++){ehtl->stack[i]=i;} // preset the stack
+ ehtl->allocated = initsize;
+ ehtl->chunk = chunksize;
+ ehtl->table[0] = 0; // This slot isn't actually ever used
+ ehtl->stack[0] = 0; // This stack position isn't actually ever used
+ ehtl->peak = 1;
+ ehtl->sptr = 1;
+ ehtl->top = 0;
+ *eht = ehtl;
+ return(0);
+}
+
+/**
+ \brief Delete an entry from the handle table. Move it back onto the stack. The specified slot is filled with a 0.
+ \return 0 for success, >=1 for failure.
+ \param ih handle
+ \param eht EMF handle table
+
+*/
+int emf_htable_delete(
+ uint32_t *ih,
+ EMFHANDLES *eht
+ ){
+ if(!eht)return(1);
+ if(!eht->table)return(2);
+ if(!eht->stack)return(3);
+ if(*ih < 1)return(4); // invalid handle
+ if(!eht->table[*ih])return(5); // requested table position was not in use
+ eht->table[*ih]=0; // remove handle from table
+ while(eht->top>0 && !eht->table[eht->top]){ // adjust top
+ eht->top--;
+ }
+ eht->sptr--; // adjust stack
+ eht->stack[eht->sptr]=*ih; // place handle on stack
+ *ih=0; // invalidate handle variable, so a second delete will of it is not possible
+ return(0);
+}
+
+/**
+ \brief Returns the index of the first free slot.
+ Call realloc() if needed. The slot is set to handle (indicates occupied) and the peak value is adjusted.
+ \return 0 for success, >=1 for failure.
+ \param ih handle
+ \param eht EMF handle table
+*/
+int emf_htable_insert(
+ uint32_t *ih,
+ EMFHANDLES *eht
+ ){
+ unsigned int i;
+ size_t newsize;
+
+ if(!eht)return(1);
+ if(!eht->table)return(2);
+ if(!eht->stack)return(3);
+ if(!ih)return(4);
+ if(eht->sptr >= eht->allocated - 1){ // need to reallocate
+ newsize=eht->allocated + eht->chunk;
+ eht->table = realloc(eht->table,newsize * sizeof(uint32_t));
+ if(!eht->table)return(5);
+ memset(&eht->table[eht->allocated] , 0, eht->chunk * sizeof(uint32_t)); // zero all NEW slots in the table
+
+ eht->stack = realloc(eht->stack,newsize * sizeof(uint32_t));
+ if(!eht->stack)return(6);
+ for(i=eht->allocated; i<newsize;i++){ eht->stack[i] = i; } // init all NEW slots in the stack
+ eht->allocated = newsize;
+ }
+ *ih = eht->stack[eht->sptr]; // handle that is inserted
+ if(eht->table[*ih])return(7);
+ eht->table[*ih] = *ih; // handle goes into preexisting (but zero) slot in table
+ eht->stack[eht->sptr] = 0;
+ if(*ih > eht->top){ eht->top = *ih; }
+ if(eht->sptr > eht->peak){ eht->peak = eht->sptr; }
+ eht->sptr++; // next available handle
+ return(0);
+}
+
+/**
+ \brief Free all memory in an htable. Sets the pointer to NULL.
+ \return 0 for success, >=1 for failure.
+ \param eht EMF handle table
+*/
+int emf_htable_free(
+ EMFHANDLES **eht
+ ){
+ EMFHANDLES *ehtl;
+ if(!eht)return(1);
+ ehtl = *eht;
+ if(!ehtl)return(2);
+ if(!ehtl->table)return(3);
+ if(!ehtl->stack)return(4);
+ free(ehtl->table);
+ free(ehtl->stack);
+ free(ehtl);
+ *eht=NULL;
+ return(0);
+}
+
+/* **********************************************************************************************
+These functions create standard structures used in the EMR records.
+*********************************************************************************************** */
+
+
+/**
+ \brief Set up fields for an EMR_HEADER from the physical device's width and height in mm and dots per millimeter.
+ Typically this is something like 216,279,47.244 (Letter paper, 1200 DPI = 47.244 DPmm)
+ \return 0 for success, >=1 for failure.
+ \param xmm Device width in millimeters
+ \param ymm Device height in millimeters
+ \param dpmm Dots per millimeter
+ \param szlDev Device size structure in pixels
+ \param szlMm Device size structure in mm
+*/
+int device_size(
+ const int xmm,
+ const int ymm,
+ const float dpmm,
+ U_SIZEL *szlDev,
+ U_SIZEL *szlMm
+ ){
+ if(xmm < 0 || ymm < 0 || dpmm < 0)return(1);
+ szlDev->cx = U_ROUND((float) xmm * dpmm);
+ szlDev->cy = U_ROUND((float) ymm * dpmm);;
+ szlMm->cx = xmm;
+ szlMm->cy = ymm;
+ return(0);
+}
+
+/**
+ \brief Set up fields for an EMR_HEADER for drawing by physical size in mm and dots per millimeter.
+ Technically rclBounds is supposed to be the extent of the drawing within the EMF, but libUEMF has no way
+ of knowing this since it never actually draws anything. Instead this is set to the full drawing size.
+ Coordinates are inclusive inclusive, so 297 -> 0,29699.
+ \return 0 for success, >=1 for failure.
+ \param xmm Drawing width in millimeters
+ \param ymm Drawing height in millimeters
+ \param dpmm Dots per millimeter
+ \param rclBounds Drawing size structure in pixels
+ \param rclFrame Drawing size structure in mm
+*/
+int drawing_size(
+ const int xmm,
+ const int ymm,
+ const float dpmm,
+ U_RECTL *rclBounds,
+ U_RECTL *rclFrame
+ ){
+ if(xmm < 0 || ymm < 0 || dpmm < 0)return(1);
+ rclBounds->left = 0;
+ rclBounds->top = 0;
+ rclBounds->right = U_ROUND((float) xmm * dpmm) - 1; // because coordinate system is 0,0 in upper left, N,M in lower right
+ rclBounds->bottom = U_ROUND((float) ymm * dpmm) - 1;
+ rclFrame->left = 0;
+ rclFrame->top = 0;
+ rclFrame->right = U_ROUND((float) xmm * 100.) - 1;
+ rclFrame->bottom = U_ROUND((float) ymm * 100.) - 1;
+ return(0);
+}
+
+/**
+ \brief Set a U_COLORREF value from separate R,G,B values.
+ \param red Red component
+ \param green Green component
+ \param blue Blue component
+
+*/
+U_COLORREF colorref3_set(
+ uint8_t red,
+ uint8_t green,
+ uint8_t blue
+ ){
+ U_COLORREF cr = (U_COLORREF){red , green, blue, 0};
+ return(cr);
+}
+
+/**
+ \brief Set a U_COLORREF value from separate R,G,B, and Reserved values.
+ \param red Red component
+ \param green Green component
+ \param blue Blue component
+ \param Reserved Reserved component
+
+*/
+U_COLORREF colorref4_set(
+ uint8_t red,
+ uint8_t green,
+ uint8_t blue,
+ uint8_t Reserved
+ ){
+ U_COLORREF cr = (U_COLORREF){red , green, blue, Reserved};
+ return(cr);
+}
+
+/**
+ \brief Set a U_RGBQUAD value from separate R,G,B, Reserved values.
+ \param red Red component
+ \param green Green component
+ \param blue Blue component
+ \param reserved Reserved component
+
+*/
+U_RGBQUAD rgbquad_set(
+ uint8_t red,
+ uint8_t green,
+ uint8_t blue,
+ uint8_t reserved
+ ){
+ U_RGBQUAD cr = (U_RGBQUAD){blue , green, red, reserved};
+ return(cr);
+}
+
+/**
+ \brief Set rect and rectl objects from Upper Left and Lower Right corner points.
+ \param ul upper left corner of rectangle
+ \param lr lower right corner of rectangle
+*/
+U_RECTL rectl_set(
+ U_POINTL ul,
+ U_POINTL lr
+ ){
+ U_RECTL rct;
+ rct.left = ul.x;
+ rct.top = ul.y;
+ rct.right = lr.x;
+ rct.bottom = lr.y;
+ return(rct);
+}
+
+/**
+ \brief Set rect and rectl objects from Upper Left and Lower Right corner points.
+ \param array array of rectangles
+ \param index array entry to fill, numbered from 0
+ \param ul upper left corner of rectangle
+ \param lr lower right corner of rectangle
+*/
+void rectli_set(
+ PU_RECTL array,
+ int index,
+ U_POINTL ul,
+ U_POINTL lr
+ ){
+ PU_RECTL rct = &(array[index]);
+ rct->left = ul.x;
+ rct->top = ul.y;
+ rct->right = lr.x;
+ rct->bottom = lr.y;
+}
+
+/**
+ \brief Set sizel objects with X,Y values.
+ \param x X coordinate
+ \param y Y coordinate
+*/
+U_SIZEL sizel_set(
+ int32_t x,
+ int32_t y
+ ){
+ U_SIZEL sz;
+ sz.cx = x;
+ sz.cy = y;
+ return(sz);
+}
+
+/**
+ \brief Set pointl objects with X,Y values.
+ \param x X coordinate
+ \param y Y coordinate
+*/
+U_POINTL point32_set(
+ int32_t x,
+ int32_t y
+ ){
+ U_POINTL pt;
+ pt.x = x;
+ pt.y = y;
+ return(pt);
+}
+
+/**
+ \brief Set point16 objects with 16 bit X,Y values.
+ \param x X coordinate
+ \param y Y coordinate
+*/
+U_POINT16 point16_set(
+ int16_t x,
+ int16_t y
+ ){
+ U_POINT16 pt;
+ pt.x = x;
+ pt.y = y;
+ return(pt);
+}
+
+/**
+ \brief Find the bounding rectangle from a polyline of a given width.
+ \param count number of points in the polyline
+ \param pts the polyline
+ \param width width of drawn line
+
+*/
+U_RECT findbounds(
+ uint32_t count,
+ PU_POINT pts,
+ uint32_t width
+ ){
+ U_RECT rect={INT32_MAX, INT32_MAX, INT32_MIN, INT32_MIN };
+ unsigned int i;
+
+ for(i=0; i<count;i++,pts++){
+ if ( pts->x < rect.left ) rect.left = pts->x;
+ if ( pts->x > rect.right ) rect.right = pts->x;
+ if ( pts->y < rect.top ) rect.top = pts->y;
+ if ( pts->y > rect.bottom ) rect.bottom = pts->y;
+ }
+ if(width > 0){
+ rect.left -= width;
+ rect.right += width;
+ rect.top += width;
+ rect.bottom -= width;
+ }
+ return(rect);
+}
+
+/**
+ \brief Find the bounding rectangle from a polyline of a given width.
+ \param count number of points in the polyline
+ \param pts the polyline
+ \param width width of drawn line
+
+*/
+U_RECT findbounds16(
+ uint32_t count,
+ PU_POINT16 pts,
+ uint32_t width
+ ){
+ U_RECT rect={INT16_MAX, INT16_MAX, INT16_MIN, INT16_MIN };
+ unsigned int i;
+
+ for(i=0; i<count;i++,pts++){
+ if ( pts->x < rect.left ) rect.left = pts->x;
+ if ( pts->x > rect.right ) rect.right = pts->x;
+ if ( pts->y < rect.top ) rect.top = pts->y;
+ if ( pts->y > rect.bottom ) rect.bottom = pts->y;
+ }
+ if(width > 0){
+ rect.left -= width;
+ rect.right += width;
+ rect.top += width;
+ rect.bottom -= width;
+ }
+ return(rect);
+}
+/**
+ \brief Construct a U_LOGBRUSH structure.
+ \return U_LOGBRUSH structure
+ \param lbStyle LB_Style Enumeration
+ \param lbColor Brush color
+ \param lbHatch HatchStyle Enumertaion
+*/
+U_LOGBRUSH logbrush_set(
+ uint32_t lbStyle,
+ U_COLORREF lbColor,
+ int32_t lbHatch
+ ){
+ U_LOGBRUSH lb;
+ lb.lbStyle = lbStyle;
+ lb.lbColor = lbColor;
+ lb.lbHatch = lbHatch;
+ return(lb);
+}
+
+/**
+ \brief Construct a U_XFORM structure.
+ \return U_XFORM structure
+ \param eM11 Rotation Matrix element
+ \param eM12 Rotation Matrix element
+ \param eM21 Rotation Matrix element
+ \param eM22 Rotation Matrix element
+ \param eDx Translation element
+ \param eDy Translation element
+*/
+U_XFORM xform_set(
+ U_FLOAT eM11,
+ U_FLOAT eM12,
+ U_FLOAT eM21,
+ U_FLOAT eM22,
+ U_FLOAT eDx,
+ U_FLOAT eDy
+ ){
+ U_XFORM xform;
+ xform.eM11 = eM11;
+ xform.eM12 = eM12;
+ xform.eM21 = eM21;
+ xform.eM22 = eM22;
+ xform.eDx = eDx;
+ xform.eDy = eDy;
+ return(xform);
+}
+
+/**
+ \brief Construct a U_XFORM structure.
+ \return U_XFORM structure
+ \param scale Scale factor
+ \param ratio Ratio of minor axis/major axis
+ \param rot Rotation angle in degrees, positive is counter clockwise from the x axis.
+ \param axisrot Angle in degrees defining the major axis before rotation, positive is counter clockwise from the x axis.
+ \param eDx Translation element
+ \param eDy Translation element
+
+ Operation is:
+ 1 Conformal map of points based on scale, axis rotation, and axis ratio,
+ 2. Apply rotation
+ 3. Apply offset
+*/
+U_XFORM xform_alt_set(
+ U_FLOAT scale,
+ U_FLOAT ratio,
+ U_FLOAT rot,
+ U_FLOAT axisrot,
+ U_FLOAT eDx,
+ U_FLOAT eDy
+ ){
+ U_XFORM xform;
+ U_MAT2X2 mat1, mat2;
+ // angles are in degrees, must be in radians
+ rot *= (2.0 * U_PI)/360.0;
+ axisrot *= -(2.0 * U_PI)/360.0;
+ mat1.M11 = cos(rot); // set up the rotation matrix
+ mat1.M12 = -sin(rot);
+ mat1.M21 = sin(rot);
+ mat1.M22 = cos(rot);
+ if(ratio!=1.0){ // set scale/ellipticity matrix
+ mat2.M11 = scale*( cos(axisrot)*cos(axisrot) + ratio*sin(axisrot)*sin(axisrot) );
+ mat2.M12 = mat2.M21 = scale*( sin(axisrot)*cos(axisrot) * (1.0 - ratio) );
+ mat2.M22 = scale*( sin(axisrot)*sin(axisrot) + ratio*cos(axisrot)*cos(axisrot) );
+ }
+ else { // when the ratio is 1.0 then the major axis angle is ignored and only scale matters
+ mat2.M11 = scale;
+ mat2.M12 = 0.0;
+ mat2.M21 = 0.0;
+ mat2.M22 = scale;
+ }
+ xform.eM11 = mat2.M11 * mat1.M11 + mat2.M12 * mat1.M21;
+ xform.eM12 = mat2.M11 * mat1.M12 + mat2.M12 * mat1.M22;;
+ xform.eM21 = mat2.M21 * mat1.M11 + mat2.M22 * mat1.M21;
+ xform.eM22 = mat2.M21 * mat1.M12 + mat2.M22 * mat1.M22;
+ xform.eDx = eDx;
+ xform.eDy = eDy;
+ return(xform);
+}
+
+
+/**
+ \brief Construct a U_LOGCOLORSPACEA structure.
+ \return U_LOGCOLORSPACEA structure
+ \param lcsCSType LCS_CSType Enumeration
+ \param lcsIntent LCS_Intent Enumeration
+ \param lcsEndpoints CIE XYZ color space endpoints
+ \param lcsGammaRGB Gamma For RGB
+ \param lcsFilename Could name an external color profile file, otherwise empty string
+*/
+U_LOGCOLORSPACEA logcolorspacea_set(
+ int32_t lcsCSType,
+ int32_t lcsIntent,
+ U_CIEXYZTRIPLE lcsEndpoints,
+ U_LCS_GAMMARGB lcsGammaRGB,
+ char *lcsFilename
+ ){
+ U_LOGCOLORSPACEA lcsa;
+ lcsa.lcsSignature = U_LCS_SIGNATURE;
+ lcsa.lcsVersion = U_LCS_SIGNATURE;
+ lcsa.lcsSize = sizeof(U_LOGCOLORSPACEA);
+ lcsa.lcsCSType = lcsCSType;
+ lcsa.lcsIntent = lcsIntent;
+ lcsa.lcsEndpoints = lcsEndpoints;
+ lcsa.lcsGammaRGB = lcsGammaRGB;
+ strncpy(lcsa.lcsFilename,lcsFilename,U_MAX_PATH);
+ lcsa.lcsFilename[U_MAX_PATH-1] = '\0';
+ return(lcsa);
+}
+
+/**
+
+ \brief Construct a U_LOGCOLORSPACEW structure.
+ \return U_LOGCOLORSPACEW structure
+ \param lcsCSType LCS_CSType Enumeration
+ \param lcsIntent LCS_Intent Enumeration
+ \param lcsEndpoints CIE XYZ color space endpoints
+ \param lcsGammaRGB Gamma For RGB
+ \param lcsFilename Could name an external color profile file, otherwise empty string
+*/
+U_LOGCOLORSPACEW logcolorspacew_set(
+ int32_t lcsCSType,
+ int32_t lcsIntent,
+ U_CIEXYZTRIPLE lcsEndpoints,
+ U_LCS_GAMMARGB lcsGammaRGB,
+ uint16_t *lcsFilename
+ ){
+ U_LOGCOLORSPACEW lcsa;
+ lcsa.lcsSignature = U_LCS_SIGNATURE;
+ lcsa.lcsVersion = U_LCS_SIGNATURE;
+ lcsa.lcsSize = sizeof(U_LOGCOLORSPACEW);
+ lcsa.lcsCSType = lcsCSType;
+ lcsa.lcsIntent = lcsIntent;
+ lcsa.lcsEndpoints = lcsEndpoints;
+ lcsa.lcsGammaRGB = lcsGammaRGB;
+ wchar16strncpypad(lcsa.lcsFilename,lcsFilename,U_MAX_PATH);
+ lcsa.lcsFilename[U_MAX_PATH-1] = '\0';
+ return(lcsa);
+}
+
+/**
+
+ \brief Construct a U_PANOSE structure.
+ \return U_PANOSE structure
+ \param bFamilyType FamilyType Enumeration
+ \param bSerifStyle SerifType Enumeration
+ \param bWeight Weight Enumeration
+ \param bProportion Proportion Enumeration
+ \param bContrast Contrast Enumeration
+ \param bStrokeVariation StrokeVariation Enumeration
+ \param bArmStyle ArmStyle Enumeration
+ \param bLetterform Letterform Enumeration
+ \param bMidline Midline Enumeration
+ \param bXHeight XHeight Enumeration
+*/
+U_PANOSE panose_set(
+ uint8_t bFamilyType,
+ uint8_t bSerifStyle,
+ uint8_t bWeight,
+ uint8_t bProportion,
+ uint8_t bContrast,
+ uint8_t bStrokeVariation,
+ uint8_t bArmStyle,
+ uint8_t bLetterform,
+ uint8_t bMidline,
+ uint8_t bXHeight
+ ){
+ U_PANOSE panose;
+ panose.bFamilyType = bFamilyType;
+ panose.bSerifStyle = bSerifStyle;
+ panose.bWeight = bWeight;
+ panose.bProportion = bProportion;
+ panose.bContrast = bContrast;
+ panose.bStrokeVariation = bStrokeVariation;
+ panose.bArmStyle = bArmStyle;
+ panose.bLetterform = bLetterform;
+ panose.bMidline = bMidline;
+ panose.bXHeight = bXHeight;
+ return(panose);
+}
+
+/**
+ \brief Construct a U_LOGFONT structure.
+ \return U_LOGFONT structure
+ \param lfHeight Height in Logical units
+ \param lfWidth Average Width in Logical units
+ \param lfEscapement Angle in 0.1 degrees betweem escapement vector and X axis
+ \param lfOrientation Angle in 0.1 degrees between baseline and X axis
+ \param lfWeight LF_Weight Enumeration
+ \param lfItalic Italics: 0 or 1
+ \param lfUnderline Underline: 0 or 1
+ \param lfStrikeOut Strikeout: 0 or 1
+ \param lfCharSet LF_CharSet Enumeration
+ \param lfOutPrecision LF_OutPrecision Enumeration
+ \param lfClipPrecision LF_ClipPrecision Enumeration
+ \param lfQuality LF_Quality Enumeration
+ \param lfPitchAndFamily LF_PitchAndFamily Enumeration
+ \param lfFaceName Name of font. truncates at U_LF_FACESIZE, smaller must be null terminated
+
+*/
+U_LOGFONT logfont_set(
+ int32_t lfHeight,
+ int32_t lfWidth,
+ int32_t lfEscapement,
+ int32_t lfOrientation,
+ int32_t lfWeight,
+ uint8_t lfItalic,
+ uint8_t lfUnderline,
+ uint8_t lfStrikeOut,
+ uint8_t lfCharSet,
+ uint8_t lfOutPrecision,
+ uint8_t lfClipPrecision,
+ uint8_t lfQuality,
+ uint8_t lfPitchAndFamily,
+ uint16_t *lfFaceName
+ ){
+ U_LOGFONT lf;
+ lf.lfHeight = lfHeight;
+ lf.lfWidth = lfWidth;
+ lf.lfEscapement = lfEscapement;
+ lf.lfOrientation = lfOrientation;
+ lf.lfWeight = lfWeight;
+ lf.lfItalic = lfItalic;
+ lf.lfUnderline = lfUnderline;
+ lf.lfStrikeOut = lfStrikeOut;
+ lf.lfCharSet = lfCharSet;
+ lf.lfOutPrecision = lfOutPrecision;
+ lf.lfClipPrecision = lfClipPrecision;
+ lf.lfQuality = lfQuality;
+ lf.lfPitchAndFamily = lfPitchAndFamily;
+ wchar16strncpypad(lf.lfFaceName, lfFaceName, U_LF_FACESIZE); // pad this one as the intial structure was not set to zero
+ lf.lfFaceName[U_LF_FACESIZE-1] = '\0';
+ return(lf);
+}
+
+
+/**
+ \brief Construct a U_LOGFONT_PANOSE structure.
+ \return U_LOGFONT_PANOSE structure
+ \param elfLogFont Basic font attributes
+ \param elfFullName Font full name, truncates at U_LF_FULLFACESIZE, smaller must be null terminated
+ \param elfStyle Font style, truncates at U_LF_FULLFACESIZE, smaller must be null terminated
+ \param elfStyleSize Font hinting starting at this point size, if 0, starts at Height
+ \param elfPanose Panose Object. If all zero, it is ignored.
+*/
+U_LOGFONT_PANOSE logfont_panose_set(
+ U_LOGFONT elfLogFont,
+ uint16_t *elfFullName,
+ uint16_t *elfStyle,
+ uint32_t elfStyleSize,
+ U_PANOSE elfPanose
+ ){
+ U_LOGFONT_PANOSE lfp;
+ memset(&lfp,0,sizeof(U_LOGFONT_PANOSE)); // all fields zero unless needed. Many should be ignored or must be 0.
+ wchar16strncpy(lfp.elfFullName, elfFullName, U_LF_FULLFACESIZE);
+ lfp.elfFullName[U_LF_FULLFACESIZE-1] = '\0';
+ wchar16strncpy(lfp.elfStyle, elfStyle, U_LF_FACESIZE);
+ lfp.elfStyle[U_LF_FACESIZE-1] = '\0';
+ lfp.elfLogFont = elfLogFont;
+ lfp.elfStyleSize = elfStyleSize;
+ lfp.elfPanose = elfPanose;
+ return(lfp);
+}
+
+/**
+ \brief Construct a U_BITMAPINFOHEADER structure.
+ \return U_BITMAPINFOHEADER structure
+ \param biWidth Bitmap width in pixels
+ \param biHeight Bitmap height in pixels
+ \param biPlanes Planes (must be 1)
+ \param biBitCount BitCount Enumeration
+ \param biCompression BI_Compression Enumeration
+ \param biSizeImage Size in bytes of image
+ \param biXPelsPerMeter X Resolution in pixels/meter
+ \param biYPelsPerMeter Y Resolution in pixels/meter
+ \param biClrUsed Number of bmciColors in U_BITMAPCOREINFO
+ \param biClrImportant Number of bmciColors needed (0 means all).
+*/
+U_BITMAPINFOHEADER bitmapinfoheader_set(
+ int32_t biWidth,
+ int32_t biHeight,
+ uint16_t biPlanes,
+ uint16_t biBitCount,
+ uint32_t biCompression,
+ uint32_t biSizeImage,
+ int32_t biXPelsPerMeter,
+ int32_t biYPelsPerMeter,
+ U_NUM_RGBQUAD biClrUsed,
+ uint32_t biClrImportant
+ ){
+ U_BITMAPINFOHEADER Bmi;
+ Bmi.biSize = sizeof(U_BITMAPINFOHEADER);
+ Bmi.biWidth = biWidth;
+ Bmi.biHeight = biHeight;
+ Bmi.biPlanes = biPlanes;
+ Bmi.biBitCount = biBitCount;
+ Bmi.biCompression = biCompression;
+ Bmi.biSizeImage = biSizeImage;
+ Bmi.biXPelsPerMeter = biXPelsPerMeter;
+ Bmi.biYPelsPerMeter = biYPelsPerMeter;
+ Bmi.biClrUsed = biClrUsed;
+ Bmi.biClrImportant = biClrImportant;
+ return(Bmi);
+}
+
+
+/**
+ \brief Allocate and construct a U_BITMAPINFO structure.
+ \return Pointer to a U_BITMAPINFO structure
+ \param BmiHeader Geometry and pixel properties
+ \param BmiColors Color table (must be NULL for some values of BmiHeader->biBitCount)
+*/
+PU_BITMAPINFO bitmapinfo_set(
+ U_BITMAPINFOHEADER BmiHeader,
+ PU_RGBQUAD BmiColors
+ ){
+ char *record;
+ int irecsize;
+ int cbColors, cbColors4, off;
+
+ cbColors = 4*get_real_color_count((char *) &BmiHeader);
+ cbColors4 = UP4(cbColors);
+ irecsize = sizeof(U_BITMAPINFOHEADER) + cbColors4;
+ record = malloc(irecsize);
+ if(record){
+ memcpy(record, &BmiHeader, sizeof(U_BITMAPINFOHEADER));
+ if(cbColors){
+ off = sizeof(U_BITMAPINFOHEADER);
+ memcpy(record + off, BmiColors, cbColors);
+ off += cbColors;
+ if(cbColors4 - cbColors){ memset(record + off, 0, cbColors4 - cbColors); }
+ }
+ }
+ return((PU_BITMAPINFO) record);
+}
+
+/**
+ \brief Allocate and construct a U_EXTLOGPEN structure.
+ \return pointer to U_EXTLOGPEN structure, or NULL on error
+ \param elpPenStyle PenStyle Enumeration
+ \param elpWidth Width in logical units (elpPenStyle & U_PS_GEOMETRIC) or 1 (pixel)
+ \param elpBrushStyle LB_Style Enumeration
+ \param elpColor Pen color
+ \param elpHatch HatchStyle Enumeration
+ \param elpNumEntries Count of StyleEntry array
+ \param elpStyleEntry Array of StyleEntry (For user specified dot/dash patterns)
+*/
+PU_EXTLOGPEN extlogpen_set(
+ uint32_t elpPenStyle,
+ uint32_t elpWidth,
+ uint32_t elpBrushStyle,
+ U_COLORREF elpColor,
+ int32_t elpHatch,
+ U_NUM_STYLEENTRY elpNumEntries,
+ U_STYLEENTRY *elpStyleEntry
+ ){
+ int irecsize,szSyleArray;
+ char *record;
+
+ if(elpNumEntries){
+ if(!elpStyleEntry)return(NULL);
+ szSyleArray = elpNumEntries * sizeof(U_STYLEENTRY);
+ irecsize = sizeof(U_EXTLOGPEN) + szSyleArray - sizeof(U_STYLEENTRY); // first one is in the record
+ }
+ else {
+ szSyleArray = 0;
+ irecsize = sizeof(U_EXTLOGPEN);
+ }
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EXTLOGPEN) record)->elpPenStyle = elpPenStyle;
+ ((PU_EXTLOGPEN) record)->elpWidth = elpWidth;
+ ((PU_EXTLOGPEN) record)->elpBrushStyle = elpBrushStyle;
+ ((PU_EXTLOGPEN) record)->elpColor = elpColor;
+ ((PU_EXTLOGPEN) record)->elpHatch = elpHatch;
+ ((PU_EXTLOGPEN) record)->elpNumEntries = elpNumEntries;
+ if(elpNumEntries){ memcpy(((PU_EXTLOGPEN) record)->elpStyleEntry,elpStyleEntry,szSyleArray); }
+ else { memset(((PU_EXTLOGPEN) record)->elpStyleEntry,0,sizeof(U_STYLEENTRY)); } // not used, but this stops valgrind warnings
+ }
+ return((PU_EXTLOGPEN) record);
+}
+
+/**
+ \brief Construct a U_LOGPEN structure.
+ \return U_LOGPEN structure
+ \param lopnStyle PenStyle Enumeration
+ \param lopnWidth Width of pen set by X, Y is ignored
+ \param lopnColor Pen color value
+
+*/
+U_LOGPEN logpen_set(
+ uint32_t lopnStyle,
+ U_POINT lopnWidth,
+ U_COLORREF lopnColor
+ ){
+ U_LOGPEN lp;
+ lp.lopnStyle = lopnStyle;
+ lp.lopnWidth = lopnWidth;
+ lp.lopnColor = lopnColor;
+ return(lp);
+}
+
+/**
+ \brief Construct a U_LOGPLTNTRY structure.
+ \return U_LOGPLTNTRY structure
+ \param peReserved Ignore
+ \param peRed Palette entry Red Intensity
+ \param peGreen Palette entry Green Intensity
+ \param peBlue Palette entry Blue Intensity
+*/
+U_LOGPLTNTRY logpltntry_set(
+ uint8_t peReserved,
+ uint8_t peRed,
+ uint8_t peGreen,
+ uint8_t peBlue
+ ){
+ U_LOGPLTNTRY lpny;
+ lpny.peReserved = peReserved;
+ lpny.peRed = peRed;
+ lpny.peGreen = peGreen;
+ lpny.peBlue = peBlue;
+ return(lpny);
+}
+
+/**
+ \brief Allocate and construct a U_LOGPALETTE structure.
+ \return pointer to U_LOGPALETTE structure, or NULL on error.
+ \param palNumEntries Number of U_LOGPLTNTRY objects
+ \param palPalEntry array, PC_Entry Enumeration
+*/
+PU_LOGPALETTE logpalette_set(
+ U_NUM_LOGPLTNTRY palNumEntries,
+ PU_LOGPLTNTRY *palPalEntry
+ ){
+ PU_LOGPALETTE record;
+ int cbPalArray,irecsize;
+
+ if(palNumEntries == 0 || !palPalEntry)return(NULL);
+ cbPalArray = palNumEntries * sizeof(U_LOGPLTNTRY);
+ irecsize = sizeof(U_LOGPALETTE) + cbPalArray - sizeof(U_LOGPLTNTRY);
+ record = (PU_LOGPALETTE) malloc(irecsize);
+ if(irecsize){
+ record->palVersion = U_LP_VERSION;
+ record->palNumEntries = palNumEntries;
+ memcpy(record->palPalEntry,palPalEntry,cbPalArray);
+ }
+ return(record);
+}
+
+/**
+ \brief Construct a U_RGNDATAHEADER structure.
+ \return U_RGNDATAHEADER structure
+ \param nCount Number of rectangles in region
+ \param rclBounds Region bounds
+*/
+U_RGNDATAHEADER rgndataheader_set(
+ U_NUM_RECTL nCount,
+ U_RECTL rclBounds
+ ){
+ U_RGNDATAHEADER rdh;
+ rdh.dwSize = U_RDH_OBJSIZE;
+ rdh.iType = U_RDH_RECTANGLES;
+ rdh.nCount = nCount;
+ rdh.nRgnSize = nCount * sizeof(U_RECTL); // Size in bytes of rectangle array
+ rdh.rclBounds = rclBounds;
+ return(rdh);
+}
+
+/**
+ \brief Allocate and construct a U_RGNDATA structure.
+ \return pointer to U_RGNDATA structure, or NULL on error.
+ \param rdh Data description
+ \param Buffer Array of U_RECTL elements
+*/
+PU_RGNDATA rgndata_set(
+ U_RGNDATAHEADER rdh,
+ PU_RECTL Buffer
+ ){
+ char *record;
+ int irecsize;
+ int szRgnArray,off;
+
+ if(!Buffer || !rdh.nCount || !rdh.nRgnSize)return(NULL);
+ szRgnArray = rdh.nRgnSize; // size of the U_RECTL array
+ irecsize = sizeof(U_RGNDATA) + szRgnArray - sizeof(U_RECTL); // core + array - overlap
+ record = malloc(irecsize);
+ if(record){
+ memcpy(record, &rdh, sizeof(U_RGNDATAHEADER));
+ off = sizeof(U_RGNDATAHEADER);
+ memcpy(record + off, Buffer, szRgnArray);
+ }
+ return((PU_RGNDATA) record);
+}
+
+/**
+ \brief Construct a U_COLORADJUSTMENT structure.
+ \return U_COLORADJUSTMENT structure
+ \param Size Size of this structure in bytes
+ \param Flags ColorAdjustment Enumeration
+ \param IlluminantIndex Illuminant Enumeration
+ \param RedGamma Red Gamma correction (range:2500:65000, 10000 is no correction)
+ \param GreenGamma Green Gamma correction (range:2500:65000, 10000 is no correction)
+ \param BlueGamma Blue Gamma correction (range:2500:65000, 10000 is no correction)
+ \param ReferenceBlack Values less than this are black (range:0:4000)
+ \param ReferenceWhite Values more than this are white (range:6000:10000)
+ \param Contrast Contrast adjustment (range:-100:100, 0 is no correction)
+ \param Brightness Brightness adjustment (range:-100:100, 0 is no correction)
+ \param Colorfulness Colorfulness adjustment (range:-100:100, 0 is no correction)
+ \param RedGreenTint Tine adjustment (range:-100:100, 0 is no correction)
+*/
+U_COLORADJUSTMENT coloradjustment_set(
+ uint16_t Size,
+ uint16_t Flags,
+ uint16_t IlluminantIndex,
+ uint16_t RedGamma,
+ uint16_t GreenGamma,
+ uint16_t BlueGamma,
+ uint16_t ReferenceBlack,
+ uint16_t ReferenceWhite,
+ int16_t Contrast,
+ int16_t Brightness,
+ int16_t Colorfulness,
+ int16_t RedGreenTint
+ ){
+ U_COLORADJUSTMENT ca;
+ ca.caSize = Size;
+ ca.caFlags = Flags;
+ ca.caIlluminantIndex = IlluminantIndex;
+ ca.caRedGamma = U_MNMX(RedGamma, U_RGB_GAMMA_MIN, U_RGB_GAMMA_MAX);
+ ca.caGreenGamma = U_MNMX(GreenGamma, U_RGB_GAMMA_MIN, U_RGB_GAMMA_MAX);
+ ca.caBlueGamma = U_MNMX(BlueGamma, U_RGB_GAMMA_MIN, U_RGB_GAMMA_MAX);
+ // Next one is different to eliminate compiler warning - U_R_B_MIN is 0 and unsigned
+ ca.caReferenceBlack = U_MAX( ReferenceBlack, U_REFERENCE_BLACK_MAX);
+ ca.caReferenceWhite = U_MNMX(ReferenceWhite, U_REFERENCE_WHITE_MIN, U_REFERENCE_WHITE_MAX);
+ ca.caContrast = U_MNMX(Contrast, U_COLOR_ADJ_MIN, U_COLOR_ADJ_MAX);
+ ca.caBrightness = U_MNMX(Brightness, U_COLOR_ADJ_MIN, U_COLOR_ADJ_MAX);
+ ca.caColorfulness = U_MNMX(Colorfulness, U_COLOR_ADJ_MIN, U_COLOR_ADJ_MAX);
+ ca.caRedGreenTint = U_MNMX(RedGreenTint, U_COLOR_ADJ_MIN, U_COLOR_ADJ_MAX);
+ return(ca);
+}
+
+/**
+ \brief Construct a U_PIXELFORMATDESCRIPTOR structure.
+ \return U_PIXELFORMATDESCRIPTOR structure
+ \param dwFlags PFD_dwFlags Enumeration
+ \param iPixelType PFD_iPixelType Enumeration
+ \param cColorBits RGBA: total bits per pixel
+ \param cRedBits Red bits per pixel
+ \param cRedShift Red shift to data bits
+ \param cGreenBits Green bits per pixel
+ \param cGreenShift Green shift to data bits
+ \param cBlueBits Blue bits per pixel
+ \param cBlueShift Blue shift to data bits
+ \param cAlphaBits Alpha bits per pixel
+ \param cAlphaShift Alpha shift to data bits
+ \param cAccumBits Accumulator buffer, total bitplanes
+ \param cAccumRedBits Red accumulator buffer bitplanes
+ \param cAccumGreenBits Green accumulator buffer bitplanes
+ \param cAccumBlueBits Blue accumulator buffer bitplanes
+ \param cAccumAlphaBits Alpha accumulator buffer bitplanes
+ \param cDepthBits Depth of Z-buffer
+ \param cStencilBits Depth of stencil buffer
+ \param cAuxBuffers Depth of auxilliary buffers (not supported)
+ \param iLayerType PFD_iLayerType Enumeration, may be ignored
+ \param bReserved Bits 0:3/4:7 are number of Overlay/Underlay planes
+ \param dwLayerMask may be ignored
+ \param dwVisibleMask color or index of underlay plane
+ \param dwDamageMask may be ignored
+*/
+U_PIXELFORMATDESCRIPTOR pixelformatdescriptor_set(
+ uint32_t dwFlags,
+ uint8_t iPixelType,
+ uint8_t cColorBits,
+ uint8_t cRedBits,
+ uint8_t cRedShift,
+ uint8_t cGreenBits,
+ uint8_t cGreenShift,
+ uint8_t cBlueBits,
+ uint8_t cBlueShift,
+ uint8_t cAlphaBits,
+ uint8_t cAlphaShift,
+ uint8_t cAccumBits,
+ uint8_t cAccumRedBits,
+ uint8_t cAccumGreenBits,
+ uint8_t cAccumBlueBits,
+ uint8_t cAccumAlphaBits,
+ uint8_t cDepthBits,
+ uint8_t cStencilBits,
+ uint8_t cAuxBuffers,
+ uint8_t iLayerType,
+ uint8_t bReserved,
+ uint32_t dwLayerMask,
+ uint32_t dwVisibleMask,
+ uint32_t dwDamageMask
+ ){
+ U_PIXELFORMATDESCRIPTOR pfd;
+ pfd.nSize = sizeof(U_PIXELFORMATDESCRIPTOR);
+ pfd.nVersion = 1;
+ pfd.dwFlags = dwFlags;
+ pfd.iPixelType = iPixelType;
+ pfd.cColorBits = cColorBits;
+ pfd.cRedBits = cRedBits;
+ pfd.cRedShift = cRedShift;
+ pfd.cGreenBits = cGreenBits;
+ pfd.cGreenShift = cGreenShift;
+ pfd.cBlueBits = cBlueBits;
+ pfd.cBlueShift = cBlueShift;
+ pfd.cAlphaBits = cAlphaBits;
+ pfd.cAlphaShift = cAlphaShift;
+ pfd.cAccumBits = cAccumBits;
+ pfd.cAccumRedBits = cAccumRedBits;
+ pfd.cAccumGreenBits = cAccumGreenBits;
+ pfd.cAccumBlueBits = cAccumBlueBits;
+ pfd.cAccumAlphaBits = cAccumAlphaBits;
+ pfd.cDepthBits = cDepthBits;
+ pfd.cStencilBits = cStencilBits;
+ pfd.cAuxBuffers = cAuxBuffers;
+ pfd.iLayerType = iLayerType;
+ pfd.bReserved = bReserved;
+ pfd.dwLayerMask = dwLayerMask;
+ pfd.dwVisibleMask = dwVisibleMask;
+ pfd.dwDamageMask = dwDamageMask;
+ return(pfd);
+}
+
+/**
+ \brief Allocate and create a U_EMRTEXT structure followed by its variable pieces via a char* pointer.
+ Dx cannot be NULL, if the calling program has no appropriate values call dx_set() first.
+ \return char* pointer to U_EMRTEXT structure followed by its variable pieces, or NULL on error
+ \param ptlReference String start coordinates
+ \param NumString Number of characters in string, does NOT include a terminator
+ \param cbChar Number of bytes per character
+ \param String String to write
+ \param fOptions ExtTextOutOptions Enumeration
+ \param rcl (Optional, when fOptions & 7) grayed/clipping/opaque rectangle
+ \param Dx Character spacing array from the start of the RECORD
+*/
+char *emrtext_set(
+ U_POINTL ptlReference,
+ U_NUM_STR NumString,
+ uint32_t cbChar,
+ void *String,
+ uint32_t fOptions,
+ U_RECTL rcl,
+ uint32_t *Dx
+ ){
+ int irecsize,cbDxArray,cbString4,cbString,off;
+ char *record;
+ uint32_t *loffDx;
+
+ if(!String)return(NULL);
+ if(!Dx)return(NULL);
+ cbString = cbChar * NumString; // size of the string in bytes
+ cbString4 = UP4(cbString); // size of the string buffer
+ cbDxArray = sizeof(uint32_t)*NumString; // size of Dx array storage
+ if(fOptions & U_ETO_PDY)cbDxArray += cbDxArray; // of the Dx buffer, here do both X and Y coordinates
+ irecsize = sizeof(U_EMRTEXT) + sizeof(uint32_t) + cbString4 + cbDxArray; // core structure + offDx + string buf + dx buf
+ if(!(fOptions & U_ETO_NO_RECT)){ irecsize += sizeof(U_RECTL); } // plus variable U_RECTL, when it is present
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMRTEXT)record)->ptlReference = ptlReference;
+ ((PU_EMRTEXT)record)->nChars = NumString;
+ // pick up ((PU_EMRTEXT)record)->offString later
+ ((PU_EMRTEXT)record)->fOptions = fOptions;
+ off = sizeof(U_EMRTEXT); // location where variable pieces will start to be written
+ if(!(fOptions & U_ETO_NO_RECT)){ // variable field, may or may not be present
+ memcpy(record + off,&rcl, sizeof(U_RECTL));
+ off += sizeof(U_RECTL);
+ }
+ loffDx = (uint32_t *)(record + off); // offDx will go here, but we do not know with what value yet
+ off += sizeof(uint32_t);
+ memcpy(record + off,String,cbString); // copy the string data to its buffer
+ ((PU_EMRTEXT)record)->offString = off; // now save offset in the structure
+ off += cbString;
+ if(cbString < cbString4){
+ memset(record+off,0,cbString4-cbString); // keeps valgrind happy (initialize padding after string)
+ off += cbString4-cbString;
+ }
+ memcpy(record + off, Dx, cbDxArray); // copy the Dx data to its buffer
+ *loffDx = off; // now save offDx to the structure
+ }
+ return(record);
+}
+
+
+
+/* **********************************************************************************************
+These functions are simpler or more convenient ways to generate the specified types of EMR records.
+Each should be called in preference to the underlying "base" EMR function.
+*********************************************************************************************** */
+
+
+/**
+ \brief Allocate and construct a U_EMRCOMMENT structure with a UTF8 string.
+ A U_EMRCOMMENT contains application specific data, and that may include contain null characters. This function may be used when the
+ comment only incluces UT8 text.
+ \return pointer to U_EMRCOMMENT structure, or NULL on error.
+ \param string UTF8 string to store in the comment
+
+
+*/
+char *textcomment_set(
+ const char *string
+ ){
+ if(!string)return(NULL);
+ return(U_EMRCOMMENT_set(1 + strlen(string),string));
+}
+
+/**
+ \brief Allocate and construct a U_EMRDELETEOBJECT structure and also delete the requested object from the table.
+ Use this function instead of calling U_EMRDELETEOBJECT_set() directly.
+ \return pointer to U_EMRDELETEOBJECT structure, or NULL on error.
+ \param ihObject Pointer to handle to delete. This value is set to 0 if the function succeeds.
+ \param eht EMF handle table
+
+ Note that calling this function should always be conditional on the specifed object being defined. It is easy to
+ write a program where deleteobject_set() is called in a sequence where, at the time, we know that ihObject is defined.
+ Then a later modification, possibly quite far away in the code, causes it to be undefined. That distant change will
+ result in a failure when this function reutrns. That problem cannot be handled here because the only values which
+ may be returned are a valid U_EMRDELETEOBJECT record or a NULL, and other errors could result in the NULL.
+ So the object must be checked before the call.
+*/
+char *deleteobject_set(
+ uint32_t *ihObject,
+ EMFHANDLES *eht
+ ){
+ uint32_t saveObject=*ihObject;
+ if(emf_htable_delete(ihObject,eht))return(NULL); // invalid handle or other problem, cannot be deleted
+ return(U_EMRDELETEOBJECT_set(saveObject));
+}
+
+/**
+ \brief Allocate and construct a U_EMRSELECTOBJECT structure, checks that the handle specified is one that can actually be selected.
+ Use this function instead of calling U_EMRSELECTOBJECT_set() directly.
+ \return pointer to U_EMRSELECTOBJECT structure, or NULL on error.
+ \param ihObject handle to select
+ \param eht EMF handle table
+*/
+char *selectobject_set(
+ uint32_t ihObject,
+ EMFHANDLES *eht
+ ){
+ if(!(U_STOCK_OBJECT & ihObject)){ // not a stock object, those go straight through
+ if(ihObject > eht->top)return(NULL); // handle this high is not in the table
+ if(!eht->table[ihObject])return(NULL); // handle is not in the table, so not active, so cannot be selected
+ }
+ return(U_EMRSELECTOBJECT_set(ihObject));
+}
+
+/**
+ \brief Allocate and construct a U_EMREXTCREATEPEN structure, create a handle and return it.
+ Use this function instead of calling U_EMREXTCREATEPEN_set() directly.
+ \return pointer to U_EMREXTCREATEPEN structure, or NULL on error.
+ \param ihPen handle to be used by new object
+ \param eht EMF handle table
+ \param Bmi bitmapbuffer
+ \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ \param Px pixel array (NULL if cbPx == 0)
+ \param elp Pen parameters (Size is Variable!!!!)
+*/
+char *extcreatepen_set(
+ uint32_t *ihPen,
+ EMFHANDLES *eht,
+ PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ char *Px,
+ PU_EXTLOGPEN elp
+ ){
+ if(emf_htable_insert(ihPen, eht))return(NULL);
+ return(U_EMREXTCREATEPEN_set(*ihPen, Bmi, cbPx, Px, elp ));
+}
+
+/**
+ \brief Allocate and construct a U_EMRCREATEPEN structure, create a handle and returns it
+ Use this function instead of calling U_EMRCREATEPEN_set() directly.
+ \return pointer to U_EMRCREATEPEN structure, or NULL on error.
+ \param ihPen handle to be used by new object
+ \param eht EMF handle table
+ \param lopn Pen parameters
+*/
+char *createpen_set(
+ uint32_t *ihPen,
+ EMFHANDLES *eht,
+ U_LOGPEN lopn
+ ){
+ if(emf_htable_insert(ihPen, eht))return(NULL);
+ return(U_EMRCREATEPEN_set(*ihPen, lopn));
+}
+
+/**
+ \brief Allocate and construct a U_EMRCREATEBRUSHINDIRECT structure, create a handle and returns it
+ Use this function instead of calling U_EMRCREATEBRUSHINDIRECT_set() directly.
+ \return pointer to U_EMRCREATEBRUSHINDIRECT structure, or NULL on error.
+ \param ihBrush handle to be used by new object
+ \param eht EMF handle table
+ \param lb Brush parameters
+*/
+char *createbrushindirect_set(
+ uint32_t *ihBrush,
+ EMFHANDLES *eht,
+ U_LOGBRUSH lb
+ ){
+ if(emf_htable_insert(ihBrush, eht))return(NULL);
+ return(U_EMRCREATEBRUSHINDIRECT_set(*ihBrush, lb));
+}
+
+/**
+ \brief Allocate and construct a U_EMRCREATEDIBPATTERNBRUSHPT_set structure, create a handle and returns it
+ Use this function instead of calling U_EMRCREATEDIBPATTERNBRUSHPT_set() directly.
+ \return pointer to U_EMRCREATEDIBPATTERNBRUSHPT_set structure, or NULL on error.
+ \param ihBrush handle to be used by new object
+ \param eht EMF handle table
+ \param iUsage DIBColors enumeration
+ \param Bmi Bitmap info
+ \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+*/
+char *createdibpatternbrushpt_set(
+ uint32_t *ihBrush,
+ EMFHANDLES *eht,
+ const uint32_t iUsage,
+ PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ const char *Px
+
+ ){
+ if(emf_htable_insert(ihBrush, eht))return(NULL);
+ return(U_EMRCREATEDIBPATTERNBRUSHPT_set(*ihBrush, iUsage, Bmi, cbPx, Px));
+}
+
+/**
+ \brief Allocate and construct a U_EMRCREATEMONOBRUSH_set structure, create a handle and returns it
+ Use this function instead of calling U_EMRCREATEMONOBRUSH_set() directly.
+ \return pointer to U_EMRCREATEMONOBRUSH_set structure, or NULL on error.
+ \param ihBrush handle to be used by new object
+ \param eht EMF handle table
+ \param iUsage DIBColors enumeration
+ \param Bmi Bitmap info
+ \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+*/
+char *createmonobrush_set(
+ uint32_t *ihBrush,
+ EMFHANDLES *eht,
+ const uint32_t iUsage,
+ PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ const char *Px
+
+ ){
+ if(emf_htable_insert(ihBrush, eht))return(NULL);
+ return(U_EMRCREATEMONOBRUSH_set(*ihBrush, iUsage, Bmi, cbPx, Px));
+}
+
+
+/**
+ \brief Allocate and construct a U_EMRCREATECOLORSPACE structure, create a handle and returns it
+ Use this function instead of calling U_EMRCREATECOLORSPACE_set() directly.
+ \return pointer to U_EMRCREATECOLORSPACE structure, or NULL on error.
+ \param ihCS ColorSpace handle, will be created and returned
+ \param eht Pointer to structure holding all EMF handles
+ \param lcs ColorSpace parameters
+*/
+char *createcolorspace_set(
+ uint32_t *ihCS,
+ EMFHANDLES *eht,
+ U_LOGCOLORSPACEA lcs
+ ){
+ if(emf_htable_insert(ihCS, eht))return(NULL);
+ return(U_EMRCREATECOLORSPACE_set(*ihCS,lcs));
+}
+
+/**
+ \brief Allocate and construct a U_EMRCREATECOLORSPACEW structure, create a handle and returns it
+ Use this function instead of calling U_EMRCREATECOLORSPACEW_set() directly.
+ \return pointer to U_EMRCREATECOLORSPACEW structure, or NULL on error.
+ \param ihCS ColorSpace handle, will be created and returned
+ \param eht Pointer to structure holding all EMF handles
+ \param lcs ColorSpace parameters
+ \param dwFlags If low bit set Data is present
+ \param cbData Number of bytes of theData field.
+ \param Data (Optional, dwFlags & 1) color profile data
+*/
+char *createcolorspacew_set(
+ uint32_t *ihCS,
+ EMFHANDLES *eht,
+ U_LOGCOLORSPACEW lcs,
+ uint32_t dwFlags,
+ U_CBDATA cbData,
+ uint8_t *Data
+ ){
+ if(emf_htable_insert(ihCS, eht))return(NULL);
+ return(U_EMRCREATECOLORSPACEW_set(*ihCS, lcs, dwFlags, cbData, Data));
+}
+
+/**
+ \brief Allocate and construct a U_EMREXTCREATEFONTINDIRECTW structure, create a handle and returns it
+ Use this function instead of calling U_EMREXTCREATEFONTINDIRECTW_set() directly.
+ \return pointer to U_EMREXTCREATEFONTINDIRECTW structure, or NULL on error.
+ \param ihFont Font handle, will be created and returned
+ \param eht Pointer to structure holding all EMF handles
+ \param elf Pointer to Font parameters asPU_LOGFONT
+ \param elfw Pointer to Font parameters as U_LOGFONT_PANOSE
+*/
+char *extcreatefontindirectw_set(
+ uint32_t *ihFont,
+ EMFHANDLES *eht,
+ const char *elf,
+ const char *elfw
+ ){
+ if(emf_htable_insert(ihFont, eht))return(NULL);
+ return(U_EMREXTCREATEFONTINDIRECTW_set(*ihFont, elf, elfw));
+}
+
+/**
+ \brief Allocate and construct a U_EMRCREATEPALETTE structure, create a handle and returns it
+ Use this function instead of calling U_EMRCREATEPALETTE_set() directly.
+ \return pointer to U_EMRCREATEPALETTE structure, or NULL on error.
+ \param ihPal Palette handle, will be created and returned
+ \param eht Pointer to structure holding all EMF handles
+ \param lgpl PaletteFont parameters
+*/
+char *createpalette_set(
+ uint32_t *ihPal,
+ EMFHANDLES *eht,
+ U_LOGPALETTE lgpl
+ ){
+ if(emf_htable_insert(ihPal, eht))return(NULL);
+ return(U_EMRCREATEPALETTE_set(*ihPal, lgpl));
+}
+
+/**
+ \brief Allocate and construct a U_EMRSETPALETTEENTRIES structure, create a handle and returns it
+ Use this function instead of calling U_EMRSETPALETTEENTRIES_set() directly.
+ \return pointer to U_EMRSETPALETTEENTRIES structure, or NULL on error.
+ \param ihPal Palette handle, will be created and returned
+ \param eht Pointer to structure holding all EMF handles
+ \param iStart First Palette entry in selected object to set
+ \param cEntries Number of Palette entries in selected object to set
+ \param aPalEntries Values to set with
+*/
+char *setpaletteentries_set(
+ uint32_t *ihPal,
+ EMFHANDLES *eht,
+ const uint32_t iStart,
+ const U_NUM_LOGPLTNTRY cEntries,
+ const PU_LOGPLTNTRY aPalEntries
+ ){
+ if(emf_htable_insert(ihPal, eht))return(NULL);
+ return(U_EMRSETPALETTEENTRIES_set(*ihPal, iStart, cEntries, aPalEntries));
+}
+
+/**
+ \brief Allocate and construct a U_EMRFILLRGN structure, create a handle and returns it
+ Use this function instead of calling U_EMRFILLRGN_set() directly.
+ \return pointer to U_EMRFILLRGN structure, or NULL on error.
+ \param ihBrush Brush handle, will be created and returned
+ \param eht Pointer to structure holding all EMF handles
+ \param rclBounds Bounding rectangle in device units
+ \param RgnData Pointer to a U_RGNDATA structure
+*/
+char *fillrgn_set(
+ uint32_t *ihBrush,
+ EMFHANDLES *eht,
+ const U_RECTL rclBounds,
+ const PU_RGNDATA RgnData
+ ){
+ if(emf_htable_insert(ihBrush, eht))return(NULL);
+ return(U_EMRFILLRGN_set(rclBounds, *ihBrush, RgnData));
+}
+
+/**
+ \brief Allocate and construct a U_EMRFRAMERGN structure, create a handle and returns it
+ Use this function instead of calling U_EMRFRAMERGN_set() directly.
+ \return pointer to U_EMRFRAMERGN structure, or NULL on error.
+ \param ihBrush Brush handle, will be created and returned
+ \param eht Pointer to structure holding all EMF handles
+ \param rclBounds Bounding rectangle in device units
+ \param szlStroke W & H of Brush stroke
+ \param RgnData Pointer to a U_RGNDATA structure
+*/
+char *framergn_set(
+ uint32_t *ihBrush,
+ EMFHANDLES *eht,
+ const U_RECTL rclBounds,
+ const U_SIZEL szlStroke,
+ const PU_RGNDATA RgnData
+ ){
+ if(emf_htable_insert(ihBrush, eht))return(NULL);
+ return(U_EMRFRAMERGN_set(rclBounds, *ihBrush, szlStroke, RgnData));
+}
+
+/**
+ \brief Allocate and construct an array of U_POINT objects which has been subjected to a U_XFORM
+ \returns pointer to an array of U_POINT structures.
+ \param points pointer to the source U_POINT structures
+ \param count number of members in points
+ \param xform U_XFORM to apply
+
+ May also be used to modify U_RECT by doubling the count and casting the pointer.
+*/
+PU_POINT points_transform(PU_POINT points, int count, U_XFORM xform){
+ PU_POINT newpts;
+ int i;
+ float x,y;
+ newpts = (PU_POINT) malloc(count * sizeof(U_POINT));
+ for(i=0; i<count; i++){
+ x = (float) points[i].x;
+ y = (float) 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_POINT16 objects which has been subjected to a U_XFORM
+ \returns pointer to an array of U_POINT16 structures.
+ \param points pointer to the source U_POINT16 structures
+ \param count number of members in points
+ \param xform U_XFORM to apply
+
+ Transformed src points {x0,y0} appear at {x0*xscale + x, y0*yscale + y}
+*/
+PU_POINT16 point16_transform(PU_POINT16 points, int count, U_XFORM xform){
+ PU_POINT16 newpts;
+ int i;
+ float x,y;
+ newpts = (PU_POINT16) malloc(count * sizeof(U_POINT16));
+ for(i=0; i<count; i++){
+ x = (float) points[i].x;
+ y = (float) 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_TRIVERTEX objects which has been subjected to a U_XFORM
+ \returns pointer to an array of U_TRIVERTEX structures.
+ \param tv pointer to the source U_TRIVERTEX structures
+ \param count number of members in points
+ \param xform U_XFORM to apply
+
+ Transformed Trivertex points {x0,y0} appear at {x0*xscale + x, y0*yscale + y}
+*/
+PU_TRIVERTEX trivertex_transform(PU_TRIVERTEX tv, int count, U_XFORM xform){
+ PU_TRIVERTEX newtvs;
+ int i;
+ float x,y;
+ newtvs = (PU_TRIVERTEX) malloc(count * sizeof(U_TRIVERTEX));
+ for(i=0; i<count; i++){
+ x = (float) tv[i].x;
+ y = (float) tv[i].y;
+ newtvs[i] = tv[i];
+ newtvs[i].x = U_ROUND(x * xform.eM11 + y * xform.eM21 + xform.eDx);
+ newtvs[i].y = U_ROUND(x * xform.eM12 + y * xform.eM22 + xform.eDy);
+ }
+ return(newtvs);
+}
+
+/**
+ \brief Allocate and construct an array of U_POINT objects from a set of U_POINT16 objects
+ \returns pointer to an array of U_POINT structures.
+ \param points pointer to the source U_POINT16 structures
+ \param count number of members in points
+
+*/
+PU_POINT point16_to_point(PU_POINT16 points, int count){
+ PU_POINT newpts;
+ int i;
+ newpts = (PU_POINT) malloc(count * sizeof(U_POINT));
+ for(i=0; i<count; i++){
+ newpts[i].x = points[i].x;
+ newpts[i].y = points[i].y;
+ }
+ return(newpts);
+}
+
+/**
+ \brief Allocate and construct an array of U_POINT16 objects from a set of U_POINT objects
+ \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.
+*/
+PU_POINT16 point_to_point16(PU_POINT points, int count){
+ PU_POINT16 newpts;
+ int i;
+ newpts = (PU_POINT16) malloc(count * sizeof(U_POINT16));
+ for(i=0; i<count; i++){
+ newpts[i].x = U_MNMX(points[i].x, INT16_MIN, INT16_MAX);
+ newpts[i].y = U_MNMX(points[i].y, INT16_MIN, INT16_MAX);
+ }
+ return(newpts);
+}
+
+// hide these from Doxygen
+//! @cond
+/* **********************************************************************************************
+These functions contain shared code used by various U_EMR*_set functions. These should NEVER be called
+by end user code and to further that end prototypes are NOT provided and they are hidden from Doxygen.
+
+
+ These are (mostly) ordered by U_EMR_* index number.
+ For all _set functions the caller must eventually call free() on the returned pointer.
+
+ CORE1(uint32_t iType, U_RECTL rclBounds, const uint32_t cptl, const U_POINTL *points){
+ CORE2(uint32_t iType, U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts,const uint32_t cptl, const U_POINTL *points){
+ CORE3(uint32_t iType, uint32_t iMode){ (generic 1 uint)
+ CORE4(uint32_t iType, U_RECTL rclBox){
+ CORE5(uint32_t iType){ (generic noargs)
+ CORE6(uint32_t iType, U_RECTL rclBounds, const uint32_t cpts, const U_POINT16 *points){ (16bit form of CORE1)
+ CORE7(uint32_t iType, U_PAIR pair){
+ CORE8(uint32_t iType, U_RECTL rclBounds, uint32_t iGraphicsMode, U_FLOAT exScale, U_FLOAT eyScale, PU_EMRTEXT emrtext){
+ CORE9(uint32_t iType, U_RECTL rclBox, U_POINTL ptlStart, U_POINTL ptlEnd){
+ CORE10(uint32_t iType, U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts,const uint32_t cpts, const U_POINT16 *points){ (16bit form of CORE2)
+ CORE11(uint32_t iType, PU_RGNDATA RgnData){
+ CORE12(uint32_t iType, uint32_t ihBrush, uint32_t iUsage, PU_BITMAPINFO Bmi){
+ CORE13(uint32_t iType, U_RECTL rclBounds, U_POINTL Dest, U_POINTL cDest,
+ U_POINTL Src, U_POINTL cSrc, U_XFORM xformSrc, U_COLORREF crBkColorSrc, uint32_t iUsageSrc,
+ uint32_t Data, PU_BITMAPINFO Bmi);
+*********************************************************************************************** */
+
+
+// Functions with the same form starting with U_EMRPOLYBEZIER_set
+char *U_EMR_CORE1_set(uint32_t iType, U_RECTL rclBounds, const uint32_t cptl, const U_POINTL *points){
+ char *record;
+ int cbPoints;
+ int irecsize;
+
+ cbPoints = sizeof(U_POINTL)*cptl;
+ irecsize = sizeof(U_EMRPOLYBEZIER) + cbPoints - sizeof(U_POINTL); // First instance is in struct
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = iType;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRPOLYBEZIER) record)->rclBounds = rclBounds;
+ ((PU_EMRPOLYBEZIER) record)->cptl = cptl;
+ memcpy(((PU_EMRPOLYBEZIER) record)->aptl,points,cbPoints);
+ }
+ return(record);
+}
+
+// Functions with the same form starting with U_EMR_POLYPOLYLINE
+char *U_EMR_CORE2_set(uint32_t iType, U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts,const uint32_t cptl, const U_POINTL *points){
+ char *record;
+ int cbPolys,cbPoints,off;
+ int irecsize;
+
+ cbPoints = sizeof(U_POINTL)*cptl;
+ cbPolys = sizeof(uint32_t)*nPolys;
+ irecsize = sizeof(U_EMRPOLYPOLYLINE) + cbPoints + cbPolys - sizeof(uint32_t); // First instance of each is in struct
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = iType;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRPOLYPOLYLINE) record)->rclBounds = rclBounds;
+ ((PU_EMRPOLYPOLYLINE) record)->nPolys = nPolys;
+ ((PU_EMRPOLYPOLYLINE) record)->cptl = cptl;
+ memcpy(((PU_EMRPOLYPOLYLINE) record)->aPolyCounts,aPolyCounts,cbPolys);
+ off = sizeof(U_EMRPOLYPOLYLINE) - 4 + cbPolys;
+ memcpy(record + off,points,cbPoints);
+ }
+ return(record);
+}
+
+// Functions with the same form starting with U_EMR_SETMAPMODE_set
+char *U_EMR_CORE3_set(uint32_t iType, uint32_t iMode){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRSETMAPMODE);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = iType;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRSETMAPMODE)record)->iMode = iMode;
+ }
+ return(record);
+}
+
+// Functions taking a single U_RECT or U_RECTL, starting with U_EMRELLIPSE_set, also U_EMRFILLPATH,
+char *U_EMR_CORE4_set(uint32_t iType, U_RECTL rclBox){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRELLIPSE);
+ record = malloc(irecsize);
+ memset(record,0,irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = iType;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRELLIPSE)record)->rclBox = rclBox; // bounding rectangle in logical units
+ }
+ return(record);
+}
+
+// Functions with the same form starting with U_EMRSETMETARGN_set
+char *U_EMR_CORE5_set(uint32_t iType){
+ char *record;
+ int irecsize = 8;
+
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = iType;
+ ((PU_EMR) record)->nSize = irecsize;
+ }
+ return(record);
+}
+
+// Functions with the same form starting with U_EMRPOLYBEZIER16_set
+char *U_EMR_CORE6_set(uint32_t iType, U_RECTL rclBounds, const uint32_t cpts, const U_POINT16 *points){
+ char *record;
+ int cbPoints,cbPoints4,off;
+ int irecsize;
+
+ cbPoints = sizeof(U_POINT16)*cpts;
+ cbPoints4 = UP4(cbPoints);
+ off = sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(U_NUM_POINT16); // offset to the start of the variable region
+ irecsize = off + cbPoints4; // First instance is in struct
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = iType;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRPOLYBEZIER16) record)->rclBounds = rclBounds;
+ ((PU_EMRPOLYBEZIER16) record)->cpts = cpts;
+ memcpy(record + off, points, cbPoints);
+ if(cbPoints < cbPoints4){
+ off += cbPoints;
+ memset(record + off, 0, cbPoints4 - cbPoints);
+ }
+ }
+ return(record);
+}
+
+
+// Functions that take a single struct argument which contains two uint32_t, starting with U_EMRSETWINDOWEXTEX_set
+// these all pass two 32 bit ints and are cast by the caller to U_PAIR
+char *U_EMR_CORE7_set(uint32_t iType, U_PAIR pair){
+ char *record;
+ int irecsize = sizeof(U_EMRGENERICPAIR);
+
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = iType;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRGENERICPAIR)record)->pair = pair;
+ }
+ return(record);
+}
+
+// For U_EMREXTTEXTOUTA and U_EMREXTTEXTOUTW
+char *U_EMR_CORE8_set(
+ uint32_t iType,
+ U_RECTL rclBounds, // Bounding rectangle in device units
+ uint32_t iGraphicsMode, // Graphics mode Enumeration
+ U_FLOAT exScale, // scale to 0.01 mm units ( only if iGraphicsMode & GM_COMPATIBLE)
+ U_FLOAT eyScale, // scale to 0.01 mm units ( only if iGraphicsMode & GM_COMPATIBLE)
+ PU_EMRTEXT emrtext // Text parameters
+ ){
+ char *record;
+ int irecsize,cbString,cbString4,cbDx,cbEmrtext,cbEmrtextAll;
+ uint32_t *loffDx;
+ int csize;
+
+ if( iType == U_EMR_EXTTEXTOUTA){ csize = 1; } // how many bytes per character
+ else if(iType == U_EMR_EXTTEXTOUTW){ csize = 2; }
+ else { return(NULL); }
+
+ cbString = csize * emrtext->nChars;
+ cbString4 = UP4(cbString); // size of the string buffer
+ cbEmrtext = sizeof(U_EMRTEXT); // size of the constant part of the U_EMRTEXT structure
+ if(!(emrtext->fOptions & U_ETO_NO_RECT)){ cbEmrtext += sizeof(U_RECTL); } // plus the variable U_RECTL, when it is present
+ cbDx = emrtext->nChars * sizeof(int32_t); // size of Dx buffer
+ if(emrtext->fOptions & U_ETO_PDY)cbDx += cbDx; // size of Dx buffer when both x and y offsets are used
+ cbEmrtextAll = cbEmrtext + sizeof(uint32_t) + cbString4 + cbDx; // structure (+- rect) + offDx + string buf + dx buf + offDx
+
+ /* adjust offset fields in emrtext to match the EMRTEXTOUT* field, currently they match EMRTEXT.
+ This works because the variable pieces have all been moved outside of the U_EMRTEXT and U_EMRTEXTOUTA strutures.
+ */
+ ((PU_EMRTEXT)emrtext)->offString += sizeof(U_EMREXTTEXTOUTA) - sizeof(U_EMRTEXT); // adjust offString
+ loffDx = (uint32_t *)((char *)emrtext + cbEmrtext);
+ *loffDx += sizeof(U_EMREXTTEXTOUTA) - sizeof(U_EMRTEXT);
+
+ // final record size is: U_EMREXTTEXTOUTA (includes constant part of U_EMRTEXT) + U_RECTL (if present) + offDx + dx buffer + string buffer
+ irecsize = sizeof(U_EMREXTTEXTOUTA) + cbEmrtextAll - sizeof(U_EMRTEXT); // do not count core emrtext strcture twice
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = iType;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMREXTTEXTOUTA) record)->iGraphicsMode = iGraphicsMode;
+ ((PU_EMREXTTEXTOUTA) record)->rclBounds = rclBounds;
+ ((PU_EMREXTTEXTOUTA) record)->exScale = exScale;
+ ((PU_EMREXTTEXTOUTA) record)->eyScale = eyScale;
+ // copy the adjusted U_EMRTEXT into the emrtext part of the full record..
+ memcpy(&(((PU_EMREXTTEXTOUTA) record)->emrtext), emrtext, cbEmrtextAll);
+ }
+ return(record);
+}
+
+// Functions that take a rect and a pair of points, starting with U_EMRARC_set
+char *U_EMR_CORE9_set(uint32_t iType, U_RECTL rclBox, U_POINTL ptlStart, U_POINTL ptlEnd){
+ char *record;
+ int irecsize = sizeof(U_EMRARC);
+
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = iType;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRARC) record)->rclBox = rclBox;
+ ((PU_EMRARC) record)->ptlStart = ptlStart;
+ ((PU_EMRARC) record)->ptlEnd = ptlEnd;
+ }
+ return(record);
+}
+
+// Functions with the same form starting with U_EMR_POLYPOLYLINE16
+char *U_EMR_CORE10_set(uint32_t iType, U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts,const uint32_t cpts, const U_POINT16 *points){
+ char *record;
+ int cbPoints,cbPolys,off;
+ int irecsize;
+
+ cbPolys = sizeof(uint32_t)*nPolys;
+ cbPoints = sizeof(U_POINT16)*cpts;
+ irecsize = sizeof(U_EMRPOLYPOLYLINE16) + cbPoints + cbPolys - sizeof(uint32_t); // First instance of each is in struct
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = iType;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRPOLYPOLYLINE16) record)->rclBounds = rclBounds;
+ ((PU_EMRPOLYPOLYLINE16) record)->nPolys = nPolys;
+ ((PU_EMRPOLYPOLYLINE16) record)->cpts = cpts;
+ memcpy(((PU_EMRPOLYPOLYLINE16) record)->aPolyCounts,aPolyCounts,cbPolys);
+ off = sizeof(U_EMRPOLYPOLYLINE16) - 4 + cbPolys;
+ memcpy(record + off,points,cbPoints);
+ }
+ return(record);
+}
+
+// common code for U_EMRINVERTRGN and U_EMRPAINTRGN,
+char *U_EMR_CORE11_set(uint32_t iType, PU_RGNDATA RgnData){
+ char *record;
+ int irecsize;
+ int cbRgns,cbRgns4,rds,rds4,off;
+
+ if(!RgnData)return(NULL);
+ cbRgns = ((PU_RGNDATAHEADER) RgnData)->nRgnSize;
+ cbRgns4 = UP4(cbRgns);
+ rds = sizeof(U_RGNDATAHEADER) + cbRgns;
+ rds4 = UP4(rds);
+ irecsize = sizeof(U_EMRINVERTRGN) - sizeof(U_RECTL) + cbRgns4; // core + array - overlap of one rectL
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = iType;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRINVERTRGN) record)->rclBounds = ((PU_RGNDATAHEADER) RgnData)->rclBounds;
+ ((PU_EMRINVERTRGN) record)->cbRgnData = rds;
+ off = sizeof(U_EMRINVERTRGN) - sizeof(U_RGNDATA);
+ memcpy(record + off, RgnData, rds);
+ off += rds;
+ if(rds < rds4){ memset(record + off,0, rds4 - rds); } // clear any unused bytes
+ }
+ return(record);
+}
+
+
+// common code for U_EMRCREATEMONOBRUSH_set and U_EMRCREATEDIBPATTERNBRUSHPT_set,
+char *U_EMR_CORE12_set(
+ uint32_t iType,
+ uint32_t ihBrush, // Index to place object in EMF object table (this entry must not yet exist)
+ uint32_t iUsage, // DIBcolors Enumeration
+ PU_BITMAPINFO Bmi, // (Optional) bitmapbuffer (U_BITMAPINFO + pixel array)
+ const uint32_t cbPx, // Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ const char *Px // (Optional) bitmapbuffer (pixel array section )
+ ){
+ char *record;
+ int irecsize;
+ int cbImage,cbImage4,cbBmi,off;
+
+ SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
+
+ irecsize = sizeof(U_EMRCREATEMONOBRUSH) + cbBmi + cbImage4;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = iType;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRCREATEMONOBRUSH) record)->ihBrush = ihBrush;
+ ((PU_EMRCREATEMONOBRUSH) record)->iUsage = iUsage;
+ if(cbBmi){
+ off = sizeof(U_EMRCREATEMONOBRUSH);
+ memcpy(record + off, Bmi, cbBmi);
+ ((PU_EMRCREATEMONOBRUSH) record)->offBmi = off;
+ ((PU_EMRCREATEMONOBRUSH) record)->cbBmi = cbBmi;
+ off += cbBmi;
+ memcpy(record + off, Px, cbPx);
+ ((PU_EMRCREATEMONOBRUSH) record)->offBits = off;
+ ((PU_EMRCREATEMONOBRUSH) record)->cbBits = cbImage;
+ }
+ else {
+ ((PU_EMRCREATEMONOBRUSH) record)->offBmi = 0;
+ ((PU_EMRCREATEMONOBRUSH) record)->cbBmi = 0;
+ ((PU_EMRCREATEMONOBRUSH) record)->offBits = 0;
+ ((PU_EMRCREATEMONOBRUSH) record)->cbBits = 0;
+ }
+ }
+ return(record);
+}
+
+// common code for U_EMRBLEND_set and U_EMRTRANSPARENTBLT_set,
+char *U_EMR_CORE13_set(
+ uint32_t iType,
+ U_RECTL rclBounds, // Bounding rectangle in device units
+ U_POINTL Dest, // Destination UL corner in logical units
+ U_POINTL cDest, // Destination width in logical units
+ U_POINTL Src, // Source UL corner in logical units
+ U_POINTL cSrc, // Src W & H in logical units
+ U_XFORM xformSrc, // Transform to apply to source
+ U_COLORREF crBkColorSrc, // Background color
+ uint32_t iUsageSrc, // DIBcolors Enumeration
+ uint32_t Data, // The meaning and type of this field varies, but it is always 4 bytes
+ const PU_BITMAPINFO Bmi, // (Optional) bitmapbuffer (U_BITMAPINFO section)
+ const uint32_t cbPx, // Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ char *Px // (Optional) bitmapbuffer (pixel array section )
+ ){
+ char *record;
+ int irecsize;
+ int cbImage,cbImage4,cbBmi,off;
+
+ SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
+
+ irecsize = sizeof(U_EMRALPHABLEND) + cbBmi + cbImage4;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = iType;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRALPHABLEND) record)->rclBounds = rclBounds;
+ ((PU_EMRALPHABLEND) record)->Dest = Dest;
+ ((PU_EMRALPHABLEND) record)->cDest = cDest;
+ ((PU_EMRALPHABLEND) record)->Blend = *((PU_BLEND)&Data);
+ ((PU_EMRALPHABLEND) record)->Src = Src;
+ ((PU_EMRALPHABLEND) record)->xformSrc = xformSrc;
+ ((PU_EMRALPHABLEND) record)->crBkColorSrc = crBkColorSrc;
+ ((PU_EMRALPHABLEND) record)->iUsageSrc = iUsageSrc;
+ off = sizeof(U_EMRALPHABLEND);
+ APPEND_PXBMISRC(record, U_EMRALPHABLEND, cbBmi, Bmi, Px, cbImage, cbImage4);
+ ((PU_EMRALPHABLEND) record)->cSrc = cSrc;
+ }
+ return(record);
+}
+//! @endcond
+
+/* **********************************************************************************************
+These are the core EMR functions, each creates a particular type of record.
+All return these records via a char* pointer, which is NULL if the call failed.
+They are listed in order by the corresponding U_EMR_* index number.
+*********************************************************************************************** */
+
+// U_EMRHEADER_set 1
+
+/**
+ \brief Allocate and construct a U_EMRHEADER record.
+ \return pointer to U_EMRHEADER record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param rclFrame Bounding rectangle in 0.01 mm units
+ \param pfmtDesc Pointer to a PixelFormatDescriptor
+ \param nDesc number of characters in Description, will include first three '\0'
+ \param Description Description, formatted like: text1\0text2\0\0
+ \param szlDevice Reference device size in pixels
+ \param szlMillimeters Reference device size in 0.01 mm
+ \param bOpenGL nonZero if OpenGL commands are included
+*/
+char *U_EMRHEADER_set(
+ const U_RECTL rclBounds,
+ const U_RECTL rclFrame,
+ U_PIXELFORMATDESCRIPTOR* const pfmtDesc,
+ U_CBSTR nDesc,
+ uint16_t* const Description,
+ const U_SIZEL szlDevice,
+ const U_SIZEL szlMillimeters,
+ const uint32_t bOpenGL
+ ){
+
+ char *record;
+ int cbPFD,cbDesc,cbDesc4;
+ uint32_t off;
+ int irecsize;
+
+ if(pfmtDesc){ cbPFD = sizeof(U_PIXELFORMATDESCRIPTOR); }
+ else { cbPFD = 0; }
+ if(Description){ cbDesc = 2*nDesc; } // also copy the terminator. Size is in bytes
+ else { cbDesc = 0; }
+ cbDesc4 = UP4(cbDesc);
+ irecsize = sizeof(U_EMRHEADER) + cbPFD + cbDesc4;
+ record = malloc(irecsize);
+ if(record){
+ off = sizeof(U_EMRHEADER);
+ ((PU_EMR) record)->iType = U_EMR_HEADER;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRHEADER) record)->rclBounds = rclBounds;
+ ((PU_EMRHEADER) record)->rclFrame = rclFrame;
+ ((PU_EMRHEADER) record)->dSignature = U_ENHMETA_SIGNATURE;
+ ((PU_EMRHEADER) record)->nVersion = U_ENHMETA_VERSION;
+ ((PU_EMRHEADER) record)->nBytes = 0; // Not known yet
+ ((PU_EMRHEADER) record)->nRecords = 0; // Not known yet
+ ((PU_EMRHEADER) record)->nHandles = 0; // Not known yet
+ ((PU_EMRHEADER) record)->sReserved = 0; // Must be 0
+ ((PU_EMRHEADER) record)->nDescription = nDesc;
+ ((PU_EMRHEADER) record)->offDescription = 0; // may change below
+ ((PU_EMRHEADER) record)->nPalEntries = 0; // Not known yet
+ ((PU_EMRHEADER) record)->szlDevice = szlDevice;
+ ((PU_EMRHEADER) record)->szlMillimeters = szlMillimeters;
+ ((PU_EMRHEADER) record)->cbPixelFormat = cbPFD;
+ ((PU_EMRHEADER) record)->offPixelFormat = 0; // may change below
+ ((PU_EMRHEADER) record)->bOpenGL = bOpenGL;
+ ((PU_EMRHEADER) record)->szlMicrometers.cx = szlMillimeters.cx*1000;
+ ((PU_EMRHEADER) record)->szlMicrometers.cy = szlMillimeters.cy*1000;
+ if(cbDesc4){
+ ((PU_EMRHEADER) record)->offDescription = off;
+ memcpy(record + off, Description, cbDesc);
+ off += cbDesc;
+ if(cbDesc < cbDesc4)memset(record + off,0,cbDesc4-cbDesc); // clear any unused bytes
+ off += cbDesc4 - cbDesc;
+ }
+ if(cbPFD){
+ ((PU_EMRHEADER) record)->offPixelFormat = off;
+ memcpy(record+off,pfmtDesc,cbPFD);
+ }
+ }
+ return(record);
+}
+
+// U_EMRPOLYBEZIER_set 2
+/**
+ \brief Allocate and construct a U_EMR_POLYBEZIER record.
+ \return pointer to U_EMR_POLYBEZIER record, or NULL on error.
+ \param rclBounds bounding rectangle in device units
+ \param cptl Number of points to draw
+ \param points array of points
+*/
+char *U_EMRPOLYBEZIER_set(
+ const U_RECTL rclBounds,
+ const uint32_t cptl,
+ const U_POINTL *points
+ ){
+ return(U_EMR_CORE1_set(U_EMR_POLYBEZIER, rclBounds, cptl, points));
+}
+
+// U_EMRPOLYGON_set 3
+/**
+ \brief Allocate and construct a U_EMR_POLYGON record.
+ \return pointer to U_EMR_POLYGON record, or NULL on error.
+ \param rclBounds bounding rectangle in device units
+ \param cptl Number of points to draw
+ \param points array of points
+*/
+char *U_EMRPOLYGON_set(
+ const U_RECTL rclBounds,
+ const uint32_t cptl,
+ const U_POINTL *points
+ ){
+ return(U_EMR_CORE1_set(U_EMR_POLYGON, rclBounds, cptl, points));
+}
+
+// U_EMRPOLYLINE_set 4
+/**
+ \brief Allocate and construct a U_EMR_POLYLINE record.
+ \return pointer to U_EMR_POLYLINE record, or NULL on error.
+ \param rclBounds bounding rectangle in device units
+ \param cptl Number of points to draw
+ \param points array of points
+*/
+char *U_EMRPOLYLINE_set(
+ const U_RECTL rclBounds,
+ const uint32_t cptl,
+ const U_POINTL *points
+ ){
+ return(U_EMR_CORE1_set(U_EMR_POLYLINE, rclBounds, cptl, points));
+}
+
+// U_EMRPOLYBEZIERTO_set 5
+/**
+ \brief Allocate and construct a U_EMR_POLYBEZIERTO record.
+ \return pointer to U_EMR_POLYBEZIERTO record, or NULL on error.
+ \param rclBounds bounding rectangle in device units
+ \param cptl Number of points to draw
+ \param points array of points
+*/
+char *U_EMRPOLYBEZIERTO_set(
+ const U_RECTL rclBounds,
+ const uint32_t cptl,
+ const U_POINTL *points
+ ){
+ return(U_EMR_CORE1_set(U_EMR_POLYBEZIERTO, rclBounds, cptl, points));
+}
+
+// U_EMRPOLYLINETO_set 6
+/**
+ \brief Allocate and construct a U_EMR_POLYLINETO record.
+ \return pointer to U_EMR_POLYLINETO record, or NULL on error.
+ \param rclBounds bounding rectangle in device units
+ \param cptl Number of points to draw
+ \param points array of points
+*/
+char *U_EMRPOLYLINETO_set(
+ const U_RECTL rclBounds,
+ const uint32_t cptl,
+ const U_POINTL *points
+ ){
+ return(U_EMR_CORE1_set(U_EMR_POLYLINETO, rclBounds, cptl, points));
+}
+
+// U_EMRPOLYPOLYLINE_set 7
+/**
+ \brief Allocate and construct a U_EMR_POLYPOLYLINE record.
+ \return pointer to U_EMR_POLYPOLYLINE record, or NULL on error.
+ \param rclBounds bounding rectangle in device units
+ \param nPolys Number of elements in aPolyCounts
+ \param aPolyCounts Number of points in each poly (sequential)
+ \param cptl Total number of points (over all poly)
+ \param points array of points
+*/
+char *U_EMRPOLYPOLYLINE_set(
+ const U_RECTL rclBounds,
+ const uint32_t nPolys,
+ const uint32_t *aPolyCounts,
+ const uint32_t cptl,
+ const U_POINTL *points
+ ){
+ return(U_EMR_CORE2_set(U_EMR_POLYPOLYLINE, rclBounds, nPolys, aPolyCounts,cptl, points));
+}
+
+// U_EMRPOLYPOLYGON_set 8
+/**
+ \brief Allocate and construct a U_EMR_POLYPOLYGON record.
+ \return pointer to U_EMR_POLYPOLYGON record, or NULL on error.
+ \param rclBounds bounding rectangle in device units
+ \param nPolys Number of elements in aPolyCounts
+ \param aPolyCounts Number of points in each poly (sequential)
+ \param cptl Total number of points (over all poly)
+ \param points array of points
+*/
+char *U_EMRPOLYPOLYGON_set(
+ const U_RECTL rclBounds,
+ const uint32_t nPolys,
+ const uint32_t *aPolyCounts,
+ const uint32_t cptl,
+ const U_POINTL *points
+ ){
+ return(U_EMR_CORE2_set(U_EMR_POLYPOLYGON, rclBounds, nPolys, aPolyCounts,cptl, points));
+}
+
+// U_EMRSETWINDOWEXTEX_set 9
+/**
+ \brief Allocate and construct a U_EMR_SETWINDOWEXTEX record.
+ \return pointer to U_EMR_SETWINDOWEXTEX record, or NULL on error.
+ \param szlExtent H & V extent in logical units
+*/
+char *U_EMRSETWINDOWEXTEX_set(
+ const U_SIZEL szlExtent
+ ){
+ U_PAIR temp;
+ temp.x = szlExtent.cx;
+ temp.y = szlExtent.cy;
+ return(U_EMR_CORE7_set(U_EMR_SETWINDOWEXTEX, temp));
+}
+
+// U_EMRSETWINDOWORGEX_set 10
+/**
+ \brief Allocate and construct a U_EMR_SETWINDOWORGEX record.
+ \return pointer to U_EMR_SETWINDOWORGEX record, or NULL on error.
+ \param ptlOrigin H & V origin in logical units
+*/
+char *U_EMRSETWINDOWORGEX_set(
+ const U_POINTL ptlOrigin
+ ){
+ return(U_EMR_CORE7_set(U_EMR_SETWINDOWORGEX, ptlOrigin)); // U_PAIR and U_POINTL are the same thing
+}
+
+// U_EMRSETVIEWPORTEXTEX_set 11
+/**
+ \brief Allocate and construct a U_EMR_SETVIEWPORTEXTEX record.
+ \return pointer to U_EMR_SETVIEWPORTEXTEX record, or NULL on error.
+ \param szlExtent H & V extent in logical units
+*/
+char *U_EMRSETVIEWPORTEXTEX_set(
+ const U_SIZEL szlExtent
+ ){
+ U_PAIR temp;
+ temp.x = szlExtent.cx;
+ temp.y = szlExtent.cy;
+ return(U_EMR_CORE7_set(U_EMR_SETVIEWPORTEXTEX, temp));
+}
+
+// U_EMRSETVIEWPORTORGEX_set 12
+/**
+ \brief Allocate and construct a U_EMR_SETVIEWPORTORGEX record.
+ \return pointer to U_EMR_SETVIEWPORTORGEX record, or NULL on error.
+ \param ptlOrigin H & V origin in logical units
+*/
+char *U_EMRSETVIEWPORTORGEX_set(
+ const U_POINTL ptlOrigin
+ ){
+ return(U_EMR_CORE7_set(U_EMR_SETVIEWPORTORGEX, ptlOrigin)); // U_PAIR and U_POINTL are the same thing
+}
+
+// U_EMRSETBRUSHORGEX_set 13
+/**
+ \brief Allocate and construct a U_EMR_SETBRUSHORGEX record.
+ \return pointer to U_EMR_SETBRUSHORGEX record, or NULL on error.
+ \param ptlOrigin H & V origin in logical units
+*/
+char *U_EMRSETBRUSHORGEX_set(
+ const U_POINTL ptlOrigin
+ ){
+ return(U_EMR_CORE7_set(U_EMR_SETBRUSHORGEX, *((PU_PAIR) & ptlOrigin)));
+}
+
+// U_EMREOF_set 14
+/**
+ \brief Allocate and construct a U_EMR_EOF record.
+ \return pointer to U_EMR_EOF record, or NULL on error.
+ \param cbPalEntries Number of palette entries
+ \param PalEntries (optional) array of PalEntries
+ \param et tracking information, needed for nSizeLast calculation
+*/
+char *U_EMREOF_set(
+ const U_CBPLENTRIES cbPalEntries,
+ const PU_LOGPLTNTRY PalEntries,
+ EMFTRACK *et
+ ){
+ char *record;
+ char *ptr;
+ int irecsize;
+ int cbPals; // space allocated for Palette Entries
+ uint32_t off;
+
+ if(cbPalEntries && !PalEntries)return(NULL);
+ if(!et)return(NULL);
+ cbPals = cbPalEntries * sizeof(U_LOGPLTNTRY);
+ irecsize = sizeof(U_EMREOF) + cbPals + sizeof(uint32_t); //invariant core, variable palette, palette byte count
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_EOF;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMREOF) record)->cbPalEntries = cbPalEntries;
+ ((PU_EMREOF) record)->offPalEntries = 0; // May be changed below
+ off = sizeof(U_EMREOF); //start of the variable region
+ if(cbPals){
+ ((PU_EMREOF) record)->offPalEntries = off;
+ memcpy(record+off,PalEntries,cbPals);
+ off += cbPals;
+ }
+ ptr = record + off;
+ *(uint32_t *)ptr = irecsize + et->used; // EMREOF nSizeLast field, not at a fixed position, cannot be accessed by field name
+ }
+ et->PalEntries = cbPalEntries;
+ return(record);
+}
+
+
+// U_EMRSETPIXELV_set 15
+/**
+ \brief Allocate and construct a U_EMR_SETPIXELV record.
+ \return pointer to U_EMR_SETPIXELV record, or NULL on error.
+ \param ptlPixel Pixel coordinates (logical)
+ \param crColor Pixel color
+*/
+char *U_EMRSETPIXELV_set(
+ const U_POINTL ptlPixel,
+ const U_COLORREF crColor
+ ){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRSETPIXELV);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_SETPIXELV;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRSETPIXELV)record)->ptlPixel = ptlPixel;
+ ((PU_EMRSETPIXELV)record)->crColor = crColor;
+ }
+ return(record);
+}
+
+
+// U_EMRSETMAPPERFLAGS_set 16
+/**
+ \brief Allocate and construct a U_EMR_SETMAPPERFLAGS record.
+ \return pointer to U_EMR_SETMAPPERFLAGS record, or NULL on error.
+*/
+char *U_EMRSETMAPPERFLAGS_set(void){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRSETMAPPERFLAGS);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_SETMAPPERFLAGS;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRSETMAPPERFLAGS)record)->dwFlags = 1;
+ }
+ return(record);
+}
+
+// U_EMRSETMAPMODE_set 17
+/**
+ \brief Allocate and construct a U_EMR_SETMAPMODE record.
+ \return pointer to U_EMR_SETMAPMODE record, or NULL on error.
+ \param iMode MapMode Enumeration
+*/
+char *U_EMRSETMAPMODE_set(
+ const uint32_t iMode
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SETMAPMODE, iMode));
+}
+
+// U_EMRSETBKMODE_set 18
+/**
+ \brief Allocate and construct a U_EMR_SETBKMODE record.
+ \return pointer to U_EMR_SETBKMODE record, or NULL on error.
+ \param iMode BackgroundMode Enumeration
+*/
+char *U_EMRSETBKMODE_set(
+ const uint32_t iMode
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SETBKMODE, iMode));
+}
+
+// U_EMRSETPOLYFILLMODE_set 19
+/**
+ \brief Allocate and construct a U_EMR_SETPOLYFILLMODE record.
+ \return pointer to U_EMR_SETPOLYFILLMODE record, or NULL on error.
+ \param iMode PolygonFillMode Enumeration
+*/
+char *U_EMRSETPOLYFILLMODE_set(
+ const uint32_t iMode
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SETPOLYFILLMODE, iMode));
+}
+
+// U_EMRSETROP2_set 20
+/**
+ \brief Allocate and construct a U_EMR_SETROP2 record.
+ \return pointer to U_EMR_SETROP2 record, or NULL on error.
+ \param iMode RasterOperation2 Enumeration
+*/
+char *U_EMRSETROP2_set(
+ const uint32_t iMode
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SETROP2, iMode));
+}
+
+// U_EMRSETSTRETCHBLTMODE_set 21
+/**
+ \brief Allocate and construct a U_EMR_SETSTRETCHBLTMODE record.
+ \return pointer to U_EMR_SETSTRETCHBLTMODE record, or NULL on error.
+ \param iMode StretchMode Enumeration
+*/
+char *U_EMRSETSTRETCHBLTMODE_set(
+ const uint32_t iMode
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SETSTRETCHBLTMODE, iMode));
+}
+
+// U_EMRSETTEXTALIGN_set 22
+/**
+ \brief Allocate and construct a U_EMR_SETTEXTALIGN record.
+ \return pointer to U_EMR_SETTEXTALIGN record, or NULL on error.
+ \param iMode TextAlignment Enumeration
+*/
+char *U_EMRSETTEXTALIGN_set(
+ const uint32_t iMode
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SETTEXTALIGN, iMode));
+}
+
+// U_EMRSETCOLORADJUSTMENT_set 23
+/**
+ \brief Allocate and construct a U_EMR_SETCOLORADJUSTMENT record.
+ \return pointer to U_EMR_SETCOLORADJUSTMENT record, or NULL on error.
+ \param ColorAdjustment Color Adjustment
+*/
+char *U_EMRSETCOLORADJUSTMENT_set(
+ const U_COLORADJUSTMENT ColorAdjustment
+ ){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRSETCOLORADJUSTMENT);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_SETCOLORADJUSTMENT;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRSETCOLORADJUSTMENT) record)->ColorAdjustment = ColorAdjustment;
+ }
+ return(record);
+}
+
+// U_EMRSETTEXTCOLOR_set 24
+/**
+ \brief Allocate and construct a U_EMR_SETTEXTCOLOR record.
+ \return pointer to U_EMR_SETTEXTCOLOR record, or NULL on error.
+ \param crColor Text Color
+*/
+char *U_EMRSETTEXTCOLOR_set(
+ const U_COLORREF crColor
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SETTEXTCOLOR, *(uint32_t *) &crColor));
+}
+
+// U_EMRSETBKCOLOR_set 25
+/**
+ \brief Allocate and construct a U_EMR_SETBKCOLOR record.
+ \return pointer to U_EMR_SETBKCOLOR record, or NULL on error.
+ \param crColor Background Color
+*/
+char *U_EMRSETBKCOLOR_set(
+ const U_COLORREF crColor
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SETBKCOLOR, *(uint32_t *) &crColor));
+}
+
+// U_EMROFFSETCLIPRGN_set 26
+/**
+ \brief Allocate and construct a U_EMR_OFFSETCLIPRGN record.
+ \return pointer to U_EMR_OFFSETCLIPRGN record, or NULL on error.
+ \param ptl Clipping region
+*/
+char *U_EMROFFSETCLIPRGN_set(
+ const U_POINTL ptl
+ ){
+ return(U_EMR_CORE7_set(U_EMR_OFFSETCLIPRGN, ptl));
+}
+
+// U_EMRMOVETOEX_set 27
+/**
+ \brief Allocate and construct a U_EMR_MOVETOEX record.
+ \return pointer to U_EMR_MOVETOEX record, or NULL on error.
+ \param ptl Point coordinates
+*/
+char *U_EMRMOVETOEX_set(
+ const U_POINTL ptl
+ ){
+ return(U_EMR_CORE7_set(U_EMR_MOVETOEX, ptl));
+}
+
+// U_EMRSETMETARGN_set 28
+/**
+ \brief Allocate and construct a U_EMR_SETMETARGN record.
+ \return pointer to U_EMR_SETMETARGN record, or NULL on error.
+*/
+char *U_EMRSETMETARGN_set(void){
+ return(U_EMR_CORE5_set(U_EMR_SETMETARGN));
+}
+
+// U_EMREXCLUDECLIPRECT_set 29
+/**
+ \brief Allocate and construct a U_EMR_EXCLUDECLIPRECT record.
+ \return pointer to U_EMR_EXCLUDECLIPRECT record, or NULL on error.
+ \param rclClip Clipping Region
+*/
+char *U_EMREXCLUDECLIPRECT_set(
+ const U_RECTL rclClip
+ ){
+ return(U_EMR_CORE4_set(U_EMR_EXCLUDECLIPRECT,rclClip));
+}
+
+// U_EMRINTERSECTCLIPRECT_set 30
+/**
+ \brief Allocate and construct a U_EMR_INTERSECTCLIPRECT record.
+ \return pointer to U_EMR_INTERSECTCLIPRECT record, or NULL on error.
+ \param rclClip Clipping Region
+*/
+char *U_EMRINTERSECTCLIPRECT_set(
+ const U_RECTL rclClip
+ ){
+ return(U_EMR_CORE4_set(U_EMR_INTERSECTCLIPRECT,rclClip));
+}
+
+// U_EMRSCALEVIEWPORTEXTEX_set 31
+/**
+ \brief Allocate and construct a U_EMR_SCALEVIEWPORTEXTEX record.
+ \return pointer to U_EMR_SCALEVIEWPORTEXTEX record, or NULL on error.
+ \param xNum Horizontal multiplier (!=0)
+ \param xDenom Horizontal divisor (!=0)
+ \param yNum Vertical multiplier (!=0)
+ \param yDenom Vertical divisor (!=0)
+*/
+char *U_EMRSCALEVIEWPORTEXTEX_set(
+ const int32_t xNum,
+ const int32_t xDenom,
+ const int32_t yNum,
+ const int32_t yDenom
+ ){
+ return(U_EMR_CORE4_set(U_EMR_SCALEVIEWPORTEXTEX,(U_RECTL){xNum,xDenom,yNum,yDenom}));
+}
+
+
+// U_EMRSCALEWINDOWEXTEX_set 32
+/**
+ \brief Allocate and construct a U_EMR_SCALEWINDOWEXTEX record.
+ \return pointer to U_EMR_SCALEWINDOWEXTEX record, or NULL on error.
+ \param xNum Horizontal multiplier (!=0)
+ \param xDenom Horizontal divisor (!=0)
+ \param yNum Vertical multiplier (!=0)
+ \param yDenom Vertical divisor (!=0)
+*/
+char *U_EMRSCALEWINDOWEXTEX_set(
+ const int32_t xNum,
+ const int32_t xDenom,
+ const int32_t yNum,
+ const int32_t yDenom
+ ){
+ return(U_EMR_CORE4_set(U_EMR_SCALEWINDOWEXTEX,(U_RECTL){xNum,xDenom,yNum,yDenom}));
+}
+
+// U_EMRSAVEDC_set 33
+/**
+ \brief Allocate and construct a U_EMR_SAVEDC record.
+ \return pointer to U_EMR_SAVEDC record, or NULL on error.
+*/
+char *U_EMRSAVEDC_set(void){
+ return(U_EMR_CORE5_set(U_EMR_SAVEDC));
+}
+
+// U_EMRRESTOREDC_set 34
+/**
+ \brief Allocate and construct a U_EMR_RESTOREDC record.
+ \return pointer to U_EMR_RESTOREDC record, or NULL on error.
+ \param iRelative DC to restore. -1 is preceding
+*/
+char *U_EMRRESTOREDC_set(
+ const int32_t iRelative
+ ){
+ return(U_EMR_CORE3_set(U_EMR_RESTOREDC, (uint32_t) iRelative));
+}
+
+// U_EMRSETWORLDTRANSFORM_set 35
+/**
+ \brief Allocate and construct a U_EMR_SETWORLDTRANSFORM record.
+ \return pointer to U_EMR_SETWORLDTRANSFORM record, or NULL on error.
+ \param xform Transform to use
+*/
+char *U_EMRSETWORLDTRANSFORM_set(
+ const U_XFORM xform
+ ){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRSETWORLDTRANSFORM);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_SETWORLDTRANSFORM;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRSETWORLDTRANSFORM) record)->xform = xform;
+ }
+ return(record);
+}
+
+// U_EMRMODIFYWORLDTRANSFORM_set 36
+/**
+ \brief Allocate and construct a U_EMR_MODIFYWORLDTRANSFORM record.
+ \return pointer to U_EMR_MODIFYWORLDTRANSFORM record, or NULL on error.
+ \param xform Transform to use
+ \param iMode ModifyWorldTransformMode Enumeration
+*/
+char *U_EMRMODIFYWORLDTRANSFORM_set(
+ const U_XFORM xform,
+ const uint32_t iMode
+ ){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRMODIFYWORLDTRANSFORM);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_MODIFYWORLDTRANSFORM;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRMODIFYWORLDTRANSFORM) record)->xform = xform;
+ ((PU_EMRMODIFYWORLDTRANSFORM) record)->iMode = iMode;
+ }
+ return(record);
+}
+
+// U_EMRSELECTOBJECT_set 37
+/**
+ \brief Allocate and construct a U_EMR_SELECTOBJECT record.
+ Use selectobject_set() instead of calling this function directly.
+ \return pointer to U_EMR_SELECTOBJECT record, or NULL on error.
+ \param ihObject Number of a stock or created object
+*/
+char *U_EMRSELECTOBJECT_set(
+ const uint32_t ihObject
+ ){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRSELECTOBJECT);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_SELECTOBJECT;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRSELECTOBJECT) record)->ihObject = ihObject; // Index of object to SELECT
+ }
+ return(record);
+}
+
+// U_EMRCREATEPEN_set 38
+/**
+ \brief Allocate and construct a U_EMR_CREATEPEN record.
+ Use createpen_set() instead of calling this function directly.
+ \return pointer to U_EMR_CREATEPEN record, or NULL on error.
+ \param ihPen Handle of created pen
+ \param lopn U_LOGPEN structure describing this pen
+*/
+char *U_EMRCREATEPEN_set(
+ const uint32_t ihPen,
+ const U_LOGPEN lopn
+ ){
+ char *record;
+ int irecsize=sizeof(U_EMRCREATEPEN);
+
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_CREATEPEN;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRCREATEPEN) record)->ihPen = ihPen;
+ ((PU_EMRCREATEPEN) record)->lopn = lopn;
+ }
+ return(record);
+}
+
+// U_EMRCREATEBRUSHINDIRECT_set 39
+/**
+ \brief Allocate and construct a U_EMR_CREATEBRUSHINDIRECT record.
+ Use createbrushindirect_set() instead of calling this function directly.
+ \return pointer to U_EMR_CREATEBRUSHINDIRECT record, or NULL on error.
+ \param ihBrush Index to place object in EMF object table (this entry must not yet exist)
+ \param lb Brush properties
+*/
+char *U_EMRCREATEBRUSHINDIRECT_set(
+ const uint32_t ihBrush,
+ const U_LOGBRUSH lb
+ ){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRCREATEBRUSHINDIRECT);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_CREATEBRUSHINDIRECT;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRCREATEBRUSHINDIRECT) record)->ihBrush = ihBrush; // Index to place object in EMF object table (this entry must not yet exist)
+ ((PU_EMRCREATEBRUSHINDIRECT) record)->lb = lb;
+ }
+ return(record);
+}
+
+// U_EMRDELETEOBJECT_set 40
+/**
+ \brief Allocate and construct a U_EMR_DELETEOBJECT record.
+ Use deleteobject_set() instead of calling this function directly.
+ \return pointer to U_EMR_DELETEOBJECT record, or NULL on error.
+ \param ihObject Number of a stock or created object
+*/
+char *U_EMRDELETEOBJECT_set(
+ const uint32_t ihObject
+ ){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRDELETEOBJECT);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_DELETEOBJECT;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRDELETEOBJECT) record)->ihObject = ihObject; // Index of object to DELETE
+ }
+ return(record);
+}
+
+// U_EMRANGLEARC_set 41
+/**
+ \brief Allocate and construct a U_EMR_ANGLEARC record.
+ \return pointer to U_EMR_ANGLEARC record, or NULL on error.
+ \param ptlCenter Center in logical units
+ \param nRadius Radius in logical units
+ \param eStartAngle Starting angle in degrees (counter clockwise from x axis)
+ \param eSweepAngle Sweep angle in degrees
+*/
+char *U_EMRANGLEARC_set(
+ const U_POINTL ptlCenter,
+ const uint32_t nRadius,
+ const U_FLOAT eStartAngle,
+ const U_FLOAT eSweepAngle
+ ){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRANGLEARC);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_ANGLEARC;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRANGLEARC) record)->ptlCenter = ptlCenter;
+ ((PU_EMRANGLEARC) record)->nRadius = nRadius;
+ ((PU_EMRANGLEARC) record)->eStartAngle = eStartAngle;
+ ((PU_EMRANGLEARC) record)->eSweepAngle = eSweepAngle;
+ }
+ return(record);
+}
+
+// U_EMRELLIPSE_set 42
+/**
+ \brief Allocate and construct a U_EMR_ELLIPSE record.
+ \return pointer to U_EMR_ELLIPSE record, or NULL on error.
+ \param rclBox bounding rectangle in logical units
+*/
+char *U_EMRELLIPSE_set(
+ const U_RECTL rclBox
+ ){
+ return(U_EMR_CORE4_set(U_EMR_ELLIPSE,rclBox));
+}
+
+// U_EMRRECTANGLE_set 43
+/**
+ \brief Allocate and construct a U_EMR_RECTANGLE record.
+ \return pointer to U_EMR_RECTANGLE record, or NULL on error.
+ \param rclBox bounding rectangle in logical units
+*/
+char *U_EMRRECTANGLE_set(
+ const U_RECTL rclBox
+ ){
+ return(U_EMR_CORE4_set(U_EMR_RECTANGLE,rclBox));
+}
+
+// U_EMRROUNDRECT_set 44
+/**
+ \brief Allocate and construct a U_EMR_ROUNDRECT record.
+ \return pointer to U_EMR_ROUNDRECT record, or NULL on error.
+ \param rclBox bounding rectangle in logical units
+ \param szlCorner W & H in logical units of ellipse used to round corner
+*/
+char *U_EMRROUNDRECT_set(
+ const U_RECTL rclBox,
+ const U_SIZEL szlCorner
+ ){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRROUNDRECT);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_ROUNDRECT;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRROUNDRECT) record)->rclBox = rclBox;
+ ((PU_EMRROUNDRECT) record)->szlCorner = szlCorner;
+ }
+ return(record);
+}
+
+// U_EMRARC_set 45
+/**
+ \brief Allocate and construct a U_EMR_ARC record.
+ \return pointer to U_EMR_ARC record, or NULL on error.
+ \param rclBox bounding rectangle in logical units
+ \param ptlStart Start point in logical units
+ \param ptlEnd End point in logical units
+*/
+char *U_EMRARC_set(
+ const U_RECTL rclBox,
+ const U_POINTL ptlStart,
+ const U_POINTL ptlEnd
+ ){
+ return(U_EMR_CORE9_set(U_EMR_ARC,rclBox, ptlStart, ptlEnd));
+}
+
+// U_EMRCHORD_set 46
+/**
+ \brief Allocate and construct a U_EMR_CHORD record.
+ \return pointer to U_EMR_CHORD record, or NULL on error.
+ \param rclBox bounding rectangle in logical units
+ \param ptlStart Start point in logical units
+ \param ptlEnd End point in logical units
+*/
+char *U_EMRCHORD_set(
+ const U_RECTL rclBox,
+ const U_POINTL ptlStart,
+ const U_POINTL ptlEnd
+ ){
+ return(U_EMR_CORE9_set(U_EMR_CHORD,rclBox, ptlStart, ptlEnd));
+}
+
+// U_EMRPIE_set 47
+/**
+ \brief Allocate and construct a U_EMR_PIE record.
+ \return pointer to U_EMR_PIE record, or NULL on error.
+ \param rclBox bounding rectangle in logical units
+ \param ptlStart Start point in logical units
+ \param ptlEnd End point in logical units
+*/
+char *U_EMRPIE_set(
+ const U_RECTL rclBox,
+ const U_POINTL ptlStart,
+ const U_POINTL ptlEnd
+ ){
+ return(U_EMR_CORE9_set(U_EMR_PIE,rclBox, ptlStart, ptlEnd));
+}
+
+// U_EMRSELECTPALETTE_set 48
+/**
+ \brief Allocate and construct a U_EMR_SELECTPALETTE record.
+ \return pointer to U_EMR_SELECTPALETTE record, or NULL on error.
+ \param ihPal Index of a Palette object in the EMF object table
+*/
+char *U_EMRSELECTPALETTE_set(
+ const uint32_t ihPal
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SELECTPALETTE, ihPal));
+}
+
+// U_EMRCREATEPALETTE_set 49
+/**
+ \brief Allocate and construct a U_EMR_CREATEPALETTE record.
+ Use createpalette_set() instead of calling this function directly.
+ \return pointer to U_EMR_CREATEPALETTE record, or NULL on error.
+ \param ihPal Index to place object in EMF object table (this entry must not yet exist)
+ \param lgpl Palette properties
+*/
+char *U_EMRCREATEPALETTE_set(
+ const uint32_t ihPal,
+ const U_LOGPALETTE lgpl
+ ){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRCREATEPALETTE);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_CREATEPALETTE;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRCREATEPALETTE) record)->ihPal = ihPal;
+ ((PU_EMRCREATEPALETTE) record)->lgpl = lgpl;
+ }
+ return(record);
+}
+
+// U_EMRSETPALETTEENTRIES_set 50
+/**
+ \brief Allocate and construct a U_EMR_SETPALETTEENTRIES record.
+ Use setpaletteentries_set() instead of calling this function directly.
+ \return pointer to U_EMR_SETPALETTEENTRIES record, or NULL on error.
+ \param ihPal Index of a Palette object in the EMF object table
+ \param iStart First Palette entry in selected object to set
+ \param cEntries Number of Palette entries in selected object to set
+ \param aPalEntries Values to set with
+*/
+char *U_EMRSETPALETTEENTRIES_set(
+ const uint32_t ihPal,
+ const uint32_t iStart,
+ const U_NUM_LOGPLTNTRY cEntries,
+ const PU_LOGPLTNTRY aPalEntries
+ ){
+ char *record;
+ int irecsize;
+ int cbPals;
+
+ if(!aPalEntries)return(NULL);
+ cbPals = cEntries * sizeof(U_LOGPLTNTRY);
+ irecsize = sizeof(U_EMRSETPALETTEENTRIES) + cbPals - sizeof(U_LOGPLTNTRY);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_SETPALETTEENTRIES;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRSETPALETTEENTRIES) record)->ihPal = ihPal;
+ ((PU_EMRSETPALETTEENTRIES) record)->iStart = iStart;
+ ((PU_EMRSETPALETTEENTRIES) record)->cEntries = cEntries;
+ memcpy(((PU_EMRSETPALETTEENTRIES) record)->aPalEntries, aPalEntries,cbPals);
+ }
+ return(record);
+}
+
+// U_EMRRESIZEPALETTE_set 51
+/**
+ \brief Allocate and construct a U_EMR_RESIZEPALETTE record.
+ \return pointer to U_EMR_RESIZEPALETTE record, or NULL on error.
+ \param ihPal Index of a Palette object in the EMF object table
+ \param cEntries Number to expand or truncate the Palette entry list to
+*/
+char *U_EMRRESIZEPALETTE_set(
+ const uint32_t ihPal,
+ const uint32_t cEntries
+ ){
+ return(U_EMR_CORE7_set(U_EMR_RESIZEPALETTE, (U_PAIR){ihPal,cEntries}));
+}
+
+// U_EMRREALIZEPALETTE_set 52
+/**
+ \brief Allocate and construct a U_EMR_REALIZEPALETTE record.
+ \return pointer to U_EMR_REALIZEPALETTE record, or NULL on error.
+*/
+char *U_EMRREALIZEPALETTE_set(void){
+ return(U_EMR_CORE5_set(U_EMR_REALIZEPALETTE));
+}
+
+// U_EMREXTFLOODFILL_set 53
+/**
+ \brief Allocate and construct a U_EMR_EXTFLOODFILL record.
+ \return pointer to U_EMR_EXTFLOODFILL record, or NULL on error.
+ \param ptlStart Start point in logical units
+ \param crColor Color to fill with
+ \param iMode FloodFill Enumeration
+*/
+char *U_EMREXTFLOODFILL_set(
+ const U_POINTL ptlStart,
+ const U_COLORREF crColor,
+ const uint32_t iMode
+ ){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMREXTFLOODFILL);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_EXTFLOODFILL;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMREXTFLOODFILL) record)->ptlStart = ptlStart;
+ ((PU_EMREXTFLOODFILL) record)->crColor = crColor;
+ ((PU_EMREXTFLOODFILL) record)->iMode = iMode;
+ }
+ return(record);
+}
+
+// U_EMRLINETO_set 54
+/**
+ \brief Allocate and construct a U_EMR_LINETO record.
+ \return pointer to U_EMR_LINETO record, or NULL on error.
+ \param ptl Point coordinates
+*/
+char *U_EMRLINETO_set(
+ const U_POINTL ptl
+ ){
+ return(U_EMR_CORE7_set(U_EMR_LINETO, ptl));
+}
+
+// U_EMRARCTO_set 55
+/**
+ \brief Allocate and construct a U_EMR_ARCTO record.
+ \return pointer to U_EMR_ARCTO record, or NULL on error.
+ \param rclBox bounding rectangle in logical units
+ \param ptlStart Start point in logical units
+ \param ptlEnd End point in logical units
+
+ Note that the draw begins with a line from the current point to ptlStart, which is
+ not indicated in the Microsoft EMF documentation for this record.
+*/
+char *U_EMRARCTO_set(
+ U_RECTL rclBox,
+ U_POINTL ptlStart,
+ U_POINTL ptlEnd
+ ){
+ return(U_EMR_CORE9_set(U_EMR_ARCTO,rclBox, ptlStart, ptlEnd));
+}
+
+// U_EMRPOLYDRAW_set 56
+/**
+ \brief Allocate and construct a U_EMR_POLYDRAW record.
+ \return pointer to U_EMR_POLYDRAW record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param cptl Number of U_POINTL objects
+ \param aptl Array of U_POINTL objects
+ \param abTypes Array of Point Enumeration
+*/
+char *U_EMRPOLYDRAW_set(
+ const U_RECTL rclBounds,
+ const U_NUM_POINTL cptl,
+ const U_POINTL *aptl,
+ const uint8_t *abTypes
+ ){
+ char *record;
+ int irecsize;
+ int cbPoints, cbAbTypes, cbAbTypes4, off;
+
+ if(!cptl || !aptl || !abTypes)return(NULL);
+ cbPoints = cptl * sizeof(U_POINTL); // space for aptl
+ cbAbTypes = cptl; // number of abTypes (same array size, 1 byte each)
+ cbAbTypes4 = UP4(cbAbTypes); // space for abTypes
+ irecsize = sizeof(U_EMRPOLYDRAW) + cbPoints + cbAbTypes4 - sizeof(U_POINTL) - 1;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_POLYDRAW;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRPOLYDRAW) record)->rclBounds = rclBounds;
+ ((PU_EMRPOLYDRAW) record)->cptl = cptl;
+ off = sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(uint32_t); // offset to first variable part
+ memcpy(record+off,aptl,cbPoints);
+ off += cbPoints;
+ memcpy(record+off,abTypes,cbAbTypes);
+ off += cbAbTypes;
+ if(cbAbTypes4 > cbAbTypes){ memset(record+off,0,cbAbTypes4-cbAbTypes); } // keeps valgrind happy (initialize padding after byte array)
+ }
+ return(record);
+}
+
+// U_EMRSETARCDIRECTION_set 57
+/**
+ \brief Allocate and construct a U_EMR_SETARCDIRECTION record.
+ \return pointer to U_EMR_SETARCDIRECTION record, or NULL on error.
+ \param iArcDirection ArcDirection Enumeration
+*/
+char *U_EMRSETARCDIRECTION_set(
+ const uint32_t iArcDirection
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SETARCDIRECTION, iArcDirection));
+}
+
+// U_EMRSETMITERLIMIT_set 58
+/**
+ \brief Allocate and construct a U_EMR_SETMITERLIMIT record.
+ \return pointer to U_EMR_SETMITERLIMIT record, or NULL on error.
+ \param eMiterLimit MapMode Enumeration
+*/
+char *U_EMRSETMITERLIMIT_set(
+ const uint32_t eMiterLimit
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SETMITERLIMIT, eMiterLimit));
+}
+
+
+// U_EMRBEGINPATH_set 59
+/**
+ \brief Allocate and construct a U_EMR_BEGINPATH record.
+ \return pointer to U_EMR_BEGINPATH record, or NULL on error.
+*/
+char *U_EMRBEGINPATH_set(void){
+ return(U_EMR_CORE5_set(U_EMR_BEGINPATH));
+}
+
+// U_EMRENDPATH_set 60
+/**
+ \brief Allocate and construct a U_EMR_ENDPATH record.
+ \return pointer to U_EMR_ENDPATH record, or NULL on error.
+*/
+char *U_EMRENDPATH_set(void){
+ return(U_EMR_CORE5_set(U_EMR_ENDPATH));
+}
+
+// U_EMRCLOSEFIGURE_set 61
+/**
+ \brief Allocate and construct a U_EMR_CLOSEFIGURE record.
+ \return pointer to U_EMR_CLOSEFIGURE record, or NULL on error.
+*/
+char *U_EMRCLOSEFIGURE_set(void){
+ return(U_EMR_CORE5_set(U_EMR_CLOSEFIGURE));
+}
+
+// U_EMRFILLPATH_set 62
+/**
+ \brief Allocate and construct a U_EMR_FILLPATH record.
+ \return pointer to U_EMR_FILLPATH record, or NULL on error.
+ \param rclBox Bounding rectangle in device units
+
+ U_EMR_FILLPATH closes the open figure before filling.
+*/
+char *U_EMRFILLPATH_set(
+ const U_RECTL rclBox
+ ){
+ return(U_EMR_CORE4_set(U_EMR_FILLPATH,rclBox));
+}
+
+// U_EMRSTROKEANDFILLPATH_set 63
+/**
+ \brief Allocate and construct a U_EMR_STROKEANDFILLPATH record.
+ \return pointer to U_EMR_STROKEANDFILLPATH record, or NULL on error.
+ \param rclBox Bounding rectangle in device units
+
+ U_EMR_STROKEANDFILLPATH closes the open figure before filling and stroking.
+ There appears to be no way to fill an open path while stroking it, as any one
+ of U_EMRFILLPATH, U_EMRSTROKEPATH, or U_EMRSTROKEANDFILEPATH will "use up" the path,
+*/
+char *U_EMRSTROKEANDFILLPATH_set(
+ const U_RECTL rclBox
+ ){
+ return(U_EMR_CORE4_set(U_EMR_STROKEANDFILLPATH,rclBox));
+}
+
+// U_EMRSTROKEPATH_set 64
+/**
+ \brief Allocate and construct a U_EMR_STROKEPATH record.
+ \return pointer to U_EMR_STROKEPATH record, or NULL on error.
+ \param rclBox Bounding rectangle in device units
+
+ U_EMR_STROKEPATH does NOT close the open figure before stroking it.
+*/
+char *U_EMRSTROKEPATH_set(
+ const U_RECTL rclBox
+ ){
+ return(U_EMR_CORE4_set(U_EMR_STROKEPATH,rclBox));
+}
+
+// U_EMRFLATTENPATH_set 65
+/**
+ \brief Allocate and construct a U_EMR_FLATTENPATH record.
+ \return pointer to U_EMR_FLATTENPATH record, or NULL on error.
+*/
+char *U_EMRFLATTENPATH_set(void){
+ return(U_EMR_CORE5_set(U_EMR_FLATTENPATH));
+}
+
+// U_EMRWIDENPATH_set 66
+/**
+ \brief Allocate and construct a U_EMR_WIDENPATH record.
+ \return pointer to U_EMR_WIDENPATH record, or NULL on error.
+*/
+char *U_EMRWIDENPATH_set(void){
+ return(U_EMR_CORE5_set(U_EMR_WIDENPATH));
+}
+
+// U_EMRSELECTCLIPPATH_set 67
+/**
+ \brief Allocate and construct a U_EMR_SELECTCLIPPATH record.
+ \return pointer to U_EMR_SELECTCLIPPATH record, or NULL on error.
+ \param iMode RegionMode Enumeration
+*/
+char *U_EMRSELECTCLIPPATH_set(
+ const uint32_t iMode
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SELECTCLIPPATH, iMode));
+}
+
+// U_EMRABORTPATH_set 68
+/**
+ \brief Allocate and construct a U_EMR_ABORTPATH record.
+ \return pointer to U_EMR_ABORTPATH record, or NULL on error.
+*/
+char *U_EMRABORTPATH_set(void){
+ return(U_EMR_CORE5_set(U_EMR_ABORTPATH));
+}
+
+// U_EMRUNDEF69 69
+
+// U_EMRCOMMENT_set 70 Comment (any binary data, interpretation is program specific)
+/**
+ \brief Allocate and construct a U_EMR_COMMENT record.
+ \return pointer to U_EMR_COMMENT record, or NULL on error.
+ \param cbData Number of bytes in comment
+ \param Data Comment (any binary data, interpretation is program specific)
+*/
+char *U_EMRCOMMENT_set(
+ const U_CBDATA cbData,
+ const char *Data
+ ){
+ char *record;
+ unsigned int cbData4;
+ int irecsize;
+
+ cbData4 = UP4(cbData);
+ irecsize = sizeof(U_EMR) + sizeof(U_CBDATA) + cbData4;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_COMMENT;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRCOMMENT) record)->cbData = cbData;
+ memcpy(record + irecsize - cbData4,Data,cbData);
+ if(cbData4 > cbData)memset(record + irecsize - cbData4 + cbData,0,cbData4-cbData); // clear any unused bytes
+ }
+ return(record);
+}
+
+// U_EMRFILLRGN_set 71
+/**
+ \brief Allocate and construct a U_EMR_FILLRGN record.
+ Use fillrgn_set() instead of calling this function directly.
+ \return pointer to U_EMR_FILLRGN record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param ihBrush Index of a Brush object in the EMF object table
+ \param RgnData Pointer to a U_RGNDATA structure
+*/
+char *U_EMRFILLRGN_set(
+ const U_RECTL rclBounds,
+ const uint32_t ihBrush,
+ const PU_RGNDATA RgnData
+ ){
+ char *record;
+ int irecsize;
+ int cbRgns,cbRgns4,rds,rds4,off;
+
+ if(!RgnData)return(NULL);
+ cbRgns = ((PU_RGNDATAHEADER) RgnData)->nRgnSize;
+ cbRgns4 = UP4(cbRgns);
+ rds = sizeof(U_RGNDATAHEADER) + cbRgns;
+ rds4 = UP4(rds);
+ irecsize = sizeof(U_EMRFILLRGN) - sizeof(U_RECTL) + cbRgns4; // core + array - overlap of one rectL
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_FILLRGN;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRFILLRGN) record)->rclBounds = rclBounds;
+ ((PU_EMRFILLRGN) record)->cbRgnData = rds;
+ ((PU_EMRFILLRGN) record)->ihBrush = ihBrush;
+ off = sizeof(U_EMRFILLRGN) - sizeof(U_RGNDATA);
+ memcpy(record + off, RgnData, rds);
+ off += rds;
+ if(rds < rds4){ memset(record + off,0, rds4 - rds); } // clear any unused bytes
+ }
+ return(record);
+}
+
+// U_EMRFRAMERGN_set 72
+/**
+ \brief Allocate and construct a U_EMR_FRAMERGN record.
+ Use framegrn_set() instead of calling this function directly.
+ \return pointer to U_EMR_FRAMERGN record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param ihBrush Index of a Brush object in the EMF object table
+ \param szlStroke W & H of Brush stroke
+ \param RgnData Pointer to a U_RGNDATA structure
+*/
+char *U_EMRFRAMERGN_set(
+ const U_RECTL rclBounds,
+ const uint32_t ihBrush,
+ const U_SIZEL szlStroke,
+ const PU_RGNDATA RgnData
+ ){
+ char *record;
+ int irecsize;
+ int cbRgns,cbRgns4,rds,rds4,off;
+
+ if(!RgnData)return(NULL);
+ cbRgns = ((PU_RGNDATAHEADER) RgnData)->nRgnSize;
+ cbRgns4 = UP4(cbRgns);
+ rds = sizeof(U_RGNDATAHEADER) + cbRgns;
+ rds4 = UP4(rds);
+ irecsize = sizeof(U_EMRFRAMERGN) - sizeof(U_RECTL) + cbRgns4; // core + array - overlap of one rectL
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_FRAMERGN;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRFRAMERGN) record)->rclBounds = rclBounds;
+ ((PU_EMRFRAMERGN) record)->cbRgnData = rds;
+ ((PU_EMRFRAMERGN) record)->ihBrush = ihBrush;
+ ((PU_EMRFRAMERGN) record)->szlStroke = szlStroke;
+ off = sizeof(U_EMRFRAMERGN) - sizeof(U_RGNDATA);
+ memcpy(record + off, RgnData, rds);
+ off += rds;
+ if(rds < rds4){ memset(record + off,0, rds4 - rds); } // clear any unused bytes
+ }
+ return(record);
+}
+
+// U_EMRINVERTRGN_set 73
+/**
+ \brief Allocate and construct a U_EMR_INVERTRGN record.
+ \return pointer to U_EMR_INVERTRGN record, or NULL on error.
+ \param RgnData Variable size U_RGNDATA structure
+*/
+char *U_EMRINVERTRGN_set(
+ const PU_RGNDATA RgnData
+ ){
+ return(U_EMR_CORE11_set(U_EMR_INVERTRGN, RgnData));
+}
+
+// U_EMRPAINTRGN_set 74
+/**
+ \brief Allocate and construct a U_EMR_PAINTRGN record.
+ \return pointer to U_EMR_PAINTRGN record, or NULL on error.
+ \param RgnData Variable size U_RGNDATA structure
+*/
+char *U_EMRPAINTRGN_set(
+ const PU_RGNDATA RgnData
+ ){
+ return(U_EMR_CORE11_set(U_EMR_PAINTRGN, RgnData));
+}
+
+// U_EMREXTSELECTCLIPRGN_set 75
+/**
+ \brief Allocate and construct a U_EMR_EXTSELECTCLIPRGN record.
+ \return pointer to U_EMR_EXTSELECTCLIPRGN or NULL on error.
+ \param iMode RegionMode Enumeration
+ \param RgnData Variable size U_RGNDATA structure
+*/
+char *U_EMREXTSELECTCLIPRGN_set(
+ const uint32_t iMode,
+ const PU_RGNDATA RgnData
+ ){
+ char *record;
+ int irecsize;
+ int cbRgns,cbRgns4,rds,rds4,off;
+
+ if(!RgnData)return(NULL);
+ cbRgns = ((PU_RGNDATAHEADER) RgnData)->nRgnSize;
+ cbRgns4 = UP4(cbRgns);
+ rds = sizeof(U_RGNDATAHEADER) + cbRgns;
+ rds4 = UP4(rds);
+ irecsize = sizeof(U_EMREXTSELECTCLIPRGN) - sizeof(U_RECTL) + cbRgns4; // core + array - overlap of one rectL
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_EXTSELECTCLIPRGN;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMREXTSELECTCLIPRGN) record)->cbRgnData = rds;
+ ((PU_EMREXTSELECTCLIPRGN) record)->iMode = iMode;
+ off = sizeof(U_EMREXTSELECTCLIPRGN) - sizeof(U_RGNDATA);
+ memcpy(record + off, RgnData, rds);
+ off += rds;
+ if(rds < rds4){ memset(record + off,0, rds4 - rds); } // clear any unused bytes
+ }
+ return(record);
+}
+
+// U_EMRBITBLT_set 76
+/**
+ \brief Allocate and construct a U_EMR_BITBLT record.
+ \return pointer to U_EMR_BITBLT record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param Dest Destination UL corner in logical units
+ \param cDest Destination width in logical units
+ \param Src Source rectangle UL corner in logical units
+ \param xformSrc Source bitmap transform (world to page coordinates)
+ \param crBkColorSrc Source bitmap background color
+ \param iUsageSrc DIBcolors Enumeration
+ \param dwRop Ternary Raster Operation enumeration
+ \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section)
+ \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+*/
+char *U_EMRBITBLT_set(
+ const U_RECTL rclBounds,
+ const U_POINTL Dest,
+ const U_POINTL cDest,
+ const U_POINTL Src,
+ const U_XFORM xformSrc,
+ const U_COLORREF crBkColorSrc,
+ const uint32_t iUsageSrc,
+ const uint32_t dwRop,
+ const PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ char *Px
+ ){
+ char *record;
+ int irecsize;
+ int cbImage,cbImage4,cbBmi,off;
+
+ SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
+ irecsize = sizeof(U_EMRBITBLT) + cbBmi + cbImage4;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_BITBLT;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRBITBLT) record)->rclBounds = rclBounds;
+ ((PU_EMRBITBLT) record)->Dest = Dest;
+ ((PU_EMRBITBLT) record)->cDest = cDest;
+ ((PU_EMRBITBLT) record)->dwRop = dwRop;
+ ((PU_EMRBITBLT) record)->Src = Src;
+ ((PU_EMRBITBLT) record)->xformSrc = xformSrc;
+ ((PU_EMRBITBLT) record)->crBkColorSrc = crBkColorSrc;
+ ((PU_EMRBITBLT) record)->iUsageSrc = iUsageSrc;
+ off = sizeof(U_EMRBITBLT);
+ APPEND_PXBMISRC(record, U_EMRBITBLT, cbBmi, Bmi, Px, cbImage, cbImage4);
+ }
+ return(record);
+}
+
+// U_EMRSTRETCHBLT_set 77
+/**
+ \brief Allocate and construct a U_EMR_STRETCHBLT record.
+ \return pointer to U_EMR_STRETCHBLT record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param Dest Destination UL corner in logical units
+ \param cDest Destination width in logical units
+ \param Src Source UL corner in logical units
+ \param cSrc Src W & H in logical units
+ \param xformSrc Transform to apply to source
+ \param crBkColorSrc Background color
+ \param iUsageSrc DIBcolors Enumeration
+ \param dwRop Ternary Raster Operation enumeration
+ \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section)
+ \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+*/
+char *U_EMRSTRETCHBLT_set(
+ const U_RECTL rclBounds,
+ const U_POINTL Dest,
+ const U_POINTL cDest,
+ const U_POINTL Src,
+ const U_POINTL cSrc,
+ const U_XFORM xformSrc,
+ const U_COLORREF crBkColorSrc,
+ const uint32_t iUsageSrc,
+ const uint32_t dwRop,
+ const PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ char *Px
+ ){
+ char *record;
+ int irecsize;
+ int cbImage,cbImage4,cbBmi,off;
+
+ SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
+
+ irecsize = sizeof(U_EMRSTRETCHBLT) + cbBmi + cbImage4;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_STRETCHBLT;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRSTRETCHBLT) record)->rclBounds = rclBounds;
+ ((PU_EMRSTRETCHBLT) record)->Dest = Dest;
+ ((PU_EMRSTRETCHBLT) record)->cDest = cDest;
+ ((PU_EMRSTRETCHBLT) record)->dwRop = dwRop;
+ ((PU_EMRSTRETCHBLT) record)->Src = Src;
+ ((PU_EMRSTRETCHBLT) record)->xformSrc = xformSrc;
+ ((PU_EMRSTRETCHBLT) record)->crBkColorSrc = crBkColorSrc;
+ ((PU_EMRSTRETCHBLT) record)->iUsageSrc = iUsageSrc;
+ off = sizeof(U_EMRSTRETCHBLT);
+ APPEND_PXBMISRC(record, U_EMRSTRETCHBLT, cbBmi, Bmi, Px, cbImage, cbImage4);
+ ((PU_EMRSTRETCHBLT) record)->cSrc = cSrc;
+ }
+ return(record);
+}
+
+// U_EMRMASKBLT_set 78
+/**
+ \brief Allocate and construct a U_EMR_MASKBLT record.
+ \return pointer to U_EMR_MASKBLT record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param Dest Destination UL corner in logical units
+ \param cDest Destination width in logical units
+ \param Src Source UL corner in logical units
+ \param xformSrc Transform to apply to source
+ \param crBkColorSrc Background color
+ \param iUsageSrc DIBcolors Enumeration
+ \param Mask Mask UL corner in logical units
+ \param iUsageMask DIBcolors Enumeration
+ \param dwRop Ternary Raster Operation enumeration
+ \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section)
+ \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+ \param MskBmi (Optional) bitmapbuffer (U_BITMAPINFO section)
+ \param cbMsk Size in bytes of mask array (row stride * height, there may be some padding at the end of each row)
+ \param Msk (Optional) bitmapbuffer (mask section )
+*/
+char *U_EMRMASKBLT_set(
+ const U_RECTL rclBounds,
+ const U_POINTL Dest,
+ const U_POINTL cDest,
+ const U_POINTL Src,
+ const U_XFORM xformSrc,
+ const U_COLORREF crBkColorSrc,
+ const uint32_t iUsageSrc,
+ const U_POINTL Mask,
+ const uint32_t iUsageMask,
+ const uint32_t dwRop,
+ const PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ char *Px,
+ const PU_BITMAPINFO MskBmi,
+ const uint32_t cbMsk,
+ char *Msk
+ ){
+ char *record;
+ int irecsize;
+ int cbImage,cbImage4,cbBmi,cbMskImage,cbMskImage4,cbMskBmi,off;
+
+ SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
+ SET_CB_FROM_PXBMI(Msk,MskBmi,cbMskImage,cbMskImage4,cbMskBmi,cbMsk);
+
+ irecsize = sizeof(U_EMRMASKBLT) + cbBmi + cbImage4 + cbMskBmi + cbMskImage4;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_MASKBLT;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRMASKBLT) record)->rclBounds = rclBounds;
+ ((PU_EMRMASKBLT) record)->Dest = Dest;
+ ((PU_EMRMASKBLT) record)->cDest = cDest;
+ ((PU_EMRMASKBLT) record)->dwRop = dwRop;
+ ((PU_EMRMASKBLT) record)->Src = Src;
+ ((PU_EMRMASKBLT) record)->xformSrc = xformSrc;
+ ((PU_EMRMASKBLT) record)->crBkColorSrc = crBkColorSrc;
+ ((PU_EMRMASKBLT) record)->iUsageSrc = iUsageSrc;
+ ((PU_EMRMASKBLT) record)->Mask = Mask;
+ ((PU_EMRMASKBLT) record)->iUsageMask = iUsageMask;
+ off = sizeof(U_EMRMASKBLT);
+ APPEND_PXBMISRC(record, U_EMRMASKBLT, cbBmi, Bmi, Px, cbImage, cbImage4);
+ APPEND_MSKBMISRC(record, U_EMRMASKBLT, cbMskBmi, MskBmi, Msk, cbMskImage, cbMskImage4);
+ }
+ return(record);
+}
+
+// U_EMRPLGBLT_set 79
+
+/**
+ \brief Allocate and construct a U_EMRPLGBLT record.
+ \return U_EMRPLGBLT record.
+ \param rclBounds Bounding rectangle in device units
+ \param aptlDst Defines parallelogram, UL, UR, LL corners, LR is derived (3 points)
+ \param Src Source UL corner in logical units
+ \param cSrc Source width in logical units
+ \param xformSrc Transform to apply to source
+ \param crBkColorSrc Background color
+ \param iUsageSrc DIBcolors Enumeration
+ \param Mask Mask UL corner in logical units
+ \param iUsageMask DIBcolors Enumeration
+ \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section)
+ \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+ \param MskBmi (Optional) bitmapbuffer (U_BITMAPINFO section)
+ \param cbMsk Size in bytes of mask array (row stride * height, there may be some padding at the end of each row)
+ \param Msk (Optional) bitmapbuffer (mask section )
+*/
+char *U_EMRPLGBLT_set(
+ const U_RECTL rclBounds,
+ const PU_POINTL aptlDst,
+ const U_POINTL Src,
+ const U_POINTL cSrc,
+ const U_XFORM xformSrc,
+ const U_COLORREF crBkColorSrc,
+ const uint32_t iUsageSrc,
+ const U_POINTL Mask,
+ const uint32_t iUsageMask,
+ const PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ char *Px,
+ const PU_BITMAPINFO MskBmi,
+ const uint32_t cbMsk,
+ char *Msk
+ ){
+ char *record;
+ int irecsize;
+ int cbImage,cbImage4,cbBmi,cbMskImage,cbMskImage4,cbMskBmi,off;
+
+ SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
+ SET_CB_FROM_PXBMI(Msk,MskBmi,cbMskImage,cbMskImage4,cbMskBmi,cbMsk);
+
+ irecsize = sizeof(U_EMRPLGBLT) + cbBmi + cbImage4 + cbMskBmi + cbMskImage4;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_PLGBLT;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRPLGBLT) record)->rclBounds = rclBounds;
+ memcpy(((PU_EMRPLGBLT) record)->aptlDst,aptlDst,3*sizeof(U_POINTL));
+ ((PU_EMRPLGBLT) record)->Src = Src;
+ ((PU_EMRPLGBLT) record)->cSrc = cSrc;
+ ((PU_EMRPLGBLT) record)->xformSrc = xformSrc;
+ ((PU_EMRPLGBLT) record)->crBkColorSrc = crBkColorSrc;
+ ((PU_EMRPLGBLT) record)->iUsageSrc = iUsageSrc;
+ ((PU_EMRPLGBLT) record)->Mask = Mask;
+ ((PU_EMRPLGBLT) record)->iUsageMask = iUsageMask;
+ off = sizeof(U_EMRPLGBLT);
+ APPEND_PXBMISRC(record, U_EMRPLGBLT, cbBmi, Bmi, Px, cbImage, cbImage4);
+ APPEND_MSKBMISRC(record, U_EMRPLGBLT, cbMskBmi, MskBmi, Msk, cbMskImage, cbMskImage4);
+ }
+ return(record);
+}
+
+// U_EMRSETDIBITSTODEVICE_set 80
+/**
+ \brief Allocate and construct a U_EMR_SETDIBITSTODEVICE record.
+ \return pointer to U_EMR_SETDIBITSTODEVICE record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param Dest Destination UL corner in logical units
+ \param Src Source UL corner in logical units
+ \param cSrc Source W & H in logical units
+ \param iUsageSrc DIBColors Enumeration
+ \param iStartScan First scan line
+ \param cScans Number of scan lines
+ \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section)
+ \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+*/
+char *U_EMRSETDIBITSTODEVICE_set(
+ const U_RECTL rclBounds,
+ const U_POINTL Dest,
+ const U_POINTL Src,
+ const U_POINTL cSrc,
+ const uint32_t iUsageSrc,
+ const uint32_t iStartScan,
+ const uint32_t cScans,
+ const PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ char *Px
+ ){
+ char *record;
+ int irecsize;
+ int cbImage,cbImage4,cbBmi,off;
+
+ SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
+
+ irecsize = sizeof(U_EMRSETDIBITSTODEVICE) + cbBmi + cbImage4;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_SETDIBITSTODEVICE;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRSETDIBITSTODEVICE) record)->rclBounds = rclBounds;
+ ((PU_EMRSETDIBITSTODEVICE) record)->Dest = Dest;
+ ((PU_EMRSETDIBITSTODEVICE) record)->Src = Src;
+ ((PU_EMRSETDIBITSTODEVICE) record)->cSrc = cSrc;
+ ((PU_EMRSETDIBITSTODEVICE) record)->iUsageSrc = iUsageSrc;
+ ((PU_EMRSETDIBITSTODEVICE) record)->iStartScan = iStartScan;
+ ((PU_EMRSETDIBITSTODEVICE) record)->cScans = cScans;
+ off = sizeof(U_EMRSETDIBITSTODEVICE);
+ APPEND_PXBMISRC(record, U_EMRSETDIBITSTODEVICE, cbBmi, Bmi, Px, cbImage, cbImage4);
+ }
+ return(record);
+}
+
+// U_EMRSTRETCHDIBITS_set 81
+/**
+ \brief Allocate and construct a U_EMR_EMRSTRETCHDIBITS record.
+ \return pointer to U_EMR_EMRSTRETCHDIBITS record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param Dest Destination UL corner in logical units
+ \param cDest Destination W & H in logical units
+ \param Src Source UL corner in logical units
+ \param cSrc Source W & H in logical units
+ \param iUsageSrc DIBColors Enumeration
+ \param dwRop RasterOPeration Enumeration
+ \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section)
+ \param cbPx Size in bytes of pixel array (row STRIDE * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+*/
+char *U_EMRSTRETCHDIBITS_set(
+ const U_RECTL rclBounds,
+ const U_POINTL Dest,
+ const U_POINTL cDest,
+ const U_POINTL Src,
+ const U_POINTL cSrc,
+ const uint32_t iUsageSrc,
+ const uint32_t dwRop,
+ const PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ char *Px
+ ){
+ char *record;
+ int irecsize;
+ int cbImage,cbImage4,cbBmi,off;
+
+ SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
+
+ irecsize = sizeof(U_EMRSTRETCHDIBITS) + cbBmi + cbImage4;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_STRETCHDIBITS;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRSTRETCHDIBITS) record)->rclBounds = rclBounds;
+ ((PU_EMRSTRETCHDIBITS) record)->Dest = Dest;
+ ((PU_EMRSTRETCHDIBITS) record)->Src = Src;
+ ((PU_EMRSTRETCHDIBITS) record)->cSrc = cSrc;
+ ((PU_EMRSTRETCHDIBITS) record)->iUsageSrc = iUsageSrc;
+ ((PU_EMRSTRETCHDIBITS) record)->dwRop = dwRop;
+ ((PU_EMRSTRETCHDIBITS) record)->cDest = cDest;
+ off = sizeof(U_EMRSTRETCHDIBITS);
+ APPEND_PXBMISRC(record, U_EMRSTRETCHDIBITS, cbBmi, Bmi, Px, cbImage, cbImage4);
+ }
+ return(record);
+}
+
+// U_EMREXTCREATEFONTINDIRECTW_set 82
+/**
+ \brief Allocate and construct a U_EMR_EXTCREATEFONTINDIRECTW record.
+ Use extcreatefontindirectw_set() instead of calling this function directly.
+ \return pointer to U_EMR_EXTCREATEFONTINDIRECTW record, or NULL on error.
+ \param ihFont Index of the font in the EMF object table
+ \param elf Font parameters as U_LOGFONT
+ \param elfw Font parameters as U_LOGFONT_PANOSE
+*/
+char *U_EMREXTCREATEFONTINDIRECTW_set(
+ const uint32_t ihFont,
+ const char * elf,
+ const char * elfw
+ ){
+ char *record;
+ const char *cptr;
+ int irecsize;
+ int cbLf,off;
+
+ if((elf && elfw) || (!elf && !elfw))return(NULL); // ONE only must be passed
+ if(elf){ cbLf = sizeof(U_LOGFONT); cptr = elf; }
+ else { cbLf = sizeof(U_LOGFONT_PANOSE); cptr = elfw; }
+
+ irecsize = sizeof(U_EMR) + sizeof(uint32_t) + cbLf;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_EXTCREATEFONTINDIRECTW;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMREXTCREATEFONTINDIRECTW) record)->ihFont = ihFont;
+ off = sizeof(U_EMR) + sizeof(uint32_t);
+ memcpy(record + off, cptr, cbLf); // No need to add padding for either structure
+ }
+ return(record);
+}
+
+// U_EMREXTTEXTOUTA_set 83
+/**
+ \brief Allocate and construct a U_EMR_EXTTEXTOUTA record.
+ \return pointer to U_EMR_EXTTEXTOUTA record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param iGraphicsMode Graphics mode Enumeration
+ \param exScale scale to 0.01 mm units ( only if iGraphicsMode & GM_COMPATIBLE)
+ \param eyScale scale to 0.01 mm units ( only if iGraphicsMode & GM_COMPATIBLE)
+ \param emrtext Text parameters
+*/
+char *U_EMREXTTEXTOUTA_set(
+ const U_RECTL rclBounds,
+ const uint32_t iGraphicsMode,
+ const U_FLOAT exScale,
+ const U_FLOAT eyScale,
+ const PU_EMRTEXT emrtext
+ ){
+ return(U_EMR_CORE8_set(U_EMR_EXTTEXTOUTA,rclBounds, iGraphicsMode, exScale, eyScale,emrtext));
+}
+
+// U_EMREXTTEXTOUTW_set 84
+/**
+ \brief Allocate and construct a U_EMR_EXTTEXTOUTW record.
+ \return pointer to U_EMR_EXTTEXTOUTW record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param iGraphicsMode Graphics mode Enumeration
+ \param exScale scale to 0.01 mm units ( only if iGraphicsMode & GM_COMPATIBLE)
+ \param eyScale scale to 0.01 mm units ( only if iGraphicsMode & GM_COMPATIBLE)
+ \param emrtext Text parameters
+*/
+char *U_EMREXTTEXTOUTW_set(
+ const U_RECTL rclBounds,
+ const uint32_t iGraphicsMode,
+ const U_FLOAT exScale,
+ const U_FLOAT eyScale,
+ const PU_EMRTEXT emrtext
+ ){
+ return(U_EMR_CORE8_set(U_EMR_EXTTEXTOUTW,rclBounds, iGraphicsMode, exScale, eyScale,emrtext));
+}
+
+// U_EMRPOLYBEZIER16_set 85
+/**
+ \brief Allocate and construct a U_EMR_POLYBEZIER16 record.
+ \return pointer to U_EMR_POLYBEZIER16 record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param cpts Number of POINT16 in array
+ \param points Array of POINT16
+*/
+char *U_EMRPOLYBEZIER16_set(
+ const U_RECTL rclBounds,
+ const uint32_t cpts,
+ const U_POINT16 *points
+ ){
+ return(U_EMR_CORE6_set(U_EMR_POLYBEZIER16, rclBounds, cpts, points));
+}
+
+// U_EMRPOLYGON16_set 86
+/**
+ \brief Allocate and construct a U_EMR_POLYGON16 record.
+ \return pointer to U_EMR_POLYGON16 record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param cpts Number of POINT16 in array
+ \param points Array of POINT16
+*/
+char *U_EMRPOLYGON16_set(
+ const U_RECTL rclBounds,
+ const uint32_t cpts,
+ const U_POINT16 *points
+ ){
+ return(U_EMR_CORE6_set(U_EMR_POLYGON16, rclBounds, cpts, points));
+}
+
+// U_EMRPOLYLINE16_set 87
+/**
+ \brief Allocate and construct a U_EMR_POLYLINE16 record.
+ \return pointer to U_EMR_POLYLINE16 record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param cpts Number of POINT16 in array
+ \param points Array of POINT16
+*/
+char *U_EMRPOLYLINE16_set(
+ const U_RECTL rclBounds,
+ const uint32_t cpts,
+ const U_POINT16 *points
+ ){
+ return(U_EMR_CORE6_set(U_EMR_POLYLINE16, rclBounds, cpts, points));
+}
+
+// U_EMRPOLYBEZIERTO16_set 88
+/**
+ \brief Allocate and construct a U_EMR_POLYBEZIERTO record.
+ \return pointer to U_EMR_POLYBEZIERTO record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param cpts Number of POINT16 in array
+ \param points Array of POINT16
+*/
+char *U_EMRPOLYBEZIERTO16_set(
+ const U_RECTL rclBounds,
+ const uint32_t cpts,
+ const U_POINT16 *points
+ ){
+ return(U_EMR_CORE6_set(U_EMR_POLYBEZIERTO16, rclBounds, cpts, points));
+}
+
+// U_EMRPOLYLINETO16_set 89
+/**
+ \brief Allocate and construct a U_EMR_POLYLINETO record.
+ \return pointer to U_EMR_POLYLINETO record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param cpts Number of POINT16 in array
+ \param points Array of POINT16
+*/
+char *U_EMRPOLYLINETO16_set(
+ const U_RECTL rclBounds,
+ const uint32_t cpts,
+ const U_POINT16 *points
+ ){
+ return(U_EMR_CORE6_set(U_EMR_POLYLINETO16, rclBounds, cpts, points));
+}
+
+// U_EMRPOLYPOLYLINE16_set 90
+/**
+ \brief Allocate and construct a U_EMR_POLYPOLYLINE16 record.
+ \return pointer to U_EMR_POLYPOLYLINE16 record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param nPolys Number of elements in aPolyCounts
+ \param aPolyCounts Number of points in each poly (sequential)
+ \param cpts Number of POINT16 in array
+ \param points Array of POINT16
+*/
+char *U_EMRPOLYPOLYLINE16_set(
+ const U_RECTL rclBounds,
+ const uint32_t nPolys,
+ const uint32_t *aPolyCounts,
+ const uint32_t cpts,
+ const U_POINT16 *points
+ ){
+ return(U_EMR_CORE10_set(U_EMR_POLYPOLYLINE16, rclBounds, nPolys, aPolyCounts,cpts, points));
+}
+
+// U_EMRPOLYPOLYGON16_set 91
+/**
+ \brief Allocate and construct a U_EMR_POLYPOLYGON16 record.
+ \return pointer to U_EMR_POLYPOLYGON16 record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param nPolys Number of elements in aPolyCounts
+ \param aPolyCounts Number of points in each poly (sequential)
+ \param cpts Number of POINT16 in array
+ \param points Array of POINT16
+*/
+char *U_EMRPOLYPOLYGON16_set(
+ const U_RECTL rclBounds,
+ const uint32_t nPolys,
+ const uint32_t *aPolyCounts,
+ const uint32_t cpts,
+ const U_POINT16 *points
+ ){
+ return(U_EMR_CORE10_set(U_EMR_POLYPOLYGON16, rclBounds, nPolys, aPolyCounts,cpts, points));
+}
+
+
+// U_EMRPOLYDRAW16_set 92
+/**
+ \brief Allocate and construct a U_EMR_POLYDRAW16 record.
+ \return pointer to U_EMR_POLYDRAW16 record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param cpts Number of U_POINTL objects
+ \param aptl Array of U_POINTL objects
+ \param abTypes Array of Point Enumeration
+*/
+char *U_EMRPOLYDRAW16_set(
+ const U_RECTL rclBounds,
+ const U_NUM_POINT16 cpts,
+ const U_POINT16 *aptl,
+ const uint8_t *abTypes
+ ){
+ char *record;
+ int irecsize;
+ int cbPoints, cbAbTypes, cbAbTypes4, off;
+
+ if(!cpts || !aptl || !abTypes)return(NULL);
+ cbPoints = cpts * sizeof(U_POINT16); // space for aptl
+ cbAbTypes = cpts; // number of abTypes (same array size, 1 byte each)
+ cbAbTypes4 = UP4(cbAbTypes); // space for abTypes
+ irecsize = sizeof(U_EMRPOLYDRAW16) + cbPoints + cbAbTypes4 - sizeof(U_POINT16) - 1;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_POLYDRAW16;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRPOLYDRAW16) record)->rclBounds = rclBounds;
+ ((PU_EMRPOLYDRAW16) record)->cpts = cpts;
+ off = sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(uint32_t); // offset to first variable part
+ memcpy(record+off,aptl,cbPoints);
+ off += cbPoints;
+ memcpy(record+off,abTypes,cbAbTypes);
+ off += cbAbTypes;
+ if(cbAbTypes4 > cbAbTypes){ memset(record+off,0,cbAbTypes4-cbAbTypes); } // keeps valgrind happy (initialize padding after byte array)
+ }
+ return(record);
+}
+
+// U_EMRCREATEMONOBRUSH_set 93
+/**
+ \brief Allocate and construct a U_EMR_CREATEMONOBRUSH record.
+ \return pointer to U_EMR_CREATEMONOBRUSH record, or NULL on error.
+ \param ihBrush Index to place object in EMF object table (this entry must not yet exist)
+ \param iUsage DIBcolors Enumeration
+ \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO + pixel array)
+ \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+*/
+char *U_EMRCREATEMONOBRUSH_set(
+ const uint32_t ihBrush,
+ const uint32_t iUsage,
+ const PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ const char *Px
+ ){
+ return(U_EMR_CORE12_set(U_EMR_CREATEMONOBRUSH,ihBrush,iUsage,Bmi,cbPx,Px));
+}
+
+// U_EMRCREATEDIBPATTERNBRUSHPT_set 94
+/**
+ \brief Allocate and construct a U_EMR_CREATEDIBPATTERNBRUSHPT record.
+ Use createdibpatternbrushpt_set() instead of calling this function directly.
+ \return pointer to U_EMR_CREATEDIBPATTERNBRUSHPT record, or NULL on error.
+ \param ihBrush Index to place object in EMF object table (this entry must not yet exist)
+ \param iUsage DIBcolors Enumeration
+ \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO + pixel array)
+ \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+*/
+char *U_EMRCREATEDIBPATTERNBRUSHPT_set(
+ const uint32_t ihBrush,
+ const uint32_t iUsage,
+ const PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ const char *Px
+ ){
+ return(U_EMR_CORE12_set(U_EMR_CREATEDIBPATTERNBRUSHPT,ihBrush,iUsage,Bmi,cbPx,Px));
+}
+
+
+// U_EMREXTCREATEPEN_set 95
+/**
+ \brief Allocate and construct a U_EMR_EXTCREATEPEN record.
+ Use extcreatepen_set() instead of calling this function directly.
+ \return pointer to U_EMR_EXTCREATEPEN record, or NULL on error.
+ \param ihPen ihPen Index to place object in EMF object table (this entry must not yet exist)
+ \param Bmi Bmi bitmapbuffer
+ \param cbPx cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ \param Px Px pixel array (NULL if cbPx == 0)
+ \param elp elp Pen parameters (Size is Variable!!!!)
+*/
+char *U_EMREXTCREATEPEN_set(
+ const uint32_t ihPen,
+ const PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ char *Px,
+ const PU_EXTLOGPEN elp
+ ){
+ char *record;
+ int cbImage,cbImage4,cbBmi,off;
+ int irecsize,cbStyleArray,cbElp;
+
+ if(!elp)return(NULL);
+
+ SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
+
+ cbStyleArray = elp->elpNumEntries * sizeof(U_STYLEENTRY); // space actually used by penstyle entries
+ // EXTLOGPEN is already included in EMREXTCREATEPEN, including the possibly unused first penstyle entry
+ if(cbStyleArray){
+ cbElp = sizeof(U_EXTLOGPEN) + cbStyleArray - sizeof(U_STYLEENTRY); // space actually used by elp
+ irecsize = sizeof(U_EMREXTCREATEPEN) + cbBmi + cbImage4 + cbStyleArray - sizeof(U_STYLEENTRY);
+ }
+ else {
+ cbElp = sizeof(U_EXTLOGPEN); // first U_STYLEENTRY is present but unused
+ irecsize = sizeof(U_EMREXTCREATEPEN) + cbBmi + cbImage4;
+ }
+ record = malloc(irecsize);
+
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_EXTCREATEPEN;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMREXTCREATEPEN) record)->ihPen = ihPen;
+ memcpy(&(((PU_EMREXTCREATEPEN) record)->elp),elp,cbElp);
+ if(cbStyleArray){
+ off = sizeof(U_EMREXTCREATEPEN) + cbStyleArray - sizeof(U_STYLEENTRY);
+ }
+ else {
+ off = sizeof(U_EMREXTCREATEPEN);
+ }
+ // Cannot use APPEND_PXBMISRC here because there is no "Src" in the field names
+ if(cbBmi){
+ memcpy(record + off, Bmi, cbBmi);
+ ((PU_EMREXTCREATEPEN) record)->offBmi = off;
+ ((PU_EMREXTCREATEPEN) record)->cbBmi = cbBmi;
+ off += cbBmi;
+ memcpy(record + off, Px, cbImage);
+ ((PU_EMREXTCREATEPEN) record)->offBits = off;
+ ((PU_EMREXTCREATEPEN) record)->cbBits = cbImage;
+ off += cbImage;
+ if(cbImage4 - cbImage){ memset(record + off, 0, cbImage4 - cbImage); }
+ }
+ else {
+ ((PU_EMREXTCREATEPEN) record)->cbBmi = 0;
+ ((PU_EMREXTCREATEPEN) record)->offBmi = 0;
+ ((PU_EMREXTCREATEPEN) record)->cbBits = 0;
+ ((PU_EMREXTCREATEPEN) record)->offBits = 0;
+ }
+ }
+ return(record);
+}
+
+// U_EMRPOLYTEXTOUTA_set 96 NOT IMPLEMENTED, denigrated after Windows NT
+// U_EMRPOLYTEXTOUTW_set 97 NOT IMPLEMENTED, denigrated after Windows NT
+
+// U_EMRSETICMMODE_set 98
+/**
+ \brief Allocate and construct a U_EMR_SETICMMODE record.
+ \return pointer to U_EMR_SETICMMODE record, or NULL on error.
+ \param iMode ICMMode Enumeration
+*/
+char *U_EMRSETICMMODE_set(
+ const uint32_t iMode
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SETICMMODE, iMode));
+}
+
+// U_EMRCREATECOLORSPACE_set 99
+/**
+ \brief Allocate and construct a U_EMR_CREATECOLORSPACE record.
+ Use createcolorspace_set() instead of calling this function directly.
+ \return pointer to U_EMR_CREATECOLORSPACE record, or NULL on error.
+ \param ihCS Index to place object in EMF object table (this entry must not yet exist)
+ \param lcs ColorSpace parameters
+*/
+char *U_EMRCREATECOLORSPACE_set(
+ const uint32_t ihCS,
+ const U_LOGCOLORSPACEA lcs
+ ){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRCREATECOLORSPACE);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_CREATECOLORSPACE;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRCREATECOLORSPACE) record)->ihCS = ihCS;
+ ((PU_EMRCREATECOLORSPACE) record)->lcs = lcs;
+ }
+ return(record);
+}
+
+// U_EMRSETCOLORSPACE_set 100
+/**
+ \brief Allocate and construct a U_EMR_SETCOLORSPACE record.
+ \return pointer to U_EMR_SETCOLORSPACE record, or NULL on error.
+ \param ihCS Index of object in EMF object table
+*/
+char *U_EMRSETCOLORSPACE_set(
+ const uint32_t ihCS
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SETCOLORSPACE, ihCS));
+}
+
+// U_EMRDELETECOLORSPACE_set 101
+/**
+ \brief Allocate and construct a U_EMR_DELETECOLORSPACE record.
+ \return pointer to U_EMR_DELETECOLORSPACE record, or NULL on error.
+ \param ihCS Index of object in EMF object table
+*/
+char *U_EMRDELETECOLORSPACE_set(
+ const uint32_t ihCS
+ ){
+ return(U_EMR_CORE3_set(U_EMR_DELETECOLORSPACE, ihCS));
+}
+
+// U_EMRGLSRECORD_set 102 Not implemented
+// U_EMRGLSBOUNDEDRECORD_set 103 Not implemented
+// U_EMRPIXELFORMAT_set 104
+/**
+ \brief Allocate and construct a U_EMR_PIXELFORMAT record.
+ \return pointer to U_EMR_PIXELFORMAT record, or NULL on error.
+ \param pfd PixelFormatDescriptor
+*/
+char *U_EMRPIXELFORMAT_set(
+ const U_PIXELFORMATDESCRIPTOR pfd
+ ){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRPIXELFORMAT);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_PIXELFORMAT;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRPIXELFORMAT) record)->pfd = pfd;
+ }
+ return(record);
+}
+// U_EMRDRAWESCAPE_set 105 Not implemented
+// U_EMREXTESCAPE_set 106 Not implemented
+// U_EMRUNDEF107_set 107 Not implemented
+
+// U_EMRSMALLTEXTOUT_set 108
+/**
+ \brief Allocate and construct a U_EMR_SMALLTEXTOUT record.
+ \return pointer to U_EMR_SMALLTEXTOUT record, or NULL on error.
+ \param Dest Where to draw the text
+ \param cChars Characters in TextString (not null terminated)
+ \param fuOptions ExtTextOutOptions Enumeration
+ \param iGraphicsMode GraphicsMode Enumeration
+ \param exScale scale on X axis
+ \param eyScale scale on Y axis
+ \param rclBounds OPTIONAL Bounding rectangle (absent when: fuOPtions & ETO_NO_U_RECT)
+ \param TextString text to output (fuOptions & ETO_SMALL_CHARS ? 8 bit : 16 bit)
+*/
+char *U_EMRSMALLTEXTOUT_set(
+ const U_POINTL Dest,
+ const U_NUM_STR cChars,
+ const uint32_t fuOptions,
+ const uint32_t iGraphicsMode,
+ const U_FLOAT exScale,
+ const U_FLOAT eyScale,
+ const U_RECTL rclBounds,
+ const char *TextString
+ ){
+ char *record;
+ int irecsize,cbString,cbString4,cbRectl,off;
+ int csize;
+
+ if( fuOptions & U_ETO_SMALL_CHARS ){ csize = 1; } // how many bytes per character
+ else { csize = 2; }
+ cbString = csize * cChars; // filled contents of the string buffer
+ cbString4 = UP4(cbString); // size of the variable string buffer
+ if(fuOptions & U_ETO_NO_RECT){ cbRectl = 0; } // size of the optional U_RECTL field
+ else { cbRectl = sizeof(U_RECTL); }
+
+ irecsize = sizeof(U_EMRSMALLTEXTOUT) + cbString4 + cbRectl;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_SMALLTEXTOUT;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRSMALLTEXTOUT) record)->Dest = Dest;
+ ((PU_EMRSMALLTEXTOUT) record)->cChars = cChars;
+ ((PU_EMRSMALLTEXTOUT) record)->fuOptions = fuOptions;
+ ((PU_EMRSMALLTEXTOUT) record)->iGraphicsMode = iGraphicsMode;
+ ((PU_EMRSMALLTEXTOUT) record)->exScale = exScale;
+ ((PU_EMRSMALLTEXTOUT) record)->eyScale = eyScale;
+ off = sizeof(U_EMRSMALLTEXTOUT); //offset to the start of the variable fields
+ if(cbRectl){
+ memcpy(record + off, &rclBounds, cbRectl);
+ off += cbRectl;
+ }
+ memcpy(record + off, TextString, cbString);
+ if(cbString < cbString4){
+ off += cbString;
+ memset(record + off, 0, cbString4 - cbString);
+ }
+ }
+ return(record);
+}
+
+// U_EMRFORCEUFIMAPPING_set 109 Not implemented
+// U_EMRNAMEDESCAPE_set 110 Not implemented
+// U_EMRCOLORCORRECTPALETTE_set 111 Not implemented
+// U_EMRSETICMPROFILEA_set 112 Not implemented
+// U_EMRSETICMPROFILEW_set 113 Not implemented
+
+// U_EMRALPHABLEND_set 114
+/**
+ \brief Allocate and construct a U_EMR_ALPHABLEND record.
+ \return pointer to U_EMR_ALPHABLEND record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param Dest Destination UL corner in logical units
+ \param cDest Destination width in logical units
+ \param Src Source UL corner in logical units
+ \param cSrc Src W & H in logical units
+ \param xformSrc Transform to apply to source
+ \param crBkColorSrc Background color
+ \param iUsageSrc DIBcolors Enumeration
+ \param Blend Blend function
+ \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section)
+ \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+*/
+char *U_EMRALPHABLEND_set(
+ const U_RECTL rclBounds,
+ const U_POINTL Dest,
+ const U_POINTL cDest,
+ const U_POINTL Src,
+ const U_POINTL cSrc,
+ const U_XFORM xformSrc,
+ const U_COLORREF crBkColorSrc,
+ const uint32_t iUsageSrc,
+ const U_BLEND Blend,
+ const PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ char *Px
+ ){
+ return(U_EMR_CORE13_set(U_EMR_ALPHABLEND,rclBounds,Dest,cDest,Src,cSrc,xformSrc,crBkColorSrc,iUsageSrc,*((uint32_t *) &Blend),Bmi,cbPx,Px));
+}
+
+// U_EMRSETLAYOUT_set 115
+/**
+ \brief Allocate and construct a U_EMR_SETLAYOUT record.
+ \return pointer to U_EMR_SETLAYOUT record, or NULL on error.
+ \param iMode Mirroring Enumeration
+*/
+char *U_EMRSETLAYOUT_set(uint32_t iMode){
+ return(U_EMR_CORE3_set(U_EMR_SETLAYOUT, iMode));
+}
+
+// U_EMRTRANSPARENTBLT_set 116
+/**
+ \brief Allocate and construct a U_EMR_TRANSPARENTBLT record.
+ \return pointer to U_EMR_TRANSPARENTBLT record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param Dest Destination UL corner in logical units
+ \param cDest Destination width in logical units
+ \param Src Source UL corner in logical units
+ \param cSrc Src W & H in logical units
+ \param xformSrc Transform to apply to source
+ \param crBkColorSrc Background color
+ \param iUsageSrc DIBcolors Enumeration
+ \param TColor Bitmap color to be treated as transparent
+ \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section)
+ \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+*/
+char *U_EMRTRANSPARENTBLT_set(
+ const U_RECTL rclBounds,
+ const U_POINTL Dest,
+ const U_POINTL cDest,
+ const U_POINTL Src,
+ const U_POINTL cSrc,
+ const U_XFORM xformSrc,
+ const U_COLORREF crBkColorSrc,
+ const uint32_t iUsageSrc,
+ const uint32_t TColor,
+ const PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ char *Px
+ ){
+ return(U_EMR_CORE13_set(U_EMR_TRANSPARENTBLT,rclBounds,Dest,cDest,Src,cSrc,xformSrc,crBkColorSrc,iUsageSrc,TColor,Bmi,cbPx,Px));
+}
+// U_EMRUNDEF117_set 117 Not implemented
+// U_EMRGRADIENTFILL_set 118
+/**
+ \brief Allocate and construct a U_EMR_TRANSPARENTBLT record.
+ \return pointer to U_EMR_TRANSPARENTBLT record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param nTriVert Number of TriVertex objects in TriVert
+ \param nGradObj Number of gradient triangle/rectangle objects
+ \param ulMode Gradientfill Enumeration (determines Triangle/Rectangle)
+ \param TriVert Array of TriVertex objects
+ \param GradObj Array of gradient objects (each has 2 [rect] or 3 [triangle] indices into TriVert array)
+
+There is an MS documentation or library problem for this record, as the size of the GradObj must always be set
+as if it was an array of U_GRADIENT3 objects for both rect and triangle. For horizontal and vertical gradients
+this means that there will be unused bytes at the end of the record. This is not what the documentation says,
+but it is how MS's libraries work.
+
+*/
+char *U_EMRGRADIENTFILL_set(
+ const U_RECTL rclBounds,
+ const U_NUM_TRIVERTEX nTriVert,
+ const U_NUM_GRADOBJ nGradObj,
+ const uint32_t ulMode,
+ const PU_TRIVERTEX TriVert,
+ const uint32_t *GradObj
+ ){
+ char *record;
+ unsigned int cbTriVert,cbGradObj,off;
+ unsigned int cbGradObjAlloc; /* larger than cbGradObj, because of problem described above */
+ int irecsize;
+
+ cbTriVert = sizeof(U_TRIVERTEX) * nTriVert; // all of the cb's will be a multiple of 4 bytes
+ if( ulMode == U_GRADIENT_FILL_TRIANGLE){ cbGradObj = sizeof(U_GRADIENT3) * nGradObj; }
+ else if(ulMode == U_GRADIENT_FILL_RECT_H ||
+ ulMode == U_GRADIENT_FILL_RECT_V){ cbGradObj = sizeof(U_GRADIENT4) * nGradObj; }
+ else { return(NULL); }
+ cbGradObjAlloc = sizeof(U_GRADIENT3) * nGradObj;
+
+ irecsize = sizeof(U_EMRGRADIENTFILL) + cbTriVert + cbGradObjAlloc;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_GRADIENTFILL;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRGRADIENTFILL) record)->rclBounds = rclBounds;
+ ((PU_EMRGRADIENTFILL) record)->nTriVert = nTriVert;
+ ((PU_EMRGRADIENTFILL) record)->nGradObj = nGradObj;
+ ((PU_EMRGRADIENTFILL) record)->ulMode = ulMode;
+ off = sizeof(U_EMRGRADIENTFILL); // offset to TriVert field
+ memcpy(record + off, TriVert, cbTriVert);
+ off += cbTriVert;
+ memcpy(record + off, GradObj, cbGradObj);
+ off += cbGradObj;
+ if(cbGradObjAlloc > cbGradObj){
+ memset(record+off,0,cbGradObjAlloc - cbGradObj);
+ }
+ }
+ return(record);
+}
+
+// U_EMRSETLINKEDUFIS_set 119 Not implemented
+// U_EMRSETTEXTJUSTIFICATION_set 120 Not implemented (denigrated)
+// U_EMRCOLORMATCHTOTARGETW_set 121 Not implemented
+
+// U_EMRCREATECOLORSPACEW_set 122
+/**
+ \brief Allocate and construct a U_EMR_CREATECOLORSPACEW record.
+ Use createcolorspacew_set() instead of calling this function directly.
+ \return pointer to U_EMR_CREATECOLORSPACEW record, or NULL on error.
+ \param ihCS Index to place object in EMF object table (this entry must not yet exist)
+ \param lcs ColorSpace parameters
+ \param dwFlags If low bit set Data is present
+ \param cbData Number of bytes of theData field.
+ \param Data (Optional, dwFlags & 1) color profile data
+*/
+char *U_EMRCREATECOLORSPACEW_set(
+ const uint32_t ihCS,
+ const U_LOGCOLORSPACEW lcs,
+ const uint32_t dwFlags,
+ const U_CBDATA cbData,
+ const uint8_t *Data
+ ){
+ char *record;
+ unsigned int cbData4,off;
+ int irecsize;
+
+ cbData4 = UP4(cbData); // buffer to hold Data
+ irecsize = sizeof(U_EMRCREATECOLORSPACEW) + cbData4;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_CREATECOLORSPACEW;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRCREATECOLORSPACEW) record)->ihCS = ihCS;
+ ((PU_EMRCREATECOLORSPACEW) record)->lcs = lcs;
+ ((PU_EMRCREATECOLORSPACEW) record)->dwFlags = dwFlags;
+ ((PU_EMRCREATECOLORSPACEW) record)->cbData = cbData;
+ off = sizeof(U_EMR) + sizeof(uint32_t) + sizeof(U_LOGCOLORSPACEW) + sizeof(uint32_t) + sizeof(U_CBDATA); // offset to Data field
+ memcpy(record + off, Data, cbData);
+ if(cbData < cbData4){
+ off += cbData;
+ memset(record + off,0,cbData4-cbData);
+ }
+ }
+ return(record);
+}
+
+
+#ifdef __cplusplus
+}
+#endif