From 14f607efe6cb318756d74604c3cd6810799b5434 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 31 Aug 2013 18:05:13 +0200 Subject: Move libuemf to a separate directory. Rename libunicode-convert to symbol_convert and put it in libuemf. (bzr r12490) --- src/libuemf/CMakeLists.txt | 23 + src/libuemf/Makefile_insert | 24 + src/libuemf/README | 5 + src/libuemf/makefile.in | 17 + src/libuemf/symbol_convert.c | 1008 +++++++ src/libuemf/symbol_convert.h | 51 + src/libuemf/uemf.c | 5523 +++++++++++++++++++++++++++++++++ src/libuemf/uemf.h | 2889 ++++++++++++++++++ src/libuemf/uemf_endian.c | 1783 +++++++++++ src/libuemf/uemf_endian.h | 37 + src/libuemf/uemf_print.c | 2358 +++++++++++++++ src/libuemf/uemf_print.h | 169 ++ src/libuemf/uemf_utf.c | 552 ++++ src/libuemf/uemf_utf.h | 53 + src/libuemf/uwmf.c | 6880 ++++++++++++++++++++++++++++++++++++++++++ src/libuemf/uwmf.h | 2492 +++++++++++++++ src/libuemf/uwmf_endian.c | 1772 +++++++++++ src/libuemf/uwmf_endian.h | 39 + src/libuemf/uwmf_print.c | 1616 ++++++++++ src/libuemf/uwmf_print.h | 48 + 20 files changed, 27339 insertions(+) create mode 100644 src/libuemf/CMakeLists.txt create mode 100644 src/libuemf/Makefile_insert create mode 100644 src/libuemf/README create mode 100644 src/libuemf/makefile.in create mode 100644 src/libuemf/symbol_convert.c create mode 100644 src/libuemf/symbol_convert.h create mode 100644 src/libuemf/uemf.c create mode 100644 src/libuemf/uemf.h create mode 100644 src/libuemf/uemf_endian.c create mode 100644 src/libuemf/uemf_endian.h create mode 100644 src/libuemf/uemf_print.c create mode 100644 src/libuemf/uemf_print.h create mode 100644 src/libuemf/uemf_utf.c create mode 100644 src/libuemf/uemf_utf.h create mode 100644 src/libuemf/uwmf.c create mode 100644 src/libuemf/uwmf.h create mode 100644 src/libuemf/uwmf_endian.c create mode 100644 src/libuemf/uwmf_endian.h create mode 100644 src/libuemf/uwmf_print.c create mode 100644 src/libuemf/uwmf_print.h (limited to 'src/libuemf') diff --git a/src/libuemf/CMakeLists.txt b/src/libuemf/CMakeLists.txt new file mode 100644 index 000000000..d7e757ad1 --- /dev/null +++ b/src/libuemf/CMakeLists.txt @@ -0,0 +1,23 @@ + +set(libuemf_SRC + symbol_convert.c + uemf.c + uemf_endian.c + uemf_print.c + uemf_utf.c + uwmf.c + uwmf_endian.c + uwmf_print.c + + # ------- + # Headers + uemf.h + uemf_endian.h + uemf_print.h + uemf_utf.h + uwmf.h + uwmf_endian.h + uwmf_print.h +) + +add_inkscape_lib(uemf_LIB "${libuemf_SRC}") diff --git a/src/libuemf/Makefile_insert b/src/libuemf/Makefile_insert new file mode 100644 index 000000000..ca14ed19f --- /dev/null +++ b/src/libuemf/Makefile_insert @@ -0,0 +1,24 @@ +## Makefile.am fragment sourced by src/Makefile.am. + +libuemf/all: libuemf.a + +libuemf/clean: + rm -f libuemf/libuemf.a $(libuemf_libuemf_a_OBJECTS) + +libuemf_libuemf_a_SOURCES = \ + libuemf/uemf.c \ + libuemf/uemf.h \ + libuemf/uemf_endian.c \ + libuemf/uemf_endian.h \ + libuemf/uemf_print.c \ + libuemf/uemf_print.h \ + libuemf/uemf_utf.c \ + libuemf/uemf_utf.h \ + libuemf/uwmf.c \ + libuemf/uwmf.h \ + libuemf/uwmf_endian.c \ + libuemf/uwmf_endian.h \ + libuemf/uwmf_print.c \ + libuemf/uwmf_print.h \ + libuemf/symbol_convert.c \ + libuemf/symbol_convert.h diff --git a/src/libuemf/README b/src/libuemf/README new file mode 100644 index 000000000..53e2469e3 --- /dev/null +++ b/src/libuemf/README @@ -0,0 +1,5 @@ +Theis directory contains the libUEMF library, +a cross-platform library for Windows Metafile and Enhanced Metafile +handling, created by David Mathog. + +http://sourceforge.net/projects/libuemf/ diff --git a/src/libuemf/makefile.in b/src/libuemf/makefile.in new file mode 100644 index 000000000..f1a595e1d --- /dev/null +++ b/src/libuemf/makefile.in @@ -0,0 +1,17 @@ +# Convenience stub makefile to call the real Makefile. + +@SET_MAKE@ + +OBJEXT = @OBJEXT@ + +# Explicit so that it's the default rule. +all: + cd .. && $(MAKE) libuemf/all + +clean %.a %.$(OBJEXT): + cd .. && $(MAKE) libuemf/$@ + +.PHONY: all clean + +.SUFFIXES: +.SUFFIXES: .a .$(OBJEXT) diff --git a/src/libuemf/symbol_convert.c b/src/libuemf/symbol_convert.c new file mode 100644 index 000000000..650f4332d --- /dev/null +++ b/src/libuemf/symbol_convert.c @@ -0,0 +1,1008 @@ +/** @file + * @brief Windows-only Enhanced Metafile input and output. + */ +/* Authors: + * David mathog + * + * Copyright (C) 2012 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + * + * References: + * see unicode-convert.h + * + * v1.4 08/21/2012 Changed this so that the incoming routines use uint32_t and the outgoing use uint16_t. This gets rid + * of wchar_t, which was different sizes on windows/linux, and required lots of ifdef's elsewhere in the code. + * v1.3 04/03/2012 Bullets were a problem. Symbol bullet -> Times New Roman Bullet looks OK, but + * it looked bad going the other way. Changed mapping Symbol bullet to 2219 (Bullet operator, math + * symbol.) That way Symbol bullet can map in and out, while other font bullet an remain in that + * font's bullet glyph. + * v1.2 03/26/2012 Introduced bug into SingleUnicodeToNon repaired. + * v1.1 03/25/2012 Changed ampersand mapping on Wingdings (to avoid normal Ampersand mapping + * to Wingdings ampersand when not intended. Fixed access bugs for when no conversion is + * mapped in UnicodeToNon and SingleUnicodeToNon + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include "symbol_convert.h" + + +static bool hold_symb=0; // if any of these change, (re)generate the map table +static bool hold_wing=0; +static bool hold_zdng=0; +static bool hold_pua=0; +static unsigned char *from_unicode=NULL; +static unsigned char *to_font=NULL; + +/* The following tables were created from the files + adobe-dingbats.enc.gz + adobe-symbol.enc.gz + adobe-standard.enc.gz + + which came as part of the X11-font-encodings rpm on Mandriva 2010. + The original source for the data must have been Adobe. + Some also from: + ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/ADOBE/symbol.txt + http://www.csn.ul.ie/~caolan/wingdings/proposal/ + www.renderx.com/Tests/zapf-dingbats.pdf + + The intent is as follows: + + on conversion from ASCII/extended -> Unicode use the appropriate table for + the font and change font + code (symbol, zapf dingbats, wingdings). + Going the other way, set up two transfer tables, + the first is unicode -> 0-FF values, and the seond is unicode -> cvt_to_font. + These tables are filled dingbats, wingdings, then symbols, so with the rightmost one getting + precedence if both contain the symbol. + + Whereever possible do NOT map two input characters to the same output character, use a slightly + off character if it is somewhat close and disambiguates. + +v 1.0.0 14-MAR-2012, David Mathog + +*/ + +static unsigned int wingdings_convert[256]={ + 0xFFFD, // 0x00 no replacement + 0xFFFD, // 0x01 no replacement + 0xFFFD, // 0x02 no replacement + 0xFFFD, // 0x03 no replacement + 0xFFFD, // 0x04 no replacement + 0xFFFD, // 0x05 no replacement + 0xFFFD, // 0x06 no replacement + 0xFFFD, // 0x07 no replacement + 0xFFFD, // 0x08 no replacement + 0xFFFD, // 0x09 no replacement + 0xFFFD, // 0x0A no replacement + 0xFFFD, // 0x0B no replacement + 0xFFFD, // 0x0C no replacement + 0xFFFD, // 0x0D no replacement + 0xFFFD, // 0x0E no replacement + 0xFFFD, // 0x0F no replacement + 0xFFFD, // 0x10 no replacement + 0xFFFD, // 0x11 no replacement + 0xFFFD, // 0x12 no replacement + 0xFFFD, // 0x13 no replacement + 0xFFFD, // 0x14 no replacement + 0xFFFD, // 0x15 no replacement + 0xFFFD, // 0x16 no replacement + 0xFFFD, // 0x17 no replacement + 0xFFFD, // 0x18 no replacement + 0xFFFD, // 0x19 no replacement + 0xFFFD, // 0x1A no replacement + 0xFFFD, // 0x1B no replacement + 0xFFFD, // 0x1C no replacement + 0xFFFD, // 0x1D no replacement + 0xFFFD, // 0x1E no replacement + 0xFFFD, // 0x1F no replacement + 0x0020, // 0x20 SPACE + 0x270E, // 0x21 LOWER RIGHT PENCIL (close, but not exact) + 0x2702, // 0x22 BLACK SCISSORS + 0x2701, // 0x23 UPPER BLADE SCISSORS + 0xFFFD, // 0x24 no replacement + 0xFFFD, // 0x25 no replacement + 0xFFFD, // 0x26 no replacement + 0xFFFD, // 0x27 no replacement + 0x260E, // 0x28 BLACK TELEPHONE + 0x2706, // 0x29 TELEPHONE LOCATION SIGN (close, but not exact) + 0x2709, // 0x2A ENVELOPE + 0x2709, // 0x2B ENVELOPE (close, but not exact) + 0xFFFD, // 0x2C no replacement + 0xFFFD, // 0x2D no replacement + 0xFFFD, // 0x2E no replacement + 0xFFFD, // 0x2F no replacement + 0xFFFD, // 0x30 no replacement + 0xFFFD, // 0x31 no replacement + 0xFFFD, // 0x32 no replacement + 0xFFFD, // 0x33 no replacement + 0xFFFD, // 0x34 no replacement + 0xFFFD, // 0x35 no replacement + 0x231B, // 0x36 HOURGLASS + 0x2328, // 0x37 KEYBOARD + 0xFFFD, // 0x38 no replacement + 0xFFFD, // 0x39 no replacement + 0xFFFD, // 0x3A no replacement + 0xFFFD, // 0x3B no replacement + 0xFFFD, // 0x3C no replacement + 0xFFFD, // 0x3D no replacement + 0x2707, // 0x3E TAPE DRIVE + 0x270D, // 0x3F WRITING HAND + 0x270D, // 0x40 WRITING HAND (close, but not exact) + 0x270C, // 0x41 VICTORY HAND + 0xFFFD, // 0x42 3 FINGER UP HAND (no replacement) + 0xFFFD, // 0x43 THUMBS UP HAND (no replacement) + 0xFFFD, // 0x44 THUMBS DOWN HAND (no replacement) + 0x261C, // 0x45 WHITE LEFT POINTING INDEX + 0x261E, // 0x46 WHITE RIGHT POINTING INDEX + 0x261D, // 0x47 WHITE UP POINTING INDEX + 0x261F, // 0x48 WHITE DOWN POINTING INDEX + 0xFFFD, // 0x49 OPEN HAND (no replacement) + 0x263A, // 0x4A WHITE SMILING FACE + 0x263A, // 0x4B WHITE SMILING FACE (close, but not exact) + 0x2639, // 0x4C WHITE FROWNING FACE + 0xFFFD, // 0x4D BOMB (no replacement. 1F4A3) + 0x2620, // 0x4E SKULL AND CROSSBONES + 0x2690, // 0x4F WHITE FLAG (not exact) + 0x2691, // 0x50 WHITE PENANT (use BLACK FLAG) + 0x2708, // 0x51 AIRPLANE + 0x263C, // 0x52 WHITE SUN WITH RAYS (close, but not exact) + 0x2602, // 0x53 RAINDROP (use UMBRELLA) + 0x2744, // 0x54 SNOWFLAKE + 0x271D, // 0x55 WHITE LATIN CROSS (use BLACK CROSS) + 0x271E, // 0x56 SHADOWED WHITE LATIN CROSS + 0x271F, // 0x57 CELTIC CROSS (use OUTLINED LATIN CROSS) + 0x2720, // 0x58 MALTESE CROSS + 0x2721, // 0x59 STAR OF DAVID + 0x262A, // 0x5A STAR AND CRESCENT + 0x262F, // 0x5B YIN YANG + 0x0950, // 0x5C DEVANGARI OM CORRECT|CLOSE: Perhaps PROPOSE SACRED OM ? + 0x2638, // 0x5D WHEEL OF DHARMA + 0x2648, // 0x5E ARIES + 0x2649, // 0x5F TAURUS + 0x264A, // 0x60 GEMINI + 0x264B, // 0x61 CANCER + 0x264C, // 0x62 LEO + 0x264D, // 0x63 VIRGO + 0x264E, // 0x64 LIBRA + 0x264F, // 0x65 SCORPIUS + 0x2650, // 0x66 SAGITTARIUS + 0x2651, // 0x67 CAPRICORN + 0x2652, // 0x68 AQUARIUS + 0x2653, // 0x69 PISCES + 0xFFFD, // 0x6A LOWER CASE AMPERSAND)?) (no replacement) + 0xFF06, // 0x6B AMPERSAND (use FULL WIDTH AMPERSAND, close, but not exact. Do NOT use 0026, or it maps normal Ampersands to Wingdings Ampersand) + 0x25CF, // 0x6C BLACK CIRCLE + 0x274D, // 0x6D SHADOWED WHITE CIRCLE (close, but not exact) + 0x25A0, // 0x6E BLACK SQUARE + 0x25A3, // 0x6F WHITE SQUARE IN BLACK RECTANGLE (use BLACK SQUSRE in WHITE SQUARE) + 0x25A1, // 0x70 WHITE SQUARE (close, but not exact) + 0x2751, // 0x71 LOWER RIGHT SHADOWED WHITE SQUARE + 0x2752, // 0x72 UPPER RIGHT SHADOWED WHITE SQUARE + 0x25CA, // 0x73 LOZENGE (close, but not exact) + 0x25CA, // 0x74 LOZENGE (close, but not exact) + 0x25C6, // 0x75 BLACK DIAMOND + 0x2756, // 0x76 BLACK DIAMOND MINUS WHITE X + 0x25C6, // 0x77 BLACK DIAMOND (close, but not exact) + 0x2327, // 0x78 X IN A RECTANGLE BOX + 0x2353, // 0x79 APL FUNCTIONAL SYMBOL QUAD UP CARET(close, but not exact) + 0x2318, // 0x7A PLACE OF INTEREST SIGN + 0x2740, // 0x7B WHITE FLORETTE (close, but not exact) + 0x273F, // 0x7C BLACK FLORETTE (close, but not exact) + 0x275D, // 0x7D HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT + 0x275E, // 0x7E HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT + 0xFFFD, // 0x7F unused + 0x24EA, // 0x80 CIRCLED DIGIT ZERO + 0x2460, // 0x81 CIRCLED DIGIT ONE + 0x2461, // 0x82 CIRCLED DIGIT TWO + 0x2462, // 0x83 CIRCLED DIGIT THREE + 0x2463, // 0x84 CIRCLED DIGIT FOUR + 0x2464, // 0x85 CIRCLED DIGIT FIVE + 0x2465, // 0x86 CIRCLED DIGIT SIX + 0x2466, // 0x87 CIRCLED DIGIT SEVEN + 0x2467, // 0x88 CIRCLED DIGIT EIGHT + 0x2468, // 0x89 CIRCLED DIGIT NINE + 0x2469, // 0x8A CIRCLED NUMBER TEN + 0xFFFD, // 0x8B no replacement + 0x2776, // 0x8C DINGBAT NEGATIVE CIRCLED DIGIT ONE + 0x2777, // 0x8D DINGBAT NEGATIVE CIRCLED DIGIT TWO + 0x2778, // 0x8E DINGBAT NEGATIVE CIRCLED DIGIT THREE + 0x2779, // 0x8F DINGBAT NEGATIVE CIRCLED DIGIT FOUR + 0x277A, // 0x90 DINGBAT NEGATIVE CIRCLED DIGIT FIVE + 0x277B, // 0x91 DINGBAT NEGATIVE CIRCLED DIGIT SIX + 0x277C, // 0x92 DINGBAT NEGATIVE CIRCLED DIGIT SEVEN + 0x277D, // 0x93 DINGBAT NEGATIVE CIRCLED DIGIT EIGHT + 0x277E, // 0x94 DINGBAT NEGATIVE CIRCLED DIGIT NINE + 0x277F, // 0x95 DINGBAT NEGATIVE CIRCLED NUMBER TEN + 0xFFFD, // 0x96 ROTATED FLORAL HEART BULLET (no good replacement) + 0xFFFD, // 0x97 REVERSED ROTATED FLORAL HEART BULLET (no good replacement) + 0xFFFD, // 0x98 REVERSED ROTATED FLORAL HEART BULLET (no good replacement) + 0xFFFD, // 0x99 ROTATED FLORAL HEART BULLET (no good replacement) + 0xFFFD, // 0x9A ROTATED FLORAL HEART BULLET (no good replacement) + 0xFFFD, // 0x9B REVERSED ROTATED FLORAL HEART BULLET (no good replacement) + 0xFFFD, // 0x9C REVERSED ROTATED FLORAL HEART BULLET (no good replacement) + 0xFFFD, // 0x9D ROTATED FLORAL HEART BULLET (no good replacement) + 0x2219, // 0x9E BULLET (use BULLET operator, so normal font BULLET will not convert to Symbol BULLET) + 0x25CF, // 0x9F BLACK CIRCLE (close, but not exact) + 0x25AA, // 0xA0 BLACK VERY SMALL SQUARE + 0x26AA, // 0xA1 WHITE CIRCLE (use MEDIUM WHITE CIRCLE) + 0x25CB, // 0xA2 HEAVY WHITE CIRCLE (use WHITE CIRCLE) + 0x25CD, // 0xA3 HEAVIEST CIRCLE (use CIRCLE WITH VERTICAL FILL) + 0x25C9, // 0xA4 CIRCLE WITH A CENTRAL DOT (close, dot much bigger) + 0x25CE, // 0xA5 BULLSEYE + 0x274D, // 0xA6 SHADOWED WHITE CIRCLE (close, but not exact) + 0xFFED, // 0xA7 BLACK SMALL SQUARE + 0x2610, // 0xA8 WHITE SQUARE (close, but not exact, different fro 25A1) + 0xFFFD, // 0xA9 no replacement + 0x2726, // 0xAA BLACK FOUR POINTED STAR MAYBE + 0x2605, // 0xAB BLACK STAR + 0x2736, // 0xAC SIX POINTED BLACK STAR + 0x2737, // 0xAD EIGHT POINTED RECTILINEAR BLACK STAR + 0x2738, // 0xAE TWELVE POINTED BLACK STAR + 0x2735, // 0xAF EIGHT POINTED PINWHEEL STAR + 0xFFFD, // 0xB0 no replacement + 0xFFFD, // 0xB1 no replacement + 0x2727, // 0xB2 WHITE FOUR POINTED STAR + 0x2726, // 0xB3 ROTATED WHITE FOUR POINTED STAR (use BLACK FOUR POINTED STAR) + 0xFFFD, // 0xB4 REPLACEMENT CHARACTER (close, but not exact) + 0x272A, // 0xB5 CIRCLED WHITE STAR + 0x2730, // 0xB6 SHADOWED WHITE STAR + 0xFFFD, // 0xB7 ANALOG CLOCK 1 (no replacement) + 0xFFFD, // 0xB8 ANALOG CLOCK 2 (no replacement) + 0xFFFD, // 0xB9 ANALOG CLOCK 3 (no replacement) + 0xFFFD, // 0xBA ANALOG CLOCK 4 (no replacement) + 0xFFFD, // 0xBB ANALOG CLOCK 5 (no replacement) + 0xFFFD, // 0xBC ANALOG CLOCK 6 (no replacement) + 0xFFFD, // 0xBD ANALOG CLOCK 7 (no replacement) + 0xFFFD, // 0xBE ANALOG CLOCK 8 (no replacement) + 0xFFFD, // 0xBF ANALOG CLOCK 9 (no replacement) + 0xFFFD, // 0xC0 ANALOG CLOCK 10 (no replacement) + 0xFFFD, // 0xC1 ANALOG CLOCK 11 (no replacement) + 0xFFFD, // 0xC2 ANALOG CLOCK 12 (no replacement) + 0x21B2, // 0xC3 TURN ARROW DOWN AND LEFT (Meaning close, shape differs) + 0x21B3, // 0xC4 TURN ARROW DOWN AND RIGHT (Meaning close, shape differs) + 0x21B0, // 0xC5 TURN ARROW UP AND LEFT (Meaning close, shape differs) + 0x21B1, // 0xC6 TURN ARROW UP AND RIGHT (Meaning close, shape differs) + 0x2B11, // 0xC7 TURN ARROW LEFT AND UP (Meaning close, shape differs) + 0x2B0F, // 0xC8 TURN ARROW RIGHT AND UP (Meaning close, shape differs) + 0x2B10, // 0xC9 TURN ARROW LEFT AND DOWN (Meaning close, shape differs) + 0x2B0E, // 0xCA TURN ARROW RIGHT AND DOWN (Meaning close, shape differs) + 0xFFFD, // 0xCB no replacement + 0xFFFD, // 0xCC no replacement + 0xFFFD, // 0xCD no replacement + 0xFFFD, // 0xCE no replacement + 0xFFFD, // 0xCF no replacement + 0xFFFD, // 0xD0 no replacement + 0xFFFD, // 0xD1 no replacement + 0xFFFD, // 0xD2 no replacement + 0xFFFD, // 0xD3 no replacement + 0xFFFD, // 0xD4 no replacement + 0x232B, // 0xD5 ERASE TO THE LEFT + 0x2326, // 0xD6 ERASE TO THE RIGHT + 0x25C0, // 0xD7 THREE-D LIGHTED LEFT ARROWHEAD (Use BLACK LEFT TRIANGLE) + 0x25B6, // 0xD8 THREE-D LIGHTED RIGHT ARROWHEAD (Use BLACK RIGHT TRIANGLE, 27A2 is exact but has no other directions) + 0x25B2, // 0xD9 THREE-D LIGHTED UP ARROWHEAD (Use BLACK UP TRIANGLE) + 0x25BC, // 0xDA THREE-D LIGHTED DOWN ARROWHEAD (Use BLACK DOWN TRIANGLE) + 0xFFFD, // 0xDB no replacement + 0x27B2, // 0xDC CIRCLED HEAVY WHITE RIGHTWARDS ARROW + 0xFFFD, // 0xDD no replacement + 0xFFFD, // 0xDE no replacement + 0x2190, // 0xDF LEFT ARROW + 0x2192, // 0xE0 RIGHT ARROW + 0x2191, // 0xE1 UP ARROW + 0x2193, // 0xE2 DOWN ARROW + 0x2196, // 0xE3 UPPER LEFT ARROW + 0x2197, // 0xE4 UPPER RIGHT ARROW + 0x2199, // 0xE5 LOWER LEFT ARROW + 0x2198, // 0xE6 LOWER RIGHT ARROW + 0x2B05, // 0xE7 HEAVY LEFT BLACK ARROW (same as regular BLACK ARROW) + 0x2B08, // 0xE8 HEAVY RIGHT BLACK ARROW (same as regular BLACK ARROW) + 0x2B06, // 0xE9 HEAVY UP BLACK ARROW (no equiv BLACK ARROW) + 0x2B07, // 0xEA HEAVY DOWN BLACK ARROW (same as regular BLACK ARROW) + 0x2B09, // 0xEB HEAVY UPPER LEFT BLACK ARROW same as regular BLACK ARROW) + 0x2B08, // 0xEC HEAVY UPPER RIGHT BLACK ARROW same as regular BLACK ARROW) + 0x2B0B, // 0xED HEAVY LOWER LEFT BLACK ARROW (same as regular BLACK ARROW) + 0x2B0A, // 0xEE HEAVY LOWER RIGHT BLACK ARROW (same as regular BLACK ARROW) + 0x21E6, // 0xEF LEFTWARDS WHITE ARROW + 0x21E8, // 0xF0 RIGHTWARDS WHITE ARROW + 0x21E7, // 0xF1 UPWARDS WHITE ARROW + 0x21E9, // 0xF2 DOWNWARDS WHITE ARROW + 0x21D4, // 0xF3 LEFT RIGHT DOUBLE ARROW + 0x21D5, // 0xF4 UP DOWN DOUBLE ARROW + 0x21D6, // 0xF5 NORTH WEST DOUBLE ARROW (close, but not exact) + 0x21D7, // 0xF6 NORTH EAST DOUBLE ARROW (close, but not exact) + 0x21D9, // 0xF7 SOUTH WEST DOUBLE ARROW (close, but not exact) + 0x21D8, // 0xF8 SOUTH EAST DOUBLE ARROW (close, but not exact) + 0xFFFD, // 0xF9 no replacement + 0xFFFD, // 0xFA no replacement + 0x2717, // 0xFB BALLOT X + 0x2713, // 0xFC CHECK MARK + 0x2612, // 0xFD BALLOT BOX WITH X + 0x2611, // 0xFE BALLOT BOX WITH CHECK + 0xFFFD // 0xFF no replacement +}; + +/* characters from zapf dingbat font, conversion to a unicode font. Change both the + code and the font on conversion. These are untested as the development machine did + not have the font installed. */ +static unsigned int dingbats_convert[256]={ + 0xFFFD, // 0x00 no replacement + 0xFFFD, // 0x01 no replacement + 0xFFFD, // 0x02 no replacement + 0xFFFD, // 0x03 no replacement + 0xFFFD, // 0x04 no replacement + 0xFFFD, // 0x05 no replacement + 0xFFFD, // 0x06 no replacement + 0xFFFD, // 0x07 no replacement + 0xFFFD, // 0x08 no replacement + 0xFFFD, // 0x09 no replacement + 0xFFFD, // 0x0A no replacement + 0xFFFD, // 0x0B no replacement + 0xFFFD, // 0x0C no replacement + 0xFFFD, // 0x0D no replacement + 0xFFFD, // 0x0E no replacement + 0xFFFD, // 0x0F no replacement + 0xFFFD, // 0x10 no replacement + 0xFFFD, // 0x11 no replacement + 0xFFFD, // 0x12 no replacement + 0xFFFD, // 0x13 no replacement + 0xFFFD, // 0x14 no replacement + 0xFFFD, // 0x15 no replacement + 0xFFFD, // 0x16 no replacement + 0xFFFD, // 0x17 no replacement + 0xFFFD, // 0x18 no replacement + 0xFFFD, // 0x19 no replacement + 0xFFFD, // 0x1A no replacement + 0xFFFD, // 0x1B no replacement + 0xFFFD, // 0x1C no replacement + 0xFFFD, // 0x1D no replacement + 0xFFFD, // 0x1E no replacement + 0xFFFD, // 0x1F no replacement + 0x0020, // 0x20 SPACE + 0x2701, // 0x21 UPPER BLADE SCISSORS + 0x2702, // 0x22 BLACK SCISSORS + 0x2703, // 0x23 LOWER BLADE SCISSORS + 0x2704, // 0x24 WHITE SCISSORS + 0x260E, // 0x25 BLACK TELEPHONE + 0x2706, // 0x26 TELEPHONE LOCATION SIGN + 0x2707, // 0x27 TAPE DRIVE + 0x2708, // 0x28 AIRPLANE + 0x2709, // 0x29 ENVELOPE + 0x261B, // 0x2A BLACK RIGHT POINTING INDEX + 0x261E, // 0x2B WHITE RIGHT POINTING INDEX + 0x270C, // 0x2C VICTORY HAND + 0x270D, // 0x2D WRITING HAND + 0x270E, // 0x2E LOWER RIGHT PENCIL + 0x270F, // 0x2F PENCIL + 0x2710, // 0x30 UPPER RIGHT PENCIL + 0x2711, // 0x31 WHITE NIB + 0x2712, // 0x32 BLACK NIB + 0x2713, // 0x33 CHECK MARK + 0x2714, // 0x34 HEAVY CHECK MARK + 0x2715, // 0x35 MULTIPLICATION X + 0x2716, // 0x36 HEAVY MULTIPLICATION X + 0x2717, // 0x37 BALLOT X + 0x2718, // 0x38 HEAVY BALLOT X + 0x2719, // 0x39 OUTLINED GREEK CROSS + 0x271A, // 0x3A HEAVY GREEK CROSS + 0x271B, // 0x3B OPEN CENTRE CROSS + 0x271C, // 0x3C HEAVY OPEN CENTRE CROSS + 0x271D, // 0x3D LATIN CROSS + 0x271E, // 0x3E SHADOWED WHITE LATIN CROSS + 0x271F, // 0x3F OUTLINED LATIN CROSS + 0x2720, // 0x40 MALTESE CROSS + 0x2721, // 0x41 STAR OF DAVID + 0x2722, // 0x42 FOUR TEARDROP-SPOKED ASTERISK + 0x2723, // 0x43 FOUR BALLOON-SPOKED ASTERISK + 0x2724, // 0x44 HEAVY FOUR BALLOON-SPOKED ASTERISK + 0x2725, // 0x45 FOUR CLUB-SPOKED ASTERISK + 0x2726, // 0x46 BLACK FOUR POINTED STAR + 0x2727, // 0x47 WHITE FOUR POINTED STAR + 0x2605, // 0x48 BLACK STAR + 0x2729, // 0x49 STRESS OUTLINED WHITE STAR + 0x272A, // 0x4A CIRCLED WHITE STAR + 0x272B, // 0x4B OPEN CENTRE BLACK STAR + 0x272C, // 0x4C BLACK CENTRE WHITE STAR + 0x272D, // 0x4D OUTLINED BLACK STAR + 0x272E, // 0x4E HEAVY OUTLINED BLACK STAR + 0x272F, // 0x4F PINWHEEL STAR + 0x2730, // 0x50 SHADOWED WHITE STAR + 0x2731, // 0x51 HEAVY ASTERISK + 0x2732, // 0x52 OPEN CENTRE ASTERISK + 0x2733, // 0x53 EIGHT SPOKED ASTERISK + 0x2734, // 0x54 EIGHT POINTED BLACK STAR + 0x2735, // 0x55 EIGHT POINTED PINWHEEL STAR + 0x2736, // 0x56 SIX POINTED BLACK STAR + 0x2737, // 0x57 EIGHT POINTED RECTILINEAR BLACK STAR + 0x2738, // 0x58 HEAVY EIGHT POINTED RECTILINEAR BLACK STAR + 0x2739, // 0x59 TWELVE POINTED BLACK STAR + 0x273A, // 0x5A SIXTEEN POINTED ASTERISK + 0x273B, // 0x5B TEARDROP-SPOKED ASTERISK + 0x273C, // 0x5C OPEN CENTRE TEARDROP-SPOKED ASTERISK + 0x273D, // 0x5D HEAVY TEARDROP-SPOKED ASTERISK + 0x273E, // 0x5E SIX PETALLED BLACK AND WHITE FLORETTE + 0x273F, // 0x5F BLACK FLORETTE + 0x2740, // 0x60 WHITE FLORETTE + 0x2741, // 0x61 EIGHT PETALLED OUTLINED BLACK FLORETTE + 0x2742, // 0x62 CIRCLED OPEN CENTRE EIGHT POINTED STAR + 0x2743, // 0x63 HEAVY TEARDROP-SPOKED PINWHEEL ASTERISK + 0x2744, // 0x64 SNOWFLAKE + 0x2745, // 0x65 TIGHT TRIFOLIATE SNOWFLAKE + 0x2746, // 0x66 HEAVY CHEVRON SNOWFLAKE + 0x2747, // 0x67 SPARKLE + 0x2748, // 0x68 HEAVY SPARKLE + 0x2749, // 0x69 BALLOON-SPOKED ASTERISK + 0x274A, // 0x6A EIGHT TEARDROP-SPOKED PROPELLER ASTERISK + 0x274B, // 0x6B HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK + 0x25CF, // 0x6C BLACK CIRCLE + 0x274D, // 0x6D SHADOWED WHITE CIRCLE + 0x25A0, // 0x6E BLACK SQUARE + 0x274F, // 0x6F LOWER RIGHT DROP-SHADOWED WHITE SQUARE + 0x2750, // 0x70 UPPER RIGHT DROP-SHADOWED WHITE SQUARE + 0x2751, // 0x71 LOWER RIGHT SHADOWED WHITE SQUARE + 0x2752, // 0x72 UPPER RIGHT SHADOWED WHITE SQUARE + 0x25B2, // 0x73 BLACK UP-POINTING TRIANGLE + 0x25BC, // 0x74 BLACK DOWN-POINTING TRIANGLE + 0x25C6, // 0x75 BLACK DIAMOND + 0x2756, // 0x76 BLACK DIAMOND MINUS WHITE X + 0x25D7, // 0x77 RIGHT HALF BLACK CIRCLE + 0x2758, // 0x78 LIGHT VERTICAL BAR + 0x2759, // 0x79 MEDIUM VERTICAL BAR + 0x275A, // 0x7A HEAVY VERTICAL BAR + 0x275B, // 0x7B HEAVY SINGLE TURNED COMMA QUOTATION MARK ORNAMENT + 0x275C, // 0x7C HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT + 0x275D, // 0x7D HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT + 0x275E, // 0x7E HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT + 0xFFFD, // 0x7F no replacement + 0xF8D7, // 0x80 MEDIUM LEFT PARENTHESIS ORNAMENT + 0xF8D8, // 0x81 MEDIUM RIGHT PARENTHESIS ORNAMENT + 0xF8D9, // 0x82 MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT + 0xF8DA, // 0x83 MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT + 0xF8DB, // 0x84 MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT + 0xF8DC, // 0x85 MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT + 0xF8DD, // 0x86 HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT + 0xF8DE, // 0x87 HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT + 0xF8DF, // 0x88 HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT + 0xF8E0, // 0x89 HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT + 0xF8E1, // 0x8A LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT + 0xF8E2, // 0x8B LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT + 0xF8E3, // 0x8C MEDIUM LEFT CURLY BRACKET ORNAMENT + 0xF8E4, // 0x8D MEDIUM RIGHT CURLY BRACKET ORNAMENT + 0xFFFD, // 0x8E no replacement + 0xFFFD, // 0x8F no replacement + 0xFFFD, // 0x90 no replacement + 0xFFFD, // 0x91 no replacement + 0xFFFD, // 0x92 no replacement + 0xFFFD, // 0x93 no replacement + 0xFFFD, // 0x94 no replacement + 0xFFFD, // 0x95 no replacement + 0xFFFD, // 0x96 no replacement + 0xFFFD, // 0x97 no replacement + 0xFFFD, // 0x98 no replacement + 0xFFFD, // 0x99 no replacement + 0xFFFD, // 0x9A no replacement + 0xFFFD, // 0x9B no replacement + 0xFFFD, // 0x9C no replacement + 0xFFFD, // 0x9D no replacement + 0xFFFD, // 0x9E no replacement + 0xFFFD, // 0x9F no replacement + 0xFFFD, // 0xA0 no replacement + 0x2761, // 0xA1 CURVED STEM PARAGRAPH SIGN ORNAMENT + 0x2762, // 0xA2 HEAVY EXCLAMATION MARK ORNAMENT + 0x2763, // 0xA3 HEAVY HEART EXCLAMATION MARK ORNAMENT + 0x2764, // 0xA4 HEAVY BLACK HEART + 0x2765, // 0xA5 ROTATED HEAVY BLACK HEART BULLET + 0x2766, // 0xA6 FLORAL HEART + 0x2767, // 0xA7 ROTATED FLORAL HEART BULLET + 0x2663, // 0xA8 BLACK CLUB SUIT + 0x2666, // 0xA9 BLACK DIAMOND SUIT + 0x2665, // 0xAA BLACK HEART SUIT + 0x2660, // 0xAB BLACK SPADE SUIT + 0x2460, // 0xAC CIRCLED DIGIT ONE + 0x2461, // 0xAD CIRCLED DIGIT TWO + 0x2462, // 0xAE CIRCLED DIGIT THREE + 0x2463, // 0xAF CIRCLED DIGIT FOUR + 0x2464, // 0xB0 CIRCLED DIGIT FIVE + 0x2465, // 0xB1 CIRCLED DIGIT SIX + 0x2466, // 0xB2 CIRCLED DIGIT SEVEN + 0x2467, // 0xB3 CIRCLED DIGIT EIGHT + 0x2468, // 0xB4 CIRCLED DIGIT NINE + 0x2469, // 0xB5 CIRCLED NUMBER TEN + 0x2776, // 0xB6 DINGBAT NEGATIVE CIRCLED DIGIT ONE + 0x2777, // 0xB7 DINGBAT NEGATIVE CIRCLED DIGIT TWO + 0x2778, // 0xB8 DINGBAT NEGATIVE CIRCLED DIGIT THREE + 0x2779, // 0xB9 DINGBAT NEGATIVE CIRCLED DIGIT FOUR + 0x277A, // 0xBA DINGBAT NEGATIVE CIRCLED DIGIT FIVE + 0x277B, // 0xBB DINGBAT NEGATIVE CIRCLED DIGIT SIX + 0x277C, // 0xBC DINGBAT NEGATIVE CIRCLED DIGIT SEVEN + 0x277D, // 0xBD DINGBAT NEGATIVE CIRCLED DIGIT EIGHT + 0x277E, // 0xBE DINGBAT NEGATIVE CIRCLED DIGIT NINE + 0x277F, // 0xBF DINGBAT NEGATIVE CIRCLED NUMBER TEN + 0x2780, // 0xC0 DINGBAT CIRCLED SANS-SERIF DIGIT ONE + 0x2781, // 0xC1 DINGBAT CIRCLED SANS-SERIF DIGIT TWO + 0x2782, // 0xC2 DINGBAT CIRCLED SANS-SERIF DIGIT THREE + 0x2783, // 0xC3 DINGBAT CIRCLED SANS-SERIF DIGIT FOUR + 0x2784, // 0xC4 DINGBAT CIRCLED SANS-SERIF DIGIT FIVE + 0x2785, // 0xC5 DINGBAT CIRCLED SANS-SERIF DIGIT SIX + 0x2786, // 0xC6 DINGBAT CIRCLED SANS-SERIF DIGIT SEVEN + 0x2787, // 0xC7 DINGBAT CIRCLED SANS-SERIF DIGIT EIGHT + 0x2788, // 0xC8 DINGBAT CIRCLED SANS-SERIF DIGIT NINE + 0x2789, // 0xC9 DINGBAT CIRCLED SANS-SERIF NUMBER TEN + 0x278A, // 0xCA DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ONE + 0x278B, // 0xCB DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT TWO + 0x278C, // 0xCC DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT THREE + 0x278D, // 0xCD DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FOUR + 0x278E, // 0xCE DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FIVE + 0x278F, // 0xCF DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SIX + 0x2790, // 0xD0 DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SEVEN + 0x2791, // 0xD1 DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT EIGHT + 0x2792, // 0xD2 DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT NINE + 0x2793, // 0xD3 DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN + 0x2794, // 0xD4 HEAVY WIDE-HEADED RIGHTWARDS ARROW + 0x2192, // 0xD5 RIGHTWARDS ARROW + 0x2194, // 0xD6 LEFT RIGHT ARROW + 0x2195, // 0xD7 UP DOWN ARROW + 0x2798, // 0xD8 HEAVY SOUTH EAST ARROW + 0x2799, // 0xD9 HEAVY RIGHTWARDS ARROW + 0x279A, // 0xDA HEAVY NORTH EAST ARROW + 0x279B, // 0xDB DRAFTING POINT RIGHTWARDS ARROW + 0x279C, // 0xDC HEAVY ROUND-TIPPED RIGHTWARDS ARROW + 0x279D, // 0xDD TRIANGLE-HEADED RIGHTWARDS ARROW + 0x279E, // 0xDE HEAVY TRIANGLE-HEADED RIGHTWARDS ARROW + 0x279F, // 0xDF DASHED TRIANGLE-HEADED RIGHTWARDS ARROW + 0x27A0, // 0xE0 HEAVY DASHED TRIANGLE-HEADED RIGHTWARDS ARROW + 0x27A1, // 0xE1 BLACK RIGHTWARDS ARROW + 0x27A2, // 0xE2 THREE-D TOP-LIGHTED RIGHTWARDS ARROWHEAD + 0x27A3, // 0xE3 THREE-D BOTTOM-LIGHTED RIGHTWARDS ARROWHEAD + 0x27A4, // 0xE4 BLACK RIGHTWARDS ARROWHEAD + 0x27A5, // 0xE5 HEAVY BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW + 0x27A6, // 0xE6 HEAVY BLACK CURVED UPWARDS AND RIGHTWARDS ARROW + 0x27A7, // 0xE7 SQUAT BLACK RIGHTWARDS ARROW + 0x27A8, // 0xE8 HEAVY CONCAVE-POINTED BLACK RIGHTWARDS ARROW + 0x27A9, // 0xE9 RIGHT-SHADED WHITE RIGHTWARDS ARROW + 0x27AA, // 0xEA LEFT-SHADED WHITE RIGHTWARDS ARROW + 0x27AB, // 0xEB BACK-TILTED SHADOWED WHITE RIGHTWARDS ARROW + 0x27AC, // 0xEC FRONT-TILTED SHADOWED WHITE RIGHTWARDS ARROW + 0x27AD, // 0xED HEAVY LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW + 0x27AE, // 0xEE HEAVY UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW + 0x27AF, // 0xEF NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW + 0xFFFD, // 0xF0 no replacement + 0x27B1, // 0xF1 NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW + 0x27B2, // 0xF2 CIRCLED HEAVY WHITE RIGHTWARDS ARROW + 0x27B3, // 0xF3 WHITE-FEATHERED RIGHTWARDS ARROW + 0x27B4, // 0xF4 BLACK-FEATHERED SOUTH EAST ARROW + 0x27B5, // 0xF5 BLACK-FEATHERED RIGHTWARDS ARROW + 0x27B6, // 0xF6 BLACK-FEATHERED NORTH EAST ARROW + 0x27B7, // 0xF7 HEAVY BLACK-FEATHERED SOUTH EAST ARROW + 0x27B8, // 0xF8 HEAVY BLACK-FEATHERED RIGHTWARDS ARROW + 0x27B9, // 0xF9 HEAVY BLACK-FEATHERED NORTH EAST ARROW + 0x27BA, // 0xFA TEARDROP-BARBED RIGHTWARDS ARROW + 0x27BB, // 0xFB HEAVY TEARDROP-SHANKED RIGHTWARDS ARROW + 0x27BC, // 0xFC WEDGE-TAILED RIGHTWARDS ARROW + 0x27BD, // 0xFD HEAVY WEDGE-TAILED RIGHTWARDS ARROW + 0x27BE, // 0xFE OPEN-OUTLINED RIGHTWARDS ARROW + 0xFFFD // 0xFF no replacement +}; + +/* characters from symbol font, conversion to a unicode font. Change both the + code and the font on conversion. */ +static unsigned int symbol_convert[256]={ + 0xFFFD, // 0x00 no replacement + 0xFFFD, // 0x01 no replacement + 0xFFFD, // 0x02 no replacement + 0xFFFD, // 0x03 no replacement + 0xFFFD, // 0x04 no replacement + 0xFFFD, // 0x05 no replacement + 0xFFFD, // 0x06 no replacement + 0xFFFD, // 0x07 no replacement + 0xFFFD, // 0x08 no replacement + 0xFFFD, // 0x09 no replacement + 0xFFFD, // 0x0A no replacement + 0xFFFD, // 0x0B no replacement + 0xFFFD, // 0x0C no replacement + 0xFFFD, // 0x0D no replacement + 0xFFFD, // 0x0E no replacement + 0xFFFD, // 0x0F no replacement + 0xFFFD, // 0x10 no replacement + 0xFFFD, // 0x11 no replacement + 0xFFFD, // 0x12 no replacement + 0xFFFD, // 0x13 no replacement + 0xFFFD, // 0x14 no replacement + 0xFFFD, // 0x15 no replacement + 0xFFFD, // 0x16 no replacement + 0xFFFD, // 0x17 no replacement + 0xFFFD, // 0x18 no replacement + 0xFFFD, // 0x19 no replacement + 0xFFFD, // 0x1A no replacement + 0xFFFD, // 0x1B no replacement + 0xFFFD, // 0x1C no replacement + 0xFFFD, // 0x1D no replacement + 0xFFFD, // 0x1E no replacement + 0xFFFD, // 0x1F no replacement + 0x0020, // 0x20 SPACE + 0x0021, // 0x21 EXCLAMATION MARK + 0x2200, // 0x22 FOR ALL + 0x0023, // 0x23 NUMBER SIGN + 0x2203, // 0x24 THERE EXISTS + 0x0025, // 0x25 PERCENT SIGN + 0x0026, // 0x26 AMPERSAND + 0x220B, // 0x27 CONTAINS AS MEMBER + 0x0028, // 0x28 OPENING PARENTHESIS + 0x0029, // 0x29 CLOSING PARENTHESIS + 0x2217, // 0x2A ASTERISK OPERATOR + 0x002B, // 0x2B PLUS SIGN + 0x002C, // 0x2C COMMA + 0x2212, // 0x2D MINUS SIGN + 0x002E, // 0x2E PERIOD + 0x002F, // 0x2F SLASH + 0x0030, // 0x30 DIGIT ZERO + 0x0031, // 0x31 DIGIT ONE + 0x0032, // 0x32 DIGIT TWO + 0x0033, // 0x33 DIGIT THREE + 0x0034, // 0x34 DIGIT FOUR + 0x0035, // 0x35 DIGIT FIVE + 0x0036, // 0x36 DIGIT SIX + 0x0037, // 0x37 DIGIT SEVEN + 0x0038, // 0x38 DIGIT EIGHT + 0x0039, // 0x39 DIGIT NINE + 0x003A, // 0x3A COLON + 0x003B, // 0x3B SEMICOLON + 0x003C, // 0x3C LESS-THAN SIGN + 0x003D, // 0x3D EQUALS SIGN + 0x003E, // 0x3E GREATER-THAN SIGN + 0x003F, // 0x3F QUESTION MARK + 0x2245, // 0x40 APPROXIMATELY EQUAL TO + 0x0391, // 0x41 GREEK CAPITAL LETTER ALPHA + 0x0392, // 0x42 GREEK CAPITAL LETTER BETA + 0x03A7, // 0x43 GREEK CAPITAL LETTER CHI + 0x0394, // 0x44 GREEK CAPITAL LETTER DELTA + 0x0395, // 0x45 GREEK CAPITAL LETTER EPSILON + 0x03A6, // 0x46 GREEK CAPITAL LETTER PHI + 0x0393, // 0x47 GREEK CAPITAL LETTER GAMMA + 0x0397, // 0x48 GREEK CAPITAL LETTER ETA + 0x0399, // 0x49 GREEK CAPITAL LETTER IOTA + 0x03D1, // 0x4A GREEK SMALL LETTER SCRIPT THETA + 0x039A, // 0x4B GREEK CAPITAL LETTER KAPPA + 0x039B, // 0x4C GREEK CAPITAL LETTER LAMBDA + 0x039C, // 0x4D GREEK CAPITAL LETTER MU + 0x039D, // 0x4E GREEK CAPITAL LETTER NU + 0x039F, // 0x4F GREEK CAPITAL LETTER OMICRON + 0x03A0, // 0x50 GREEK CAPITAL LETTER PI + 0x0398, // 0x51 GREEK CAPITAL LETTER THETA + 0x03A1, // 0x52 GREEK CAPITAL LETTER RHO + 0x03A3, // 0x53 GREEK CAPITAL LETTER SIGMA + 0x03A4, // 0x54 GREEK CAPITAL LETTER TAU + 0x03A5, // 0x55 GREEK CAPITAL LETTER UPSILON + 0x03C2, // 0x56 GREEK SMALL LETTER FINAL SIGMA + 0x03A9, // 0x57 GREEK CAPITAL LETTER OMEGA + 0x039E, // 0x58 GREEK CAPITAL LETTER XI + 0x03A8, // 0x59 GREEK CAPITAL LETTER PSI + 0x0396, // 0x5A GREEK CAPITAL LETTER ZETA + 0x005B, // 0x5B OPENING SQUARE BRACKET + 0x2234, // 0x5C THEREFORE + 0x005D, // 0x5D CLOSING SQUARE BRACKET + 0x22A5, // 0x5E UP TACK + 0x005F, // 0x5F SPACING UNDERSCORE + 0x203E, // 0x60 SPACING OVERSCORE + 0x03B1, // 0x61 GREEK SMALL LETTER ALPHA + 0x03B2, // 0x62 GREEK SMALL LETTER BETA + 0x03C7, // 0x63 GREEK SMALL LETTER CHI + 0x03B4, // 0x64 GREEK SMALL LETTER DELTA + 0x03B5, // 0x65 GREEK SMALL LETTER EPSILON + 0x03C6, // 0x66 GREEK SMALL LETTER PHI + 0x03B3, // 0x67 GREEK SMALL LETTER GAMMA + 0x03B7, // 0x68 GREEK SMALL LETTER ETA + 0x03B9, // 0x69 GREEK SMALL LETTER IOTA + 0x03D5, // 0x6A GREEK SMALL LETTER SCRIPT PHI + 0x03BA, // 0x6B GREEK SMALL LETTER KAPPA + 0x03BB, // 0x6C GREEK SMALL LETTER LAMBDA + 0x03BC, // 0x6D GREEK SMALL LETTER MU + 0x03BD, // 0x6E GREEK SMALL LETTER NU + 0x03BF, // 0x6F GREEK SMALL LETTER OMICRON + 0x03C0, // 0x70 GREEK SMALL LETTER PI + 0x03B8, // 0x71 GREEK SMALL LETTER THETA + 0x03C1, // 0x72 GREEK SMALL LETTER RHO + 0x03C3, // 0x73 GREEK SMALL LETTER SIGMA + 0x03C4, // 0x74 GREEK SMALL LETTER TAU + 0x03C5, // 0x75 GREEK SMALL LETTER UPSILON + 0x03D6, // 0x76 GREEK SMALL LETTER OMEGA PI + 0x03C9, // 0x77 GREEK SMALL LETTER OMEGA + 0x03BE, // 0x78 GREEK SMALL LETTER XI + 0x03C8, // 0x79 GREEK SMALL LETTER PSI + 0x03B6, // 0x7A GREEK SMALL LETTER ZETA + 0x007B, // 0x7B OPENING CURLY BRACKET + 0x007C, // 0x7C VERTICAL BAR + 0x007D, // 0x7D CLOSING CURLY BRACKET + 0x223C, // 0x7E TILDE OPERATOR + 0xFFFD, // 0x7F no replacement + 0xFFFD, // 0x80 no replacement + 0xFFFD, // 0x81 no replacement + 0xFFFD, // 0x82 no replacement + 0xFFFD, // 0x83 no replacement + 0xFFFD, // 0x84 no replacement + 0xFFFD, // 0x85 no replacement + 0xFFFD, // 0x86 no replacement + 0xFFFD, // 0x87 no replacement + 0xFFFD, // 0x88 no replacement + 0xFFFD, // 0x89 no replacement + 0xFFFD, // 0x8A no replacement + 0xFFFD, // 0x8B no replacement + 0xFFFD, // 0x8C no replacement + 0xFFFD, // 0x8D no replacement + 0xFFFD, // 0x8E no replacement + 0xFFFD, // 0x8F no replacement + 0xFFFD, // 0x90 no replacement + 0xFFFD, // 0x91 no replacement + 0xFFFD, // 0x92 no replacement + 0xFFFD, // 0x93 no replacement + 0xFFFD, // 0x94 no replacement + 0xFFFD, // 0x95 no replacement + 0xFFFD, // 0x96 no replacement + 0xFFFD, // 0x97 no replacement + 0xFFFD, // 0x98 no replacement + 0xFFFD, // 0x99 no replacement + 0xFFFD, // 0x9A no replacement + 0xFFFD, // 0x9B no replacement + 0xFFFD, // 0x9C no replacement + 0xFFFD, // 0x9D no replacement + 0xFFFD, // 0x9E no replacement + 0xFFFD, // 0x9F no replacement + 0x20AC, // 0xA0 EURO SIGN + 0x03D2, // 0xA1 GREEK CAPITAL LETTER UPSILON HOOK + 0x2032, // 0xA2 PRIME + 0x2264, // 0xA3 LESS THAN OR EQUAL TO + 0x2044, // 0xA4 FRACTION SLASH + 0x221E, // 0xA5 INFINITY + 0x0192, // 0xA6 LATIN SMALL LETTER SCRIPT F + 0x2663, // 0xA7 BLACK CLUB SUIT + 0x2666, // 0xA8 BLACK DIAMOND SUIT + 0x2665, // 0xA9 BLACK HEART SUIT + 0x2660, // 0xAA BLACK SPADE SUIT + 0x2194, // 0xAB LEFT RIGHT ARROW + 0x2190, // 0xAC LEFT ARROW + 0x2191, // 0xAD UP ARROW + 0x2192, // 0xAE RIGHT ARROW + 0x2193, // 0xAF DOWN ARROW + 0x00B0, // 0xB0 DEGREE SIGN + 0x00B1, // 0xB1 PLUS-OR-MINUS SIGN + 0x2033, // 0xB2 DOUBLE PRIME + 0x2265, // 0xB3 GREATER THAN OR EQUAL TO + 0x00D7, // 0xB4 MULTIPLICATION SIGN + 0x221D, // 0xB5 PROPORTIONAL TO + 0x2202, // 0xB6 PARTIAL DIFFERENTIAL + 0x2219, // 0xB7 BULLET (use BULLET operator, so normal font BULLET will not convert to Symbol BULLET) + 0x00F7, // 0xB8 DIVISION SIGN + 0x2260, // 0xB9 NOT EQUAL TO + 0x2261, // 0xBA IDENTICAL TO + 0x2248, // 0xBB ALMOST EQUAL TO + 0x2026, // 0xBC HORIZONTAL ELLIPSIS + 0xF8E6, // 0xBD VERTICAL ARROW EXTENDER + 0xF8E7, // 0xBE HORIZONTAL ARROW EXTENDER + 0x21B5, // 0xBF DOWN ARROW WITH CORNER LEFT + 0x2135, // 0xC0 FIRST TRANSFINITE CARDINAL + 0x2111, // 0xC1 BLACK-LETTER I + 0x211C, // 0xC2 BLACK-LETTER R + 0x2118, // 0xC3 SCRIPT P + 0x2297, // 0xC4 CIRCLED TIMES + 0x2295, // 0xC5 CIRCLED PLUS + 0x2205, // 0xC6 EMPTY SET + 0x2229, // 0xC7 INTERSECTION + 0x222A, // 0xC8 UNION + 0x2283, // 0xC9 SUPERSET OF + 0x2287, // 0xCA SUPERSET OF OR EQUAL TO + 0x2284, // 0xCB NOT A SUBSET OF + 0x2282, // 0xCC SUBSET OF + 0x2286, // 0xCD SUBSET OF OR EQUAL TO + 0x2208, // 0xCE ELEMENT OF + 0x2209, // 0xCF NOT AN ELEMENT OF + 0x2220, // 0xD0 ANGLE + 0x2207, // 0xD1 NABLA + 0x00AE, // 0xD2 REGISTERED TRADE MARK SIGN + 0x00A9, // 0xD3 COPYRIGHT SIGN + 0x2122, // 0xD4 TRADEMARK + 0x220F, // 0xD5 N-ARY PRODUCT + 0x221A, // 0xD6 SQUARE ROOT + 0x22C5, // 0xD7 DOT OPERATOR + 0x00AC, // 0xD8 NOT SIGN + 0x2227, // 0xD9 LOGICAL AND + 0x2228, // 0xDA LOGICAL OR + 0x21D4, // 0xDB LEFT RIGHT DOUBLE ARROW + 0x21D0, // 0xDC LEFT DOUBLE ARROW + 0x21D1, // 0xDD UP DOUBLE ARROW + 0x21D2, // 0xDE RIGHT DOUBLE ARROW + 0x21D3, // 0xDF DOWN DOUBLE ARROW + 0x25CA, // 0xE0 LOZENGE + 0x2329, // 0xE1 BRA + 0x00AE, // 0xE2 REGISTERED TRADE MARK SIGN + 0x00A9, // 0xE3 COPYRIGHT SIGN + 0x2122, // 0xE4 TRADEMARK + 0x2211, // 0xE5 N-ARY SUMMATION + 0x239B, // 0xE6 LEFT PAREN TOP + 0x239C, // 0xE7 LEFT PAREN EXTENDER + 0x239D, // 0xE8 LEFT PAREN BOTTOM + 0x23A1, // 0xE9 LEFT SQUARE BRACKET TOP + 0x23A2, // 0xEA LEFT SQUARE BRACKET EXTENDER + 0x23A3, // 0xEB LEFT SQUARE BRACKET BOTTOM + 0x23A7, // 0xEC LEFT CURLY BRACKET TOP + 0x23A8, // 0xED LEFT CURLY BRACKET MID + 0x23A9, // 0xEE LEFT CURLY BRACKET BOTTOM + 0x23AA, // 0xEF CURLY BRACKET EXTENDER + 0xFFFD, // 0xF0 no replacement + 0x232A, // 0xF1 KET + 0x222B, // 0xF2 INTEGRAL + 0x2320, // 0xF3 TOP HALF INTEGRAL + 0x23AE, // 0xF4 INTEGRAL EXTENDER + 0x2321, // 0xF5 BOTTOM HALF INTEGRAL + 0x239E, // 0xF6 RIGHT PAREN TOP + 0x239F, // 0xF7 RIGHT PAREN EXTENDER + 0x23A0, // 0xF8 RIGHT PAREN BOTTOM + 0x23A4, // 0xF9 RIGHT SQUARE BRACKET TOP + 0x23A5, // 0xFA RIGHT SQUARE BRACKET EXTENDER + 0x23A6, // 0xFB RIGHT SQUARE BRACKET BOTTOM + 0x23AB, // 0xFC RIGHT CURLY BRACKET TOP + 0x23AC, // 0xFD RIGHT CURLY BRACKET MID + 0x23AD, // 0xFE RIGHT CURLY BRACKET BOTTOM + 0xFFFD // 0xFF no replacement +}; + +/* Use this for debugging */ +#include +void UC_log_message(char *text){ +FILE *fp; + fp=fopen("c:/temp/debug.txt","a"); + fprintf(fp,"%s",text); + fclose(fp); +} + + +//if any character is in the MS private use area (F020 through F0FF) subtract F000, for use with Symbol and Wingdings* from older software +void msdepua (uint32_t *text) +{ + while(*text){ + if(*text >= 0xF020 && *text <= 0xF0FF){ *text -= 0xF000; } + text++; + } +} + +//move characters up to MS private use area (F020 through F0FF) +void msrepua (uint16_t *text) +{ + while(*text){ + if(*text >= 0x20 && *text <= 0xFF){ *text += 0xF000; } + text++; + } +} + +// Returns the font classification code +int isNon(char *font){ +int retval; + if(!strcmp(font,"Symbol")){ + retval=CVTSYM; + } + else if(!strcmp(font,"Wingdings")){ + retval=CVTWDG; + } + else if(!strcmp(font,"ZapfDingbats")){ + retval=CVTZDG; + } + else { + retval=CVTNON; + } + return retval; +} + +// Returns the font name, given the classification code, or NULL +// The returned value must NOT be free'd +char *FontName(int code){ +char *cptr; +static char name_symbol[]="Symbol"; +static char name_wingdings[]="Wingdings"; +static char name_zapfdingbats[]="ZapfDingbats"; + switch(code){ + case CVTSYM: cptr=&name_symbol[0]; break; + case CVTWDG: cptr=&name_wingdings[0]; break; + case CVTZDG: cptr=&name_zapfdingbats[0]; break; + default: cptr=NULL; break; + } + return(cptr); +} + + +// Goes through the uint32_t string converting as needed. +int NonToUnicode(uint32_t *text, char *font){ +int retval; +unsigned int *convert_from=NULL; + retval=isNon(font); + switch(retval){ + case CVTSYM: convert_from=symbol_convert; break; + case CVTWDG: convert_from=wingdings_convert; break; + case CVTZDG: convert_from=dingbats_convert; break; + default: return(retval); //no conversion + } + while(*text){ + if(*text > 0xFF){ *text = 0xFFFD; } // out of range + else { *text = convert_from[*text]; } + text++; + } + return(retval); +} + +//returns 1 if tables are defines for UnicodeToNon translation +int CanUTN(void){ + if(from_unicode)return(1); + return(0); +} + +//translates from Unicode to some non unicode font until the target font changes. +//A target font change is like symbol -> wingdings, or symbol -> no translation +//returns the number of characters changed in ecount +//returns the enum value for the destination value in edest +void UnicodeToNon(uint16_t *text, int *ecount, int *edest){ +int count=0; +unsigned char target=0; + if(to_font){ + if(text && (target=to_font[*text])){ //There is actually something here to convert + while(*text && target==to_font[*text]){ + *text=from_unicode[*text] + (hold_pua ? 0xF000 : 0 ); + text++; + count++; + } + } + *ecount=count; + *edest=target; + } + else { // no translation tables, so change nothing and return + *ecount=0; + *edest=CVTNON; + } +} + +//Indicates the type of translation for a single character, Unicode to some non unicode +//returns the enum value for the destination value. +//If no translation tables are defined returns CVTNON (no conversions) +int SingleUnicodeToNon(uint16_t text){ + if(to_font){return(to_font[text]); } + else { return(CVTNON); } +} + +void table_filler(unsigned int *src, int code){ +unsigned int i; + for(i=0;i<0x100;i++){ + if(src[i] == 0xFFFD)continue; /* no mapping Unicode -> nonUnicode */ + if(src[i] == i)continue; /* no remapping of spaces back to spaces, for instance */ + from_unicode[src[i]] = i; + to_font[src[i]] = code; + } +} + +//possibly (re)generate the tables +void TableGen(bool new_symb,bool new_wing, bool new_zdng, bool new_pua){ +int i; + if(hold_symb != new_symb || hold_wing != new_wing + || hold_zdng != new_zdng || hold_pua != new_pua ){ // must (re)generate tables + if(!from_unicode){ // create arrays + from_unicode = (unsigned char *) calloc(0x10000,sizeof(char)); + to_font = (unsigned char *) calloc(0x10000,sizeof(char)); + // should check here for malloc error + } + hold_symb = new_symb; + hold_wing = new_wing; + hold_zdng = new_zdng; + hold_pua = new_pua; + for(i=0;i<0x10000;i++){ from_unicode[i] = to_font[i] = 0; } + if(hold_zdng)table_filler(&dingbats_convert[0],CVTZDG); + if(hold_wing)table_filler(&wingdings_convert[0],CVTWDG); + if(hold_symb)table_filler(&symbol_convert[0],CVTSYM); + } +} + +#ifdef __cplusplus +} +#endif diff --git a/src/libuemf/symbol_convert.h b/src/libuemf/symbol_convert.h new file mode 100644 index 000000000..ac1795092 --- /dev/null +++ b/src/libuemf/symbol_convert.h @@ -0,0 +1,51 @@ +/** @file + * @brief Enhanced Metafile Input/Output + */ +/* Authors: + * David Mathog + * + * Copyright (C) 2012 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef SEEN_UNICODE_CONVERT_H +#define SEEN_UNICODE_CONVERT_H +#include +#include +#include + + enum cvt_to_font {CVTNON, CVTSYM, CVTZDG, CVTWDG}; + + void msdepua(uint32_t *text); //translate down from Microsoft Private Use Area + void msrepua(uint16_t *text); //translate up to Microsoft Private Use Area + int isNon(char *font); //returns one of the cvt_to_font enum values + char *FontName(int code); //returns the font name (or NULL) given the enum code + int NonToUnicode(uint32_t *text, char *font); //nonunicode to Unicode translation + int CanUTN(void); // 1 if tables exist for UnicodeToNon translation + int SingleUnicodeToNon(uint16_t text); //retuns the enum value for this translation + void UnicodeToNon(uint16_t *text, int *ecount, int *edest); //translate Unicode to NonUnicode + void TableGen(bool symb, bool wing, bool zdng, bool pua); + +#ifdef __cplusplus +} +#endif + +#endif /* SEEN_UNICODE_CONVERT_H */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : + + diff --git a/src/libuemf/uemf.c b/src/libuemf/uemf.c new file mode 100644 index 000000000..b06990dbd --- /dev/null +++ b/src/libuemf/uemf.c @@ -0,0 +1,5523 @@ +/** + @file uemf.c 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.21 +Date: 20-FEB-2013 +Author: David Mathog, Biology Division, Caltech +email: mathog@caltech.edu +Copyright: 2013 David Mathog and California Institute of Technology (Caltech) +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include +#include +#include +#include // for INT_MAX, INT_MIN +#include // for U_ROUND() +#include /* for offsetof() macro */ +#if 0 +#include //Not actually used, looking for collisions +#include //Not actually used, looking for collisions +#include //Not actually used, looking for collisions +#endif +#include "uemf.h" +/* one prototype from uemf_endian. Put it here because end user should never need to see it, sno +not in uemf.h or uemf_endian.h */ +void U_swap2(void *ul, unsigned int count); + +/** + \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_MAX){ idx = 0; } + static char *U_WMR_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_WMR_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_BIMAPINFO, 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= 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){ + 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 *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. + 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. + + \return Number of entries in the color table. + \param Bmih char * pointer to the U_BITMAPINFOHEADER +*/ +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. + 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. + + \return Number of entries in the color table. + \param PU_BITMAPINFOHEADER pointer to to the U_BITMAPINFOHEADER +*/ +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 pEmr 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( + void *pEmr, + 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)((char *)pEmr + 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 { + *numCt = Bmih->biSizeImage; + *ct = NULL; + } + *px = (char *)((char *)pEmr + 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){ + 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> 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; jw || 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; inSize; + 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); + free(ehtl->table); + return(5); + } + memset(ehtl->table , 0, initsize * sizeof(uint32_t)); // zero all slots in the table + for(i=1; istack[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; istack[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 separeate R,G,B values. + Or use macro directly: cr = U_RGB(r,g,b). + \param red Red component + \param green Green component + \param blue Blue component + +*/ +U_COLORREF colorref_set( + uint8_t red, + uint8_t green, + uint8_t blue + ){ + U_COLORREF cr = (U_COLORREF){red , green, blue, 0}; + 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 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; ix < 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; ix < 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; + memset(lcsa.lcsFilename,0,U_MAX_PATH); // zero out the Filename field + strncpy(lcsa.lcsFilename,lcsFilename,U_MAX_PATH); + 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); + 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 + 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); + wchar16strncpy(lfp.elfStyle, elfStyle, U_LF_FACESIZE); + 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 retangle 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