diff options
Diffstat (limited to 'libmscgen')
41 files changed, 21238 insertions, 0 deletions
diff --git a/libmscgen/CMakeLists.txt b/libmscgen/CMakeLists.txt new file mode 100644 index 0000000..21b3278 --- /dev/null +++ b/libmscgen/CMakeLists.txt @@ -0,0 +1,40 @@ +set(CMAKE_C_FLAGS "-DHAVE_STDINT_H -DHAVE_LIMITS_H ${CMAKE_C_FLAGS}") + +include_directories( + ${CMAKE_SOURCE_DIR}/liblodepng + ${CMAKE_SOURCE_DIR}/libmscgen + ${GENERATED_SRC} +) + +add_library(mscgen +gd.c +gd_security.c +gdfontt.c +gdtables.c +gd_color.c +gdfonts.c +gdhelpers.c +gd_lodepng.c +mscgen_adraw.c +mscgen_gd_out.c +mscgen_ps_out.c +mscgen_null_out.c +${GENERATED_SRC}/mscgen_language.cpp +${GENERATED_SRC}/mscgen_lexer.cpp +mscgen_api.c +mscgen_msc.c +mscgen_safe.c +mscgen_svg_out.c +mscgen_usage.c +mscgen_utf8.c +) + + +FLEX_TARGET(mscgen_lexer + mscgen_lexer.l + ${GENERATED_SRC}/mscgen_lexer.cpp + COMPILE_FLAGS "${LEX_FLAGS}") +BISON_TARGET(mscgen_language + mscgen_language.y + ${GENERATED_SRC}/mscgen_language.cpp + COMPILE_FLAGS "${YACC_FLAGS}") diff --git a/libmscgen/COPYING b/libmscgen/COPYING new file mode 100644 index 0000000..7d122e1 --- /dev/null +++ b/libmscgen/COPYING @@ -0,0 +1,287 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + +TTPCom Ltd., hereby disclaims all copyright interest in the program `mscgen' +(which renders message sequence charts) written by Michael McTernan. + +Rob Meades of TTPCom Ltd, 1 August 2005 +Rob Meades, director of Software diff --git a/libmscgen/README.txt b/libmscgen/README.txt new file mode 100644 index 0000000..06b3902 --- /dev/null +++ b/libmscgen/README.txt @@ -0,0 +1,20 @@ +Issue 6880 (https://github.com/doxygen/doxygen/issues/6880) required fixes to the mscgen tool. +Since this tool is no longer maintained, it was decided to build mscgen as part of doxygen. +This directory contains the mscgen code. + +Since mscgen depends on libgd for PNG output, a part of the gd library is included as well. +Instead of using libpng as PNG generator, the lodepng library is used. This PNG library was +already part of doxygen. Module gd_lodepng.c was added to make libgd use lodepng. + +Original copyright statement follows: + +LICENCE +======= + +Mscgen, Copyright (C) 2010 Michael C McTernan, + Michael.McTernan.2001@cs.bris.ac.uk +Mscgen comes with ABSOLUTELY NO WARRANTY. Mscgen is free software, and you +are welcome to redistribute it under certain conditions; see the COPYING +file for details. + + diff --git a/libmscgen/gd.c b/libmscgen/gd.c new file mode 100644 index 0000000..7f0a258 --- /dev/null +++ b/libmscgen/gd.c @@ -0,0 +1,4539 @@ +/* $Id$ */ + +#include <stdio.h> +#include <math.h> +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gd_intern.h" + +/* 2.03: don't include zlib here or we can't build without PNG */ +#include "gd.h" +#include "gdhelpers.h" +#include "gd_color.h" +#include "gd_errors.h" + +/* 2.0.12: this now checks the clipping rectangle */ +#define gdImageBoundsSafeMacro(im, x, y) (!((((y) < (im)->cy1) || ((y) > (im)->cy2)) || (((x) < (im)->cx1) || ((x) > (im)->cx2)))) + +#ifdef _OSD_POSIX /* BS2000 uses the EBCDIC char set instead of ASCII */ +#define CHARSET_EBCDIC +#define __attribute__(any) /*nothing */ +#endif +/*_OSD_POSIX*/ + +#ifndef CHARSET_EBCDIC +#define ASC(ch) ch +#else /*CHARSET_EBCDIC */ +#define ASC(ch) gd_toascii[(unsigned char)ch] +static const unsigned char gd_toascii[256] = { + /*00 */ 0x00, 0x01, 0x02, 0x03, 0x85, 0x09, 0x86, 0x7f, + 0x87, 0x8d, 0x8e, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /*................ */ + /*10 */ 0x10, 0x11, 0x12, 0x13, 0x8f, 0x0a, 0x08, 0x97, + 0x18, 0x19, 0x9c, 0x9d, 0x1c, 0x1d, 0x1e, 0x1f, /*................ */ + /*20 */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x92, 0x17, 0x1b, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x05, 0x06, 0x07, /*................ */ + /*30 */ 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04, + 0x98, 0x99, 0x9a, 0x9b, 0x14, 0x15, 0x9e, 0x1a, /*................ */ + /*40 */ 0x20, 0xa0, 0xe2, 0xe4, 0xe0, 0xe1, 0xe3, 0xe5, + 0xe7, 0xf1, 0x60, 0x2e, 0x3c, 0x28, 0x2b, 0x7c, /* .........`.<(+| */ + /*50 */ 0x26, 0xe9, 0xea, 0xeb, 0xe8, 0xed, 0xee, 0xef, + 0xec, 0xdf, 0x21, 0x24, 0x2a, 0x29, 0x3b, 0x9f, /*&.........!$*);. */ + /*60 */ 0x2d, 0x2f, 0xc2, 0xc4, 0xc0, 0xc1, 0xc3, 0xc5, + 0xc7, 0xd1, 0x5e, 0x2c, 0x25, 0x5f, 0x3e, 0x3f, + /*-/........^,%_>?*/ + /*70 */ 0xf8, 0xc9, 0xca, 0xcb, 0xc8, 0xcd, 0xce, 0xcf, + 0xcc, 0xa8, 0x3a, 0x23, 0x40, 0x27, 0x3d, 0x22, /*..........:#@'=" */ + /*80 */ 0xd8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0xab, 0xbb, 0xf0, 0xfd, 0xfe, 0xb1, /*.abcdefghi...... */ + /*90 */ 0xb0, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, + 0x71, 0x72, 0xaa, 0xba, 0xe6, 0xb8, 0xc6, 0xa4, /*.jklmnopqr...... */ + /*a0 */ 0xb5, 0xaf, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0xa1, 0xbf, 0xd0, 0xdd, 0xde, 0xae, /*..stuvwxyz...... */ + /*b0 */ 0xa2, 0xa3, 0xa5, 0xb7, 0xa9, 0xa7, 0xb6, 0xbc, + 0xbd, 0xbe, 0xac, 0x5b, 0x5c, 0x5d, 0xb4, 0xd7, /*...........[\].. */ + /*c0 */ 0xf9, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0xad, 0xf4, 0xf6, 0xf2, 0xf3, 0xf5, /*.ABCDEFGHI...... */ + /*d0 */ 0xa6, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, + 0x51, 0x52, 0xb9, 0xfb, 0xfc, 0xdb, 0xfa, 0xff, /*.JKLMNOPQR...... */ + /*e0 */ 0xd9, 0xf7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5a, 0xb2, 0xd4, 0xd6, 0xd2, 0xd3, 0xd5, /*..STUVWXYZ...... */ + /*f0 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0xb3, 0x7b, 0xdc, 0x7d, 0xda, 0x7e /*0123456789.{.}.~ */ +}; +#endif /*CHARSET_EBCDIC */ + +extern const int gdCosT[]; +extern const int gdSinT[]; + +/** + * Group: Error Handling + */ + +void gd_stderr_error(int priority, const char *format, va_list args) +{ + switch (priority) { + case GD_ERROR: + fputs("GD Error: ", stderr); + break; + case GD_WARNING: + fputs("GD Warning: ", stderr); + break; + case GD_NOTICE: + fputs("GD Notice: ", stderr); + break; + case GD_INFO: + fputs("GD Info: ", stderr); + break; + case GD_DEBUG: + fputs("GD Debug: ", stderr); + break; + } + vfprintf(stderr, format, args); + fflush(stderr); +} + +static gdErrorMethod gd_error_method = gd_stderr_error; + +static void _gd_error_ex(int priority, const char *format, va_list args) +{ + if (gd_error_method) { + gd_error_method(priority, format, args); + } +} + +void gd_error(const char *format, ...) +{ + va_list args; + + va_start(args, format); + _gd_error_ex(GD_WARNING, format, args); + va_end(args); +} +void gd_error_ex(int priority, const char *format, ...) +{ + va_list args; + + va_start(args, format); + _gd_error_ex(priority, format, args); + va_end(args); +} + +/* + Function: gdSetErrorMethod +*/ +BGD_DECLARE(void) gdSetErrorMethod(gdErrorMethod error_method) +{ + gd_error_method = error_method; +} + +/* + Function: gdClearErrorMethod +*/ +BGD_DECLARE(void) gdClearErrorMethod(void) +{ + gd_error_method = gd_stderr_error; +} + +static void gdImageBrushApply (gdImagePtr im, int x, int y); +static void gdImageTileApply (gdImagePtr im, int x, int y); + +BGD_DECLARE(int) gdImageGetTrueColorPixel (gdImagePtr im, int x, int y); + +/** + * Group: Creation and Destruction + */ + +/* + Function: gdImageCreate + + gdImageCreate is called to create palette-based images, with no + more than 256 colors. The image must eventually be destroyed using + gdImageDestroy(). + + Parameters: + + sx - The image width. + sy - The image height. + + Returns: + + A pointer to the new image or NULL if an error occurred. + + Example: + (start code) + + gdImagePtr im; + im = gdImageCreate(64, 64); + // ... Use the image ... + gdImageDestroy(im); + + (end code) + + See Also: + + <gdImageCreateTrueColor> + + */ +BGD_DECLARE(gdImagePtr) gdImageCreate (int sx, int sy) +{ + int i; + gdImagePtr im; + + if (overflow2(sx, sy)) { + return NULL; + } + + if (overflow2(sizeof (unsigned char *), sy)) { + return NULL; + } + if (overflow2(sizeof (unsigned char *), sx)) { + return NULL; + } + + im = (gdImage *) gdCalloc(1, sizeof(gdImage)); + if (!im) { + return NULL; + } + + /* Row-major ever since gd 1.3 */ + im->pixels = (unsigned char **) gdMalloc (sizeof (unsigned char *) * sy); + if (!im->pixels) { + gdFree(im); + return NULL; + } + + im->polyInts = 0; + im->polyAllocated = 0; + im->brush = 0; + im->tile = 0; + im->style = 0; + for (i = 0; (i < sy); i++) { + /* Row-major ever since gd 1.3 */ + im->pixels[i] = (unsigned char *) gdCalloc (sx, sizeof (unsigned char)); + if (!im->pixels[i]) { + for (--i ; i >= 0; i--) { + gdFree(im->pixels[i]); + } + gdFree(im->pixels); + gdFree(im); + return NULL; + } + + } + im->sx = sx; + im->sy = sy; + im->colorsTotal = 0; + im->transparent = (-1); + im->interlace = 0; + im->thick = 1; + im->AA = 0; + for (i = 0; (i < gdMaxColors); i++) { + im->open[i] = 1; + }; + im->trueColor = 0; + im->tpixels = 0; + im->cx1 = 0; + im->cy1 = 0; + im->cx2 = im->sx - 1; + im->cy2 = im->sy - 1; + im->res_x = GD_RESOLUTION; + im->res_y = GD_RESOLUTION; + im->interpolation = NULL; + im->interpolation_id = GD_BILINEAR_FIXED; + return im; +} + + + +/* + Function: gdImageCreateTrueColor + + <gdImageCreateTrueColor> is called to create truecolor images, + with an essentially unlimited number of colors. Invoke + <gdImageCreateTrueColor> with the x and y dimensions of the + desired image. <gdImageCreateTrueColor> returns a <gdImagePtr> + to the new image, or NULL if unable to allocate the image. The + image must eventually be destroyed using <gdImageDestroy>(). + + Truecolor images are always filled with black at creation + time. There is no concept of a "background" color index. + + Parameters: + + sx - The image width. + sy - The image height. + + Returns: + + A pointer to the new image or NULL if an error occurred. + + Example: + (start code) + + gdImagePtr im; + im = gdImageCreateTrueColor(64, 64); + // ... Use the image ... + gdImageDestroy(im); + + (end code) + + See Also: + + <gdImageCreateTrueColor> + +*/ +BGD_DECLARE(gdImagePtr) gdImageCreateTrueColor (int sx, int sy) +{ + int i; + gdImagePtr im; + + if (overflow2(sx, sy)) { + return NULL; + } + + if (overflow2(sizeof (int *), sy)) { + return 0; + } + + if (overflow2(sizeof(int *), sx)) { + return NULL; + } + + im = (gdImage *) gdMalloc (sizeof (gdImage)); + if (!im) { + return 0; + } + memset (im, 0, sizeof (gdImage)); + + im->tpixels = (int **) gdMalloc (sizeof (int *) * sy); + if (!im->tpixels) { + gdFree(im); + return 0; + } + im->polyInts = 0; + im->polyAllocated = 0; + im->brush = 0; + im->tile = 0; + im->style = 0; + for (i = 0; (i < sy); i++) { + im->tpixels[i] = (int *) gdCalloc (sx, sizeof (int)); + if (!im->tpixels[i]) { + /* 2.0.34 */ + i--; + while (i >= 0) { + gdFree(im->tpixels[i]); + i--; + } + gdFree(im->tpixels); + gdFree(im); + return 0; + } + } + im->sx = sx; + im->sy = sy; + im->transparent = (-1); + im->interlace = 0; + im->trueColor = 1; + /* 2.0.2: alpha blending is now on by default, and saving of alpha is + off by default. This allows font antialiasing to work as expected + on the first try in JPEGs -- quite important -- and also allows + for smaller PNGs when saving of alpha channel is not really + desired, which it usually isn't! */ + im->saveAlphaFlag = 0; + im->alphaBlendingFlag = 1; + im->thick = 1; + im->AA = 0; + im->cx1 = 0; + im->cy1 = 0; + im->cx2 = im->sx - 1; + im->cy2 = im->sy - 1; + im->res_x = GD_RESOLUTION; + im->res_y = GD_RESOLUTION; + im->interpolation = NULL; + im->interpolation_id = GD_BILINEAR_FIXED; + return im; +} + +/* + Function: gdImageDestroy + + <gdImageDestroy> is used to free the memory associated with an + image. It is important to invoke <gdImageDestroy> before exiting + your program or assigning a new image to a <gdImagePtr> variable. + + Parameters: + + im - Pointer to the gdImage to delete. + + Returns: + + Nothing. + + Example: + (start code) + + gdImagePtr im; + im = gdImageCreate(10, 10); + // ... Use the image ... + // Now destroy it + gdImageDestroy(im); + + (end code) + +*/ + +BGD_DECLARE(void) gdImageDestroy (gdImagePtr im) +{ + int i; + if (im->pixels) { + for (i = 0; (i < im->sy); i++) { + gdFree (im->pixels[i]); + } + gdFree (im->pixels); + } + if (im->tpixels) { + for (i = 0; (i < im->sy); i++) { + gdFree (im->tpixels[i]); + } + gdFree (im->tpixels); + } + if (im->polyInts) { + gdFree (im->polyInts); + } + if (im->style) { + gdFree (im->style); + } + gdFree (im); +} + +/** + * Group: Color + */ + +/** + * Function: gdImageColorClosest + * + * Gets the closest color of the image + * + * This is a simplified variant of <gdImageColorClosestAlpha> where the alpha + * channel is always opaque. + * + * Parameters: + * im - The image. + * r - The value of the red component. + * g - The value of the green component. + * b - The value of the blue component. + * + * Returns: + * The closest color already available in the palette for palette images; + * the color value of the given components for truecolor images. + * + * See also: + * - <gdImageColorExact> + */ +BGD_DECLARE(int) gdImageColorClosest (gdImagePtr im, int r, int g, int b) +{ + return gdImageColorClosestAlpha (im, r, g, b, gdAlphaOpaque); +} + +/** + * Function: gdImageColorClosestAlpha + * + * Gets the closest color of the image + * + * Parameters: + * im - The image. + * r - The value of the red component. + * g - The value of the green component. + * b - The value of the blue component. + * a - The value of the alpha component. + * + * Returns: + * The closest color already available in the palette for palette images; + * the color value of the given components for truecolor images. + * + * See also: + * - <gdImageColorExactAlpha> + */ +BGD_DECLARE(int) gdImageColorClosestAlpha (gdImagePtr im, int r, int g, int b, int a) +{ + int i; + long rd, gd, bd, ad; + int ct = (-1); + int first = 1; + long mindist = 0; + if (im->trueColor) { + return gdTrueColorAlpha (r, g, b, a); + } + for (i = 0; (i < (im->colorsTotal)); i++) { + long dist; + if (im->open[i]) { + continue; + } + rd = (im->red[i] - r); + gd = (im->green[i] - g); + bd = (im->blue[i] - b); + /* gd 2.02: whoops, was - b (thanks to David Marwood) */ + /* gd 2.16: was blue rather than alpha! Geez! Thanks to + Artur Jakub Jerzak */ + ad = (im->alpha[i] - a); + dist = rd * rd + gd * gd + bd * bd + ad * ad; + if (first || (dist < mindist)) { + mindist = dist; + ct = i; + first = 0; + } + } + return ct; +} + +/* This code is taken from http://www.acm.org/jgt/papers/SmithLyons96/hwb_rgb.html, an article + * on colour conversion to/from RBG and HWB colour systems. + * It has been modified to return the converted value as a * parameter. + */ + +#define RETURN_HWB(h, w, b) {HWB->H = h; HWB->W = w; HWB->B = b; return HWB;} +#define RETURN_RGB(r, g, b) {RGB->R = r; RGB->G = g; RGB->B = b; return RGB;} +#define HWB_UNDEFINED -1 +#define SETUP_RGB(s, r, g, b) {s.R = r/255.0; s.G = g/255.0; s.B = b/255.0;} + +#define MIN(a,b) ((a)<(b)?(a):(b)) +#define MIN3(a,b,c) ((a)<(b)?(MIN(a,c)):(MIN(b,c))) +#define MAX(a,b) ((a)<(b)?(b):(a)) +#define MAX3(a,b,c) ((a)<(b)?(MAX(b,c)):(MAX(a,c))) + + +/* + * Theoretically, hue 0 (pure red) is identical to hue 6 in these transforms. Pure + * red always maps to 6 in this implementation. Therefore UNDEFINED can be + * defined as 0 in situations where only unsigned numbers are desired. + */ +typedef struct { + float R, G, B; +} +RGBType; +typedef struct { + float H, W, B; +} +HWBType; + +static HWBType * +RGB_to_HWB (RGBType RGB, HWBType * HWB) +{ + + /* + * RGB are each on [0, 1]. W and B are returned on [0, 1] and H is + * returned on [0, 6]. Exception: H is returned UNDEFINED if W == 1 - B. + */ + + float R = RGB.R, G = RGB.G, B = RGB.B, w, v, b, f; + int i; + + w = MIN3 (R, G, B); + v = MAX3 (R, G, B); + b = 1 - v; + if (v == w) + RETURN_HWB (HWB_UNDEFINED, w, b); + f = (R == w) ? G - B : ((G == w) ? B - R : R - G); + i = (R == w) ? 3 : ((G == w) ? 5 : 1); + RETURN_HWB (i - f / (v - w), w, b); + +} + +static float +HWB_Diff (int r1, int g1, int b1, int r2, int g2, int b2) +{ + RGBType RGB1, RGB2; + HWBType HWB1, HWB2; + float diff; + + SETUP_RGB (RGB1, r1, g1, b1); + SETUP_RGB (RGB2, r2, g2, b2); + + RGB_to_HWB (RGB1, &HWB1); + RGB_to_HWB (RGB2, &HWB2); + + /* + * I made this bit up; it seems to produce OK results, and it is certainly + * more visually correct than the current RGB metric. (PJW) + */ + + if ((HWB1.H == HWB_UNDEFINED) || (HWB2.H == HWB_UNDEFINED)) { + diff = 0; /* Undefined hues always match... */ + } else { + diff = fabs (HWB1.H - HWB2.H); + if (diff > 3) { + diff = 6 - diff; /* Remember, it's a colour circle */ + } + } + + diff = + diff * diff + (HWB1.W - HWB2.W) * (HWB1.W - HWB2.W) + (HWB1.B - + HWB2.B) * (HWB1.B - + HWB2.B); + + return diff; +} + + +#if 0 +/* + * This is not actually used, but is here for completeness, in case someone wants to + * use the HWB stuff for anything else... + */ +static RGBType * +HWB_to_RGB (HWBType HWB, RGBType * RGB) +{ + + /* + * H is given on [0, 6] or UNDEFINED. W and B are given on [0, 1]. + * RGB are each returned on [0, 1]. + */ + + float h = HWB.H, w = HWB.W, b = HWB.B, v, n, f; + int i; + + v = 1 - b; + if (h == HWB_UNDEFINED) + RETURN_RGB (v, v, v); + i = floor (h); + f = h - i; + if (i & 1) + f = 1 - f; /* if i is odd */ + n = w + f * (v - w); /* linear interpolation between w and v */ + switch (i) { + case 6: + case 0: + RETURN_RGB (v, n, w); + case 1: + RETURN_RGB (n, v, w); + case 2: + RETURN_RGB (w, v, n); + case 3: + RETURN_RGB (w, n, v); + case 4: + RETURN_RGB (n, w, v); + case 5: + RETURN_RGB (v, w, n); + } + + return RGB; + +} +#endif + +/* + Function: gdImageColorClosestHWB +*/ +BGD_DECLARE(int) gdImageColorClosestHWB (gdImagePtr im, int r, int g, int b) +{ + int i; + /* long rd, gd, bd; */ + int ct = (-1); + int first = 1; + float mindist = 0; + if (im->trueColor) { + return gdTrueColor (r, g, b); + } + for (i = 0; (i < (im->colorsTotal)); i++) { + float dist; + if (im->open[i]) { + continue; + } + dist = HWB_Diff (im->red[i], im->green[i], im->blue[i], r, g, b); + if (first || (dist < mindist)) { + mindist = dist; + ct = i; + first = 0; + } + } + return ct; +} + +/** + * Function: gdImageColorExact + * + * Gets the exact color of the image + * + * This is a simplified variant of <gdImageColorExactAlpha> where the alpha + * channel is always opaque. + * + * Parameters: + * im - The image. + * r - The value of the red component. + * g - The value of the green component. + * b - The value of the blue component. + * + * Returns: + * The exact color already available in the palette for palette images; if + * there is no exact color, -1 is returned. + * For truecolor images the color value of the given components is returned. + * + * See also: + * - <gdImageColorClosest> + */ +BGD_DECLARE(int) gdImageColorExact (gdImagePtr im, int r, int g, int b) +{ + return gdImageColorExactAlpha (im, r, g, b, gdAlphaOpaque); +} + +/** + * Function: gdImageColorExactAlpha + * + * Gets the exact color of the image + * + * Parameters: + * im - The image. + * r - The value of the red component. + * g - The value of the green component. + * b - The value of the blue component. + * a - The value of the alpha component. + * + * Returns: + * The exact color already available in the palette for palette images; if + * there is no exact color, -1 is returned. + * For truecolor images the color value of the given components is returned. + * + * See also: + * - <gdImageColorClosestAlpha> + * - <gdTrueColorAlpha> + */ +BGD_DECLARE(int) gdImageColorExactAlpha (gdImagePtr im, int r, int g, int b, int a) +{ + int i; + if (im->trueColor) { + return gdTrueColorAlpha (r, g, b, a); + } + for (i = 0; (i < (im->colorsTotal)); i++) { + if (im->open[i]) { + continue; + } + if ((im->red[i] == r) && + (im->green[i] == g) && (im->blue[i] == b) && (im->alpha[i] == a)) { + return i; + } + } + return -1; +} + +/** + * Function: gdImageColorAllocate + * + * Allocates a color + * + * This is a simplified variant of <gdImageColorAllocateAlpha> where the alpha + * channel is always opaque. + * + * Parameters: + * im - The image. + * r - The value of the red component. + * g - The value of the green component. + * b - The value of the blue component. + * + * Returns: + * The color value. + * + * See also: + * - <gdImageColorDeallocate> + */ +BGD_DECLARE(int) gdImageColorAllocate (gdImagePtr im, int r, int g, int b) +{ + return gdImageColorAllocateAlpha (im, r, g, b, gdAlphaOpaque); +} + +/** + * Function: gdImageColorAllocateAlpha + * + * Allocates a color + * + * This is typically used for palette images, but can be used for truecolor + * images as well. + * + * Parameters: + * im - The image. + * r - The value of the red component. + * g - The value of the green component. + * b - The value of the blue component. + * + * Returns: + * The color value. + * + * See also: + * - <gdImageColorDeallocate> + */ +BGD_DECLARE(int) gdImageColorAllocateAlpha (gdImagePtr im, int r, int g, int b, int a) +{ + int i; + int ct = (-1); + if (im->trueColor) { + return gdTrueColorAlpha (r, g, b, a); + } + for (i = 0; (i < (im->colorsTotal)); i++) { + if (im->open[i]) { + ct = i; + break; + } + } + if (ct == (-1)) { + ct = im->colorsTotal; + if (ct == gdMaxColors) { + return -1; + } + im->colorsTotal++; + } + im->red[ct] = r; + im->green[ct] = g; + im->blue[ct] = b; + im->alpha[ct] = a; + im->open[ct] = 0; + return ct; +} + +/* + Function: gdImageColorResolve + + gdImageColorResolve is an alternative for the code fragment + (start code) + if ((color=gdImageColorExact(im,R,G,B)) < 0) + if ((color=gdImageColorAllocate(im,R,G,B)) < 0) + color=gdImageColorClosest(im,R,G,B); + (end code) + in a single function. Its advantage is that it is guaranteed to + return a color index in one search over the color table. +*/ + +BGD_DECLARE(int) gdImageColorResolve (gdImagePtr im, int r, int g, int b) +{ + return gdImageColorResolveAlpha (im, r, g, b, gdAlphaOpaque); +} + +/* + Function: gdImageColorResolveAlpha +*/ +BGD_DECLARE(int) gdImageColorResolveAlpha (gdImagePtr im, int r, int g, int b, int a) +{ + int c; + int ct = -1; + int op = -1; + long rd, gd, bd, ad, dist; + long mindist = 4 * 255 * 255; /* init to max poss dist */ + if (im->trueColor) { + return gdTrueColorAlpha (r, g, b, a); + } + + for (c = 0; c < im->colorsTotal; c++) { + if (im->open[c]) { + op = c; /* Save open slot */ + continue; /* Color not in use */ + } + if (c == im->transparent) { + /* don't ever resolve to the color that has + * been designated as the transparent color */ + continue; + } + rd = (long) (im->red[c] - r); + gd = (long) (im->green[c] - g); + bd = (long) (im->blue[c] - b); + ad = (long) (im->alpha[c] - a); + dist = rd * rd + gd * gd + bd * bd + ad * ad; + if (dist < mindist) { + if (dist == 0) { + return c; /* Return exact match color */ + } + mindist = dist; + ct = c; + } + } + /* no exact match. We now know closest, but first try to allocate exact */ + if (op == -1) { + op = im->colorsTotal; + if (op == gdMaxColors) { + /* No room for more colors */ + return ct; /* Return closest available color */ + } + im->colorsTotal++; + } + im->red[op] = r; + im->green[op] = g; + im->blue[op] = b; + im->alpha[op] = a; + im->open[op] = 0; + return op; /* Return newly allocated color */ +} + +/** + * Function: gdImageColorDeallocate + * + * Removes a palette entry + * + * This is a no-op for truecolor images. + * + * Parameters: + * im - The image. + * color - The palette index. + * + * See also: + * - <gdImageColorAllocate> + * - <gdImageColorAllocateAlpha> + */ +BGD_DECLARE(void) gdImageColorDeallocate (gdImagePtr im, int color) +{ + if (im->trueColor || (color >= gdMaxColors) || (color < 0)) { + return; + } + /* Mark it open. */ + im->open[color] = 1; +} + +/** + * Function: gdImageColorTransparent + * + * Sets the transparent color of the image + * + * Parameter: + * im - The image. + * color - The color. + * + * See also: + * - <gdImageGetTransparent> + */ +BGD_DECLARE(void) gdImageColorTransparent (gdImagePtr im, int color) +{ + if (color < 0) { + return; + } + + if (!im->trueColor) { + if((color < -1) || (color >= gdMaxColors)) { + return; + } + if (im->transparent != -1) { + im->alpha[im->transparent] = gdAlphaOpaque; + } + if (color != -1) { + im->alpha[color] = gdAlphaTransparent; + } + } + im->transparent = color; +} + +/* + Function: gdImagePaletteCopy +*/ +BGD_DECLARE(void) gdImagePaletteCopy (gdImagePtr to, gdImagePtr from) +{ + int i; + int x, y, p; + int xlate[256]; + if (to->trueColor) { + return; + } + if (from->trueColor) { + return; + } + + for (i = 0; i < 256; i++) { + xlate[i] = -1; + }; + + for (y = 0; y < (to->sy); y++) { + for (x = 0; x < (to->sx); x++) { + /* Optimization: no gdImageGetPixel */ + p = to->pixels[y][x]; + if (xlate[p] == -1) { + /* This ought to use HWB, but we don't have an alpha-aware + version of that yet. */ + xlate[p] = + gdImageColorClosestAlpha (from, to->red[p], to->green[p], + to->blue[p], to->alpha[p]); + /*printf("Mapping %d (%d, %d, %d, %d) to %d (%d, %d, %d, %d)\n", */ + /* p, to->red[p], to->green[p], to->blue[p], to->alpha[p], */ + /* xlate[p], from->red[xlate[p]], from->green[xlate[p]], from->blue[xlate[p]], from->alpha[xlate[p]]); */ + }; + /* Optimization: no gdImageSetPixel */ + to->pixels[y][x] = xlate[p]; + }; + }; + + for (i = 0; (i < (from->colorsTotal)); i++) { + /*printf("Copying color %d (%d, %d, %d, %d)\n", i, from->red[i], from->blue[i], from->green[i], from->alpha[i]); */ + to->red[i] = from->red[i]; + to->blue[i] = from->blue[i]; + to->green[i] = from->green[i]; + to->alpha[i] = from->alpha[i]; + to->open[i] = 0; + }; + + for (i = from->colorsTotal; (i < to->colorsTotal); i++) { + to->open[i] = 1; + }; + + to->colorsTotal = from->colorsTotal; + +} + +/* + Function: gdImageColorReplace +*/ +BGD_DECLARE(int) gdImageColorReplace (gdImagePtr im, int src, int dst) +{ + register int x, y; + int n = 0; + + if (src == dst) { + return 0; + } + +#define REPLACING_LOOP(pixel) do { \ + for (y = im->cy1; y <= im->cy2; y++) { \ + for (x = im->cx1; x <= im->cx2; x++) { \ + if (pixel(im, x, y) == src) { \ + gdImageSetPixel(im, x, y, dst); \ + n++; \ + } \ + } \ + } \ + } while (0) + + if (im->trueColor) { + REPLACING_LOOP(gdImageTrueColorPixel); + } else { + REPLACING_LOOP(gdImagePalettePixel); + } + +#undef REPLACING_LOOP + + return n; +} + +/* + Function: gdImageColorReplaceThreshold +*/ +BGD_DECLARE(int) gdImageColorReplaceThreshold (gdImagePtr im, int src, int dst, float threshold) +{ + register int x, y; + int n = 0; + + if (src == dst) { + return 0; + } + +#define REPLACING_LOOP(pixel) do { \ + for (y = im->cy1; y <= im->cy2; y++) { \ + for (x = im->cx1; x <= im->cx2; x++) { \ + if (gdColorMatch(im, src, pixel(im, x, y), threshold)) { \ + gdImageSetPixel(im, x, y, dst); \ + n++; \ + } \ + } \ + } \ + } while (0) + + if (im->trueColor) { + REPLACING_LOOP(gdImageTrueColorPixel); + } else { + REPLACING_LOOP(gdImagePalettePixel); + } + +#undef REPLACING_LOOP + + return n; +} + +static int colorCmp (const void *x, const void *y) +{ + int a = *(int const *)x; + int b = *(int const *)y; + return (a > b) - (a < b); +} + +/* + Function: gdImageColorReplaceArray +*/ +BGD_DECLARE(int) gdImageColorReplaceArray (gdImagePtr im, int len, int *src, int *dst) +{ + register int x, y; + int c, *d, *base; + int i, n = 0; + + if (len <= 0 || src == dst) { + return 0; + } + if (len == 1) { + return gdImageColorReplace(im, src[0], dst[0]); + } + if (overflow2(len, sizeof(int)<<1)) { + return -1; + } + base = (int *)gdMalloc(len * (sizeof(int)<<1)); + if (!base) { + return -1; + } + for (i = 0; i < len; i++) { + base[(i<<1)] = src[i]; + base[(i<<1)+1] = dst[i]; + } + qsort(base, len, sizeof(int)<<1, colorCmp); + +#define REPLACING_LOOP(pixel) do { \ + for (y = im->cy1; y <= im->cy2; y++) { \ + for (x = im->cx1; x <= im->cx2; x++) { \ + c = pixel(im, x, y); \ + if ( (d = (int *)bsearch(&c, base, len, sizeof(int)<<1, colorCmp)) ) { \ + gdImageSetPixel(im, x, y, d[1]); \ + n++; \ + } \ + } \ + } \ + } while (0) + + if (im->trueColor) { + REPLACING_LOOP(gdImageTrueColorPixel); + } else { + REPLACING_LOOP(gdImagePalettePixel); + } + +#undef REPLACING_LOOP + + gdFree(base); + return n; +} + +/* + Function: gdImageColorReplaceCallback +*/ +BGD_DECLARE(int) gdImageColorReplaceCallback (gdImagePtr im, gdCallbackImageColor callback) +{ + int c, d, n = 0; + + if (!callback) { + return 0; + } + if (im->trueColor) { + register int x, y; + + for (y = im->cy1; y <= im->cy2; y++) { + for (x = im->cx1; x <= im->cx2; x++) { + c = gdImageTrueColorPixel(im, x, y); + if ( (d = callback(im, c)) != c) { + gdImageSetPixel(im, x, y, d); + n++; + } + } + } + } else { /* palette */ + int *sarr, *darr; + int k, len = 0; + + sarr = (int *)gdCalloc(im->colorsTotal, sizeof(int)); + if (!sarr) { + return -1; + } + for (c = 0; c < im->colorsTotal; c++) { + if (!im->open[c]) { + sarr[len++] = c; + } + } + darr = (int *)gdCalloc(len, sizeof(int)); + if (!darr) { + gdFree(sarr); + return -1; + } + for (k = 0; k < len; k++) { + darr[k] = callback(im, sarr[k]); + } + n = gdImageColorReplaceArray(im, k, sarr, darr); + gdFree(darr); + gdFree(sarr); + } + return n; +} + +/* 2.0.10: before the drawing routines, some code to clip points that are + * outside the drawing window. Nick Atty (nick@canalplan.org.uk) + * + * This is the Sutherland Hodgman Algorithm, as implemented by + * Duvanenko, Robbins and Gyurcsik - SH(DRG) for short. See Dr Dobb's + * Journal, January 1996, pp107-110 and 116-117 + * + * Given the end points of a line, and a bounding rectangle (which we + * know to be from (0,0) to (SX,SY)), adjust the endpoints to be on + * the edges of the rectangle if the line should be drawn at all, + * otherwise return a failure code */ + +/* this does "one-dimensional" clipping: note that the second time it + is called, all the x parameters refer to height and the y to width + - the comments ignore this (if you can understand it when it's + looking at the X parameters, it should become clear what happens on + the second call!) The code is simplified from that in the article, + as we know that gd images always start at (0,0) */ + +/* 2.0.26, TBB: we now have to respect a clipping rectangle, it won't + necessarily start at 0. */ + +static int +clip_1d (int *x0, int *y0, int *x1, int *y1, int mindim, int maxdim) +{ + double m; /* gradient of line */ + if (*x0 < mindim) { + /* start of line is left of window */ + if (*x1 < mindim) /* as is the end, so the line never cuts the window */ + return 0; + m = (*y1 - *y0) / (double) (*x1 - *x0); /* calculate the slope of the line */ + /* adjust x0 to be on the left boundary (ie to be zero), and y0 to match */ + *y0 -= (int)(m * (*x0 - mindim)); + *x0 = mindim; + /* now, perhaps, adjust the far end of the line as well */ + if (*x1 > maxdim) { + *y1 += m * (maxdim - *x1); + *x1 = maxdim; + } + return 1; + } + if (*x0 > maxdim) { + /* start of line is right of window - + complement of above */ + if (*x1 > maxdim) /* as is the end, so the line misses the window */ + return 0; + m = (*y1 - *y0) / (double) (*x1 - *x0); /* calculate the slope of the line */ + *y0 += (int)(m * (maxdim - *x0)); /* adjust so point is on the right + boundary */ + *x0 = maxdim; + /* now, perhaps, adjust the end of the line */ + if (*x1 < mindim) { + *y1 -= (int)(m * (*x1 - mindim)); + *x1 = mindim; + } + return 1; + } + /* the final case - the start of the line is inside the window */ + if (*x1 > maxdim) { + /* other end is outside to the right */ + m = (*y1 - *y0) / (double) (*x1 - *x0); /* calculate the slope of the line */ + *y1 += (int)(m * (maxdim - *x1)); + *x1 = maxdim; + return 1; + } + if (*x1 < mindim) { + /* other end is outside to the left */ + m = (*y1 - *y0) / (double) (*x1 - *x0); /* calculate the slope of the line */ + *y1 -= (int)(m * (*x1 - mindim)); + *x1 = mindim; + return 1; + } + /* only get here if both points are inside the window */ + return 1; +} + +/* end of line clipping code */ + +/** + * Group: Pixels + */ + +/* + Function: gdImageSetPixel +*/ +BGD_DECLARE(void) gdImageSetPixel (gdImagePtr im, int x, int y, int color) +{ + int p; + switch (color) { + case gdStyled: + if (!im->style) { + /* Refuse to draw if no style is set. */ + return; + } else { + p = im->style[im->stylePos++]; + } + if (p != (gdTransparent)) { + gdImageSetPixel (im, x, y, p); + } + im->stylePos = im->stylePos % im->styleLength; + break; + case gdStyledBrushed: + if (!im->style) { + /* Refuse to draw if no style is set. */ + return; + } + p = im->style[im->stylePos++]; + if ((p != gdTransparent) && (p != 0)) { + gdImageSetPixel (im, x, y, gdBrushed); + } + im->stylePos = im->stylePos % im->styleLength; + break; + case gdBrushed: + gdImageBrushApply (im, x, y); + break; + case gdTiled: + gdImageTileApply (im, x, y); + break; + case gdAntiAliased: + /* This shouldn't happen (2.0.26) because we just call + gdImageAALine now, but do something sane. */ + gdImageSetPixel(im, x, y, im->AA_color); + break; + default: + if (gdImageBoundsSafeMacro (im, x, y)) { + if (im->trueColor) { + switch (im->alphaBlendingFlag) { + default: + case gdEffectReplace: + im->tpixels[y][x] = color; + break; + case gdEffectAlphaBlend: + case gdEffectNormal: + im->tpixels[y][x] = gdAlphaBlend(im->tpixels[y][x], color); + break; + case gdEffectOverlay : + im->tpixels[y][x] = gdLayerOverlay(im->tpixels[y][x], color); + break; + case gdEffectMultiply : + im->tpixels[y][x] = gdLayerMultiply(im->tpixels[y][x], color); + break; + } + } else { + im->pixels[y][x] = color; + } + } + break; + } +} + +static void +gdImageBrushApply (gdImagePtr im, int x, int y) +{ + int lx, ly; + int hy; + int hx; + int x1, y1, x2, y2; + int srcx, srcy; + if (!im->brush) { + return; + } + hy = gdImageSY (im->brush) / 2; + y1 = y - hy; + y2 = y1 + gdImageSY (im->brush); + hx = gdImageSX (im->brush) / 2; + x1 = x - hx; + x2 = x1 + gdImageSX (im->brush); + srcy = 0; + if (im->trueColor) { + if (im->brush->trueColor) { + for (ly = y1; (ly < y2); ly++) { + srcx = 0; + for (lx = x1; (lx < x2); lx++) { + int p; + p = gdImageGetTrueColorPixel (im->brush, srcx, srcy); + /* 2.0.9, Thomas Winzig: apply simple full transparency */ + if (p != gdImageGetTransparent (im->brush)) { + gdImageSetPixel (im, lx, ly, p); + } + srcx++; + } + srcy++; + } + } else { + /* 2.0.12: Brush palette, image truecolor (thanks to Thorben Kundinger + for pointing out the issue) */ + for (ly = y1; (ly < y2); ly++) { + srcx = 0; + for (lx = x1; (lx < x2); lx++) { + int p, tc; + p = gdImageGetPixel (im->brush, srcx, srcy); + tc = gdImageGetTrueColorPixel (im->brush, srcx, srcy); + /* 2.0.9, Thomas Winzig: apply simple full transparency */ + if (p != gdImageGetTransparent (im->brush)) { + gdImageSetPixel (im, lx, ly, tc); + } + srcx++; + } + srcy++; + } + } + } else { + for (ly = y1; (ly < y2); ly++) { + srcx = 0; + for (lx = x1; (lx < x2); lx++) { + int p; + p = gdImageGetPixel (im->brush, srcx, srcy); + /* Allow for non-square brushes! */ + if (p != gdImageGetTransparent (im->brush)) { + /* Truecolor brush. Very slow + on a palette destination. */ + if (im->brush->trueColor) { + gdImageSetPixel (im, lx, ly, + gdImageColorResolveAlpha (im, + gdTrueColorGetRed + (p), + gdTrueColorGetGreen + (p), + gdTrueColorGetBlue + (p), + gdTrueColorGetAlpha + (p))); + } else { + gdImageSetPixel (im, lx, ly, im->brushColorMap[p]); + } + } + srcx++; + } + srcy++; + } + } +} + +static void +gdImageTileApply (gdImagePtr im, int x, int y) +{ + gdImagePtr tile = im->tile; + int srcx, srcy; + int p; + if (!tile) { + return; + } + srcx = x % gdImageSX (tile); + srcy = y % gdImageSY (tile); + if (im->trueColor) { + p = gdImageGetPixel (tile, srcx, srcy); + if (p != gdImageGetTransparent (tile)) { + if (!tile->trueColor) { + p = gdTrueColorAlpha(tile->red[p], tile->green[p], tile->blue[p], tile->alpha[p]); + } + gdImageSetPixel (im, x, y, p); + } + } else { + p = gdImageGetPixel (tile, srcx, srcy); + /* Allow for transparency */ + if (p != gdImageGetTransparent (tile)) { + if (tile->trueColor) { + /* Truecolor tile. Very slow + on a palette destination. */ + gdImageSetPixel (im, x, y, + gdImageColorResolveAlpha (im, + gdTrueColorGetRed + (p), + gdTrueColorGetGreen + (p), + gdTrueColorGetBlue + (p), + gdTrueColorGetAlpha + (p))); + } else { + gdImageSetPixel (im, x, y, im->tileColorMap[p]); + } + } + } +} + +/** + * Function: gdImageGetPixel + * + * Gets a pixel color as stored in the image. + * + * Parameters: + * im - The image. + * x - The x-coordinate. + * y - The y-coordinate. + * + * See also: + * - <gdImageGetTrueColorPixel> + * - <gdImagePalettePixel> + * - <gdImageTrueColorPixel> + */ +BGD_DECLARE(int) gdImageGetPixel (gdImagePtr im, int x, int y) +{ + if (gdImageBoundsSafeMacro (im, x, y)) { + if (im->trueColor) { + return im->tpixels[y][x]; + } else { + return im->pixels[y][x]; + } + } else { + return 0; + } +} + +/** + * Function: gdImageGetTrueColorPixel + * + * Gets a pixel color always as truecolor value. + * + * Parameters: + * im - The image. + * x - The x-coordinate. + * y - The y-coordinate. + * + * See also: + * - <gdImageGetPixel> + * - <gdImageTrueColorPixel> + */ +BGD_DECLARE(int) gdImageGetTrueColorPixel (gdImagePtr im, int x, int y) +{ + int p = gdImageGetPixel (im, x, y); + if (!im->trueColor) { + return gdTrueColorAlpha (im->red[p], im->green[p], im->blue[p], + (im->transparent == p) ? gdAlphaTransparent : + im->alpha[p]); + } else { + return p; + } +} + +/** + * Group: Primitives + */ + +/* + Function: gdImageAABlend + + NO-OP, kept for library compatibility. +*/ +BGD_DECLARE(void) gdImageAABlend (gdImagePtr im) +{ + (void)im; +} + +static void gdImageAALine (gdImagePtr im, int x1, int y1, int x2, int y2, int col); + +static void _gdImageFilledHRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, + int color); + +static void gdImageHLine(gdImagePtr im, int y, int x1, int x2, int col) +{ + if (im->thick > 1) { + int thickhalf = im->thick >> 1; + _gdImageFilledHRectangle(im, x1, y - thickhalf, x2, y + im->thick - thickhalf - 1, col); + } else { + if (x2 < x1) { + int t = x2; + x2 = x1; + x1 = t; + } + + for (; x1 <= x2; x1++) { + gdImageSetPixel(im, x1, y, col); + } + } + return; +} + +static void gdImageVLine(gdImagePtr im, int x, int y1, int y2, int col) +{ + if (im->thick > 1) { + int thickhalf = im->thick >> 1; + gdImageFilledRectangle(im, x - thickhalf, y1, x + im->thick - thickhalf - 1, y2, col); + } else { + if (y2 < y1) { + int t = y1; + y1 = y2; + y2 = t; + } + + for (; y1 <= y2; y1++) { + gdImageSetPixel(im, x, y1, col); + } + } + return; +} + +/* + Function: gdImageLine + + Bresenham as presented in Foley & Van Dam. +*/ +BGD_DECLARE(void) gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color) +{ + int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag; + int wid; + int w, wstart; + int thick; + + if (color == gdAntiAliased) { + /* + gdAntiAliased passed as color: use the much faster, much cheaper + and equally attractive gdImageAALine implementation. That + clips too, so don't clip twice. + */ + gdImageAALine(im, x1, y1, x2, y2, im->AA_color); + return; + } + /* 2.0.10: Nick Atty: clip to edges of drawing rectangle, return if no + points need to be drawn. 2.0.26, TBB: clip to edges of clipping + rectangle. We were getting away with this because gdImageSetPixel + is used for actual drawing, but this is still more efficient and opens + the way to skip per-pixel bounds checking in the future. */ + + if (clip_1d (&x1, &y1, &x2, &y2, im->cx1, im->cx2) == 0) + return; + if (clip_1d (&y1, &x1, &y2, &x2, im->cy1, im->cy2) == 0) + return; + thick = im->thick; + + dx = abs (x2 - x1); + dy = abs (y2 - y1); + + if (dx == 0) { + gdImageVLine(im, x1, y1, y2, color); + return; + } else if (dy == 0) { + gdImageHLine(im, y1, x1, x2, color); + return; + } + + if (dy <= dx) { + /* More-or-less horizontal. use wid for vertical stroke */ + /* Doug Claar: watch out for NaN in atan2 (2.0.5) */ + + /* 2.0.12: Michael Schwartz: divide rather than multiply; + TBB: but watch out for /0! */ + double ac = cos (atan2 (dy, dx)); + if (ac != 0) { + wid = thick / ac; + } else { + wid = 1; + } + if (wid == 0) { + wid = 1; + } + d = 2 * dy - dx; + incr1 = 2 * dy; + incr2 = 2 * (dy - dx); + if (x1 > x2) { + x = x2; + y = y2; + ydirflag = (-1); + xend = x1; + } else { + x = x1; + y = y1; + ydirflag = 1; + xend = x2; + } + + /* Set up line thickness */ + wstart = y - wid / 2; + for (w = wstart; w < wstart + wid; w++) + gdImageSetPixel (im, x, w, color); + + if (((y2 - y1) * ydirflag) > 0) { + while (x < xend) { + x++; + if (d < 0) { + d += incr1; + } else { + y++; + d += incr2; + } + wstart = y - wid / 2; + for (w = wstart; w < wstart + wid; w++) + gdImageSetPixel (im, x, w, color); + } + } else { + while (x < xend) { + x++; + if (d < 0) { + d += incr1; + } else { + y--; + d += incr2; + } + wstart = y - wid / 2; + for (w = wstart; w < wstart + wid; w++) + gdImageSetPixel (im, x, w, color); + } + } + } else { + /* More-or-less vertical. use wid for horizontal stroke */ + /* 2.0.12: Michael Schwartz: divide rather than multiply; + TBB: but watch out for /0! */ + double as = sin (atan2 (dy, dx)); + if (as != 0) { + wid = thick / as; + } else { + wid = 1; + } + if (wid == 0) + wid = 1; + + d = 2 * dx - dy; + incr1 = 2 * dx; + incr2 = 2 * (dx - dy); + if (y1 > y2) { + y = y2; + x = x2; + yend = y1; + xdirflag = (-1); + } else { + y = y1; + x = x1; + yend = y2; + xdirflag = 1; + } + + /* Set up line thickness */ + wstart = x - wid / 2; + for (w = wstart; w < wstart + wid; w++) + gdImageSetPixel (im, w, y, color); + + if (((x2 - x1) * xdirflag) > 0) { + while (y < yend) { + y++; + if (d < 0) { + d += incr1; + } else { + x++; + d += incr2; + } + wstart = x - wid / 2; + for (w = wstart; w < wstart + wid; w++) + gdImageSetPixel (im, w, y, color); + } + } else { + while (y < yend) { + y++; + if (d < 0) { + d += incr1; + } else { + x--; + d += incr2; + } + wstart = x - wid / 2; + for (w = wstart; w < wstart + wid; w++) + gdImageSetPixel (im, w, y, color); + } + } + } + +} +static void dashedSet (gdImagePtr im, int x, int y, int color, + int *onP, int *dashStepP, int wid, int vert); + +/* + Function: gdImageDashedLine +*/ +BGD_DECLARE(void) gdImageDashedLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color) +{ + int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag; + int dashStep = 0; + int on = 1; + int wid; + int vert; + int thick = im->thick; + + dx = abs (x2 - x1); + dy = abs (y2 - y1); + if (dy <= dx) { + /* More-or-less horizontal. use wid for vertical stroke */ + /* 2.0.12: Michael Schwartz: divide rather than multiply; + TBB: but watch out for /0! */ + double as = sin (atan2 (dy, dx)); + if (as != 0) { + wid = thick / as; + } else { + wid = 1; + } + vert = 1; + + d = 2 * dy - dx; + incr1 = 2 * dy; + incr2 = 2 * (dy - dx); + if (x1 > x2) { + x = x2; + y = y2; + ydirflag = (-1); + xend = x1; + } else { + x = x1; + y = y1; + ydirflag = 1; + xend = x2; + } + dashedSet (im, x, y, color, &on, &dashStep, wid, vert); + if (((y2 - y1) * ydirflag) > 0) { + while (x < xend) { + x++; + if (d < 0) { + d += incr1; + } else { + y++; + d += incr2; + } + dashedSet (im, x, y, color, &on, &dashStep, wid, vert); + } + } else { + while (x < xend) { + x++; + if (d < 0) { + d += incr1; + } else { + y--; + d += incr2; + } + dashedSet (im, x, y, color, &on, &dashStep, wid, vert); + } + } + } else { + /* 2.0.12: Michael Schwartz: divide rather than multiply; + TBB: but watch out for /0! */ + double as = sin (atan2 (dy, dx)); + if (as != 0) { + wid = thick / as; + } else { + wid = 1; + } + vert = 0; + + d = 2 * dx - dy; + incr1 = 2 * dx; + incr2 = 2 * (dx - dy); + if (y1 > y2) { + y = y2; + x = x2; + yend = y1; + xdirflag = (-1); + } else { + y = y1; + x = x1; + yend = y2; + xdirflag = 1; + } + dashedSet (im, x, y, color, &on, &dashStep, wid, vert); + if (((x2 - x1) * xdirflag) > 0) { + while (y < yend) { + y++; + if (d < 0) { + d += incr1; + } else { + x++; + d += incr2; + } + dashedSet (im, x, y, color, &on, &dashStep, wid, vert); + } + } else { + while (y < yend) { + y++; + if (d < 0) { + d += incr1; + } else { + x--; + d += incr2; + } + dashedSet (im, x, y, color, &on, &dashStep, wid, vert); + } + } + } +} + +static void +dashedSet (gdImagePtr im, int x, int y, int color, + int *onP, int *dashStepP, int wid, int vert) +{ + int dashStep = *dashStepP; + int on = *onP; + int w, wstart; + + dashStep++; + if (dashStep == gdDashSize) { + dashStep = 0; + on = !on; + } + if (on) { + if (vert) { + wstart = y - wid / 2; + for (w = wstart; w < wstart + wid; w++) + gdImageSetPixel (im, x, w, color); + } else { + wstart = x - wid / 2; + for (w = wstart; w < wstart + wid; w++) + gdImageSetPixel (im, w, y, color); + } + } + *dashStepP = dashStep; + *onP = on; +} + +/* + Function: gdImageBoundsSafe +*/ +BGD_DECLARE(int) gdImageBoundsSafe (gdImagePtr im, int x, int y) +{ + return gdImageBoundsSafeMacro (im, x, y); +} + +/** + * Function: gdImageChar + * + * Draws a single character. + * + * Parameters: + * im - The image to draw onto. + * f - The raster font. + * x - The x coordinate of the upper left pixel. + * y - The y coordinate of the upper left pixel. + * c - The character. + * color - The color. + * + * Variants: + * - <gdImageCharUp> + * + * See also: + * - <gdFontPtr> + */ +BGD_DECLARE(void) gdImageChar (gdImagePtr im, gdFontPtr f, int x, int y, int c, int color) +{ + int cx, cy; + int px, py; + int fline; + cx = 0; + cy = 0; +#ifdef CHARSET_EBCDIC + c = ASC (c); +#endif /*CHARSET_EBCDIC */ + if ((c < f->offset) || (c >= (f->offset + f->nchars))) { + return; + } + fline = (c - f->offset) * f->h * f->w; + for (py = y; (py < (y + f->h)); py++) { + for (px = x; (px < (x + f->w)); px++) { + if (f->data[fline + cy * f->w + cx]) { + gdImageSetPixel (im, px, py, color); + } + cx++; + } + cx = 0; + cy++; + } +} + +/** + * Function: gdImageCharUp + */ +BGD_DECLARE(void) gdImageCharUp (gdImagePtr im, gdFontPtr f, int x, int y, int c, int color) +{ + int cx, cy; + int px, py; + int fline; + cx = 0; + cy = 0; +#ifdef CHARSET_EBCDIC + c = ASC (c); +#endif /*CHARSET_EBCDIC */ + if ((c < f->offset) || (c >= (f->offset + f->nchars))) { + return; + } + fline = (c - f->offset) * f->h * f->w; + for (py = y; (py > (y - f->w)); py--) { + for (px = x; (px < (x + f->h)); px++) { + if (f->data[fline + cy * f->w + cx]) { + gdImageSetPixel (im, px, py, color); + } + cy++; + } + cy = 0; + cx++; + } +} + +/** + * Function: gdImageString + * + * Draws a character string. + * + * Parameters: + * im - The image to draw onto. + * f - The raster font. + * x - The x coordinate of the upper left pixel. + * y - The y coordinate of the upper left pixel. + * c - The character string. + * color - The color. + * + * Variants: + * - <gdImageStringUp> + * - <gdImageString16> + * - <gdImageStringUp16> + * + * See also: + * - <gdFontPtr> + * - <gdImageStringTTF> + */ +BGD_DECLARE(void) gdImageString (gdImagePtr im, gdFontPtr f, + int x, int y, unsigned char *s, int color) +{ + int i; + int l; + l = strlen ((char *) s); + for (i = 0; (i < l); i++) { + gdImageChar (im, f, x, y, s[i], color); + x += f->w; + } +} + +/** + * Function: gdImageStringUp + */ +BGD_DECLARE(void) gdImageStringUp (gdImagePtr im, gdFontPtr f, + int x, int y, unsigned char *s, int color) +{ + int i; + int l; + l = strlen ((char *) s); + for (i = 0; (i < l); i++) { + gdImageCharUp (im, f, x, y, s[i], color); + y -= f->w; + } +} + +static int strlen16 (unsigned short *s); + +/** + * Function: gdImageString16 + */ +BGD_DECLARE(void) gdImageString16 (gdImagePtr im, gdFontPtr f, + int x, int y, unsigned short *s, int color) +{ + int i; + int l; + l = strlen16 (s); + for (i = 0; (i < l); i++) { + gdImageChar (im, f, x, y, s[i], color); + x += f->w; + } +} + +/** + * Function: gdImageStringUp16 + */ +BGD_DECLARE(void) gdImageStringUp16 (gdImagePtr im, gdFontPtr f, + int x, int y, unsigned short *s, int color) +{ + int i; + int l; + l = strlen16 (s); + for (i = 0; (i < l); i++) { + gdImageCharUp (im, f, x, y, s[i], color); + y -= f->w; + } +} + +static int +strlen16 (unsigned short *s) +{ + int len = 0; + while (*s) { + s++; + len++; + } + return len; +} + +#ifndef HAVE_LSQRT +/* If you don't have a nice square root function for longs, you can use + ** this hack + */ +long +lsqrt (long n) +{ + long result = (long) sqrt ((double) n); + return result; +} +#endif + +/* s and e are integers modulo 360 (degrees), with 0 degrees + being the rightmost extreme and degrees changing clockwise. + cx and cy are the center in pixels; w and h are the horizontal + and vertical diameter in pixels. */ + +/* + Function: gdImageArc +*/ +BGD_DECLARE(void) gdImageArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, + int color) +{ + gdImageFilledArc (im, cx, cy, w, h, s, e, color, gdNoFill); +} + +/* + Function: gdImageFilledArc +*/ +BGD_DECLARE(void) gdImageFilledArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, + int color, int style) +{ + gdPoint pts[363]; + int i, pti; + int lx = 0, ly = 0; + int fx = 0, fy = 0; + + if ((s % 360) == (e % 360)) { + s = 0; + e = 360; + } else { + if (s > 360) { + s = s % 360; + } + + if (e > 360) { + e = e % 360; + } + + while (s < 0) { + s += 360; + } + + while (e < s) { + e += 360; + } + + if (s == e) { + s = 0; + e = 360; + } + } + + for (i = s, pti = 1; (i <= e); i++, pti++) { + int x, y; + x = ((long) gdCosT[i % 360] * (long) w / (2 * 1024)) + cx; + y = ((long) gdSinT[i % 360] * (long) h / (2 * 1024)) + cy; + if (i != s) { + if (!(style & gdChord)) { + if (style & gdNoFill) { + gdImageLine (im, lx, ly, x, y, color); + } else { + if (y == ly) { + pti--; /* don't add this point */ + if (((i > 270 || i < 90) && x > lx) || ((i > 90 && i < 270) && x < lx)) { + /* replace the old x coord, if increasing on the + right side or decreasing on the left side */ + pts[pti].x = x; + } + } else { + pts[pti].x = x; + pts[pti].y = y; + } + } + } + } else { + fx = x; + fy = y; + + if (!(style & (gdChord | gdNoFill))) { + pts[0].x = cx; + pts[0].y = cy; + pts[pti].x = x; + pts[pti].y = y; + } + } + lx = x; + ly = y; + } + if (style & gdChord) { + if (style & gdNoFill) { + if (style & gdEdged) { + gdImageLine (im, cx, cy, lx, ly, color); + gdImageLine (im, cx, cy, fx, fy, color); + } + gdImageLine (im, fx, fy, lx, ly, color); + } else { + pts[0].x = fx; + pts[0].y = fy; + pts[1].x = lx; + pts[1].y = ly; + pts[2].x = cx; + pts[2].y = cy; + gdImageFilledPolygon (im, pts, 3, color); + } + } else { + if (style & gdNoFill) { + if (style & gdEdged) { + gdImageLine (im, cx, cy, lx, ly, color); + gdImageLine (im, cx, cy, fx, fy, color); + } + } else { + pts[pti].x = cx; + pts[pti].y = cy; + gdImageFilledPolygon(im, pts, pti+1, color); + } + } +} + +/* + Function: gdImageEllipse +*/ +BGD_DECLARE(void) gdImageEllipse(gdImagePtr im, int mx, int my, int w, int h, int c) +{ + int x=0,mx1=0,mx2=0,my1=0,my2=0; + long aq,bq,dx,dy,r,rx,ry,a,b; + + a=w>>1; + b=h>>1; + gdImageSetPixel(im,mx+a, my, c); + gdImageSetPixel(im,mx-a, my, c); + mx1 = mx-a; + my1 = my; + mx2 = mx+a; + my2 = my; + + aq = a * a; + bq = b * b; + dx = aq << 1; + dy = bq << 1; + r = a * bq; + rx = r << 1; + ry = 0; + x = a; + while (x > 0) { + if (r > 0) { + my1++; + my2--; + ry +=dx; + r -=ry; + } + if (r <= 0) { + x--; + mx1++; + mx2--; + rx -=dy; + r +=rx; + } + gdImageSetPixel(im,mx1, my1, c); + gdImageSetPixel(im,mx1, my2, c); + gdImageSetPixel(im,mx2, my1, c); + gdImageSetPixel(im,mx2, my2, c); + } +} + + +/* + Function: gdImageFilledEllipse +*/ +BGD_DECLARE(void) gdImageFilledEllipse (gdImagePtr im, int mx, int my, int w, int h, int c) +{ + int x=0,mx1=0,mx2=0,my1=0,my2=0; + long aq,bq,dx,dy,r,rx,ry,a,b; + int i; + int old_y2; + + a=w>>1; + b=h>>1; + + for (x = mx-a; x <= mx+a; x++) { + gdImageSetPixel(im, x, my, c); + } + + mx1 = mx-a; + my1 = my; + mx2 = mx+a; + my2 = my; + + aq = a * a; + bq = b * b; + dx = aq << 1; + dy = bq << 1; + r = a * bq; + rx = r << 1; + ry = 0; + x = a; + old_y2=-2; + while (x > 0) { + if (r > 0) { + my1++; + my2--; + ry +=dx; + r -=ry; + } + if (r <= 0) { + x--; + mx1++; + mx2--; + rx -=dy; + r +=rx; + } + + if(old_y2!=my2) { + for(i=mx1; i<=mx2; i++) { + gdImageSetPixel(im,i,my2,c); + gdImageSetPixel(im,i,my1,c); + } + } + old_y2 = my2; + } +} + +/* + Function: gdImageFillToBorder +*/ +BGD_DECLARE(void) gdImageFillToBorder (gdImagePtr im, int x, int y, int border, int color) +{ + int lastBorder; + /* Seek left */ + int leftLimit, rightLimit; + int i; + int restoreAlphaBleding; + + if (border < 0 || color < 0) { + /* Refuse to fill to a non-solid border */ + return; + } + + if (!im->trueColor) { + if ((color > (im->colorsTotal - 1)) || (border > (im->colorsTotal - 1)) || (color < 0)) { + return; + } + } + + leftLimit = (-1); + + restoreAlphaBleding = im->alphaBlendingFlag; + im->alphaBlendingFlag = 0; + + if (x >= im->sx) { + x = im->sx - 1; + } else if (x < 0) { + x = 0; + } + if (y >= im->sy) { + y = im->sy - 1; + } else if (y < 0) { + y = 0; + } + + for (i = x; (i >= 0); i--) { + if (gdImageGetPixel (im, i, y) == border) { + break; + } + gdImageSetPixel (im, i, y, color); + leftLimit = i; + } + if (leftLimit == (-1)) { + im->alphaBlendingFlag = restoreAlphaBleding; + return; + } + /* Seek right */ + rightLimit = x; + for (i = (x + 1); (i < im->sx); i++) { + if (gdImageGetPixel (im, i, y) == border) { + break; + } + gdImageSetPixel (im, i, y, color); + rightLimit = i; + } + /* Look at lines above and below and start paints */ + /* Above */ + if (y > 0) { + lastBorder = 1; + for (i = leftLimit; (i <= rightLimit); i++) { + int c; + c = gdImageGetPixel (im, i, y - 1); + if (lastBorder) { + if ((c != border) && (c != color)) { + gdImageFillToBorder (im, i, y - 1, border, color); + lastBorder = 0; + } + } else if ((c == border) || (c == color)) { + lastBorder = 1; + } + } + } + /* Below */ + if (y < ((im->sy) - 1)) { + lastBorder = 1; + for (i = leftLimit; (i <= rightLimit); i++) { + int c = gdImageGetPixel (im, i, y + 1); + if (lastBorder) { + if ((c != border) && (c != color)) { + gdImageFillToBorder (im, i, y + 1, border, color); + lastBorder = 0; + } + } else if ((c == border) || (c == color)) { + lastBorder = 1; + } + } + } + im->alphaBlendingFlag = restoreAlphaBleding; +} + +/* + * set the pixel at (x,y) and its 4-connected neighbors + * with the same pixel value to the new pixel value nc (new color). + * A 4-connected neighbor: pixel above, below, left, or right of a pixel. + * ideas from comp.graphics discussions. + * For tiled fill, the use of a flag buffer is mandatory. As the tile image can + * contain the same color as the color to fill. To do not bloat normal filling + * code I added a 2nd private function. + */ + +static int gdImageTileGet (gdImagePtr im, int x, int y) +{ + int srcx, srcy; + int tileColor,p; + if (!im->tile) { + return -1; + } + srcx = x % gdImageSX(im->tile); + srcy = y % gdImageSY(im->tile); + p = gdImageGetPixel(im->tile, srcx, srcy); + if (p == im->tile->transparent) { + tileColor = im->transparent; + } else if (im->trueColor) { + if (im->tile->trueColor) { + tileColor = p; + } else { + tileColor = gdTrueColorAlpha( gdImageRed(im->tile,p), gdImageGreen(im->tile,p), gdImageBlue (im->tile,p), gdImageAlpha (im->tile,p)); + } + } else { + if (im->tile->trueColor) { + tileColor = gdImageColorResolveAlpha(im, gdTrueColorGetRed (p), gdTrueColorGetGreen (p), gdTrueColorGetBlue (p), gdTrueColorGetAlpha (p)); + } else { + tileColor = gdImageColorResolveAlpha(im, gdImageRed (im->tile,p), gdImageGreen (im->tile,p), gdImageBlue (im->tile,p), gdImageAlpha (im->tile,p)); + } + } + return tileColor; +} + + + +/* horizontal segment of scan line y */ +struct seg { + int y, xl, xr, dy; +}; + +/* max depth of stack */ +#define FILL_MAX ((int)(im->sy*im->sx)/4) +#define FILL_PUSH(Y, XL, XR, DY) \ + if (sp<stack+FILL_MAX && Y+(DY)>=0 && Y+(DY)<wy2) \ + {sp->y = Y; sp->xl = XL; sp->xr = XR; sp->dy = DY; sp++;} + +#define FILL_POP(Y, XL, XR, DY) \ + {sp--; Y = sp->y+(DY = sp->dy); XL = sp->xl; XR = sp->xr;} + +static void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc); + +/* + Function: gdImageFill +*/ +BGD_DECLARE(void) gdImageFill(gdImagePtr im, int x, int y, int nc) +{ + int l, x1, x2, dy; + int oc; /* old pixel value */ + int wx2,wy2; + + int alphablending_bak; + + /* stack of filled segments */ + /* struct seg stack[FILL_MAX],*sp = stack; */ + struct seg *stack; + struct seg *sp; + + if (!im->trueColor && nc > (im->colorsTotal - 1)) { + return; + } + + alphablending_bak = im->alphaBlendingFlag; + im->alphaBlendingFlag = 0; + + if (nc==gdTiled) { + _gdImageFillTiled(im,x,y,nc); + im->alphaBlendingFlag = alphablending_bak; + return; + } + + wx2=im->sx; + wy2=im->sy; + oc = gdImageGetPixel(im, x, y); + if (oc==nc || x<0 || x>wx2 || y<0 || y>wy2) { + im->alphaBlendingFlag = alphablending_bak; + return; + } + + /* Do not use the 4 neighbors implementation with + * small images + */ + if (im->sx < 4) { + int ix = x, iy = y, c; + do { + do { + c = gdImageGetPixel(im, ix, iy); + if (c != oc) { + goto done; + } + gdImageSetPixel(im, ix, iy, nc); + } while(ix++ < (im->sx -1)); + ix = x; + } while(iy++ < (im->sy -1)); + goto done; + } + + if(overflow2(im->sy, im->sx)) { + return; + } + + if(overflow2(sizeof(struct seg), ((im->sy * im->sx) / 4))) { + return; + } + + stack = (struct seg *)gdMalloc(sizeof(struct seg) * ((int)(im->sy*im->sx)/4)); + if (!stack) { + return; + } + sp = stack; + + /* required! */ + FILL_PUSH(y,x,x,1); + /* seed segment (popped 1st) */ + FILL_PUSH(y+1, x, x, -1); + while (sp>stack) { + FILL_POP(y, x1, x2, dy); + + for (x=x1; x>=0 && gdImageGetPixel(im,x, y)==oc; x--) { + gdImageSetPixel(im,x, y, nc); + } + if (x>=x1) { + goto skip; + } + l = x+1; + + /* leak on left? */ + if (l<x1) { + FILL_PUSH(y, l, x1-1, -dy); + } + x = x1+1; + do { + for (; x<=wx2 && gdImageGetPixel(im,x, y)==oc; x++) { + gdImageSetPixel(im, x, y, nc); + } + FILL_PUSH(y, l, x-1, dy); + /* leak on right? */ + if (x>x2+1) { + FILL_PUSH(y, x2+1, x-1, -dy); + } +skip: + for (x++; x<=x2 && (gdImageGetPixel(im, x, y)!=oc); x++); + + l = x; + } while (x<=x2); + } + + gdFree(stack); + +done: + im->alphaBlendingFlag = alphablending_bak; +} + +static void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc) +{ + int l, x1, x2, dy; + int oc; /* old pixel value */ + int wx2,wy2; + /* stack of filled segments */ + struct seg *stack; + struct seg *sp; + char *pts; + + if (!im->tile) { + return; + } + + wx2=im->sx; + wy2=im->sy; + + if(overflow2(im->sy, im->sx)) { + return; + } + + if(overflow2(sizeof(struct seg), ((im->sy * im->sx) / 4))) { + return; + } + + pts = (char *) gdCalloc(im->sy * im->sx, sizeof(char)); + if (!pts) { + return; + } + + stack = (struct seg *)gdMalloc(sizeof(struct seg) * ((int)(im->sy*im->sx)/4)); + if (!stack) { + gdFree(pts); + return; + } + sp = stack; + + oc = gdImageGetPixel(im, x, y); + + /* required! */ + FILL_PUSH(y,x,x,1); + /* seed segment (popped 1st) */ + FILL_PUSH(y+1, x, x, -1); + while (sp>stack) { + FILL_POP(y, x1, x2, dy); + for (x=x1; x>=0 && (!pts[y + x*wy2] && gdImageGetPixel(im,x,y)==oc); x--) { + nc = gdImageTileGet(im,x,y); + pts[y + x*wy2]=1; + gdImageSetPixel(im,x, y, nc); + } + if (x>=x1) { + goto skip; + } + l = x+1; + + /* leak on left? */ + if (l<x1) { + FILL_PUSH(y, l, x1-1, -dy); + } + x = x1+1; + do { + for (; x<wx2 && (!pts[y + x*wy2] && gdImageGetPixel(im,x, y)==oc) ; x++) { + if (pts[y + x*wy2]) { + /* we should never be here */ + break; + } + nc = gdImageTileGet(im,x,y); + pts[y + x*wy2]=1; + gdImageSetPixel(im, x, y, nc); + } + FILL_PUSH(y, l, x-1, dy); + /* leak on right? */ + if (x>x2+1) { + FILL_PUSH(y, x2+1, x-1, -dy); + } +skip: + for (x++; x<=x2 && (pts[y + x*wy2] || gdImageGetPixel(im,x, y)!=oc); x++); + l = x; + } while (x<=x2); + } + + gdFree(pts); + gdFree(stack); +} + +/** + * Function: gdImageRectangle + * + * Draws a rectangle. + * + * Parameters: + * im - The image. + * x1 - The x-coordinate of the upper left corner. + * y1 - The y-coordinate of the upper left corner. + * x2 - The x-coordinate of the lower right corner. + * y2 - The y-coordinate of the lower right corner. + * color - The color. + * + * Note that x1,y1 and x2,y2 may be swapped, i.e. the former may designate the + * lower right corner and the latter the upper left corner. The behavior for + * specifying other corners is undefined. + * + * See also: + * - <gdImageFilledRectangle> + */ +BGD_DECLARE(void) gdImageRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color) +{ + int thick = im->thick; + + if (x1 == x2 && y1 == y2 && thick == 1) { + gdImageSetPixel(im, x1, y1, color); + return; + } + + if (y2 < y1) { + int t; + t = y1; + y1 = y2; + y2 = t; + + t = x1; + x1 = x2; + x2 = t; + } + + if (thick > 1) { + int cx, cy, x1ul, y1ul, x2lr, y2lr; + int half = thick >> 1; + x1ul = x1 - half; + y1ul = y1 - half; + + x2lr = x2 + half; + y2lr = y2 + half; + + cy = y1ul + thick; + while (cy-- > y1ul) { + cx = x1ul - 1; + while (cx++ < x2lr) { + gdImageSetPixel(im, cx, cy, color); + } + } + + cy = y2lr - thick; + while (cy++ < y2lr) { + cx = x1ul - 1; + while (cx++ < x2lr) { + gdImageSetPixel(im, cx, cy, color); + } + } + + cy = y1ul + thick - 1; + while (cy++ < y2lr -thick) { + cx = x1ul - 1; + while (cx++ < x1ul + thick) { + gdImageSetPixel(im, cx, cy, color); + } + } + + cy = y1ul + thick - 1; + while (cy++ < y2lr -thick) { + cx = x2lr - thick - 1; + while (cx++ < x2lr) { + gdImageSetPixel(im, cx, cy, color); + } + } + + return; + } else { + if (x1 == x2 || y1 == y2) { + gdImageLine(im, x1, y1, x2, y2, color); + } else { + gdImageLine(im, x1, y1, x2, y1, color); + gdImageLine(im, x1, y2, x2, y2, color); + gdImageLine(im, x1, y1 + 1, x1, y2 - 1, color); + gdImageLine(im, x2, y1 + 1, x2, y2 - 1, color); + } + } +} + +static void _gdImageFilledHRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, + int color) +{ + int x, y; + + if (x1 == x2 && y1 == y2) { + gdImageSetPixel(im, x1, y1, color); + return; + } + + if (x1 > x2) { + x = x1; + x1 = x2; + x2 = x; + } + + if (y1 > y2) { + y = y1; + y1 = y2; + y2 = y; + } + + if (x1 < 0) { + x1 = 0; + } + + if (x2 >= gdImageSX(im)) { + x2 = gdImageSX(im) - 1; + } + + if (y1 < 0) { + y1 = 0; + } + + if (y2 >= gdImageSY(im)) { + y2 = gdImageSY(im) - 1; + } + + for (x = x1; (x <= x2); x++) { + for (y = y1; (y <= y2); y++) { + gdImageSetPixel (im, x, y, color); + } + } +} + +static void _gdImageFilledVRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, + int color) +{ + int x, y; + + if (x1 == x2 && y1 == y2) { + gdImageSetPixel(im, x1, y1, color); + return; + } + + if (x1 > x2) { + x = x1; + x1 = x2; + x2 = x; + } + + if (y1 > y2) { + y = y1; + y1 = y2; + y2 = y; + } + + if (x1 < 0) { + x1 = 0; + } + + if (x2 >= gdImageSX(im)) { + x2 = gdImageSX(im) - 1; + } + + if (y1 < 0) { + y1 = 0; + } + + if (y2 >= gdImageSY(im)) { + y2 = gdImageSY(im) - 1; + } + + for (y = y1; (y <= y2); y++) { + for (x = x1; (x <= x2); x++) { + gdImageSetPixel (im, x, y, color); + } + } +} + +/* + Function: gdImageFilledRectangle +*/ +BGD_DECLARE(void) gdImageFilledRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, + int color) +{ + _gdImageFilledVRectangle(im, x1, y1, x2, y2, color); +} + +/** + * Group: Cloning and Copying + */ + +/** + * Function: gdImageClone + * + * Clones an image + * + * Creates an exact duplicate of the given image. + * + * Parameters: + * src - The source image. + * + * Returns: + * The cloned image on success, NULL on failure. + */ +BGD_DECLARE(gdImagePtr) gdImageClone (gdImagePtr src) { + gdImagePtr dst; + register int i, x; + + if (src->trueColor) { + dst = gdImageCreateTrueColor(src->sx , src->sy); + } else { + dst = gdImageCreate(src->sx , src->sy); + } + + if (dst == NULL) { + return NULL; + } + + if (src->trueColor == 0) { + dst->colorsTotal = src->colorsTotal; + for (i = 0; i < gdMaxColors; i++) { + dst->red[i] = src->red[i]; + dst->green[i] = src->green[i]; + dst->blue[i] = src->blue[i]; + dst->alpha[i] = src->alpha[i]; + dst->open[i] = src->open[i]; + } + for (i = 0; i < src->sy; i++) { + for (x = 0; x < src->sx; x++) { + dst->pixels[i][x] = src->pixels[i][x]; + } + } + } else { + for (i = 0; i < src->sy; i++) { + for (x = 0; x < src->sx; x++) { + dst->tpixels[i][x] = src->tpixels[i][x]; + } + } + } + + if (src->styleLength > 0) { + dst->styleLength = src->styleLength; + dst->stylePos = src->stylePos; + for (i = 0; i < src->styleLength; i++) { + dst->style[i] = src->style[i]; + } + } + + dst->interlace = src->interlace; + + dst->alphaBlendingFlag = src->alphaBlendingFlag; + dst->saveAlphaFlag = src->saveAlphaFlag; + dst->AA = src->AA; + dst->AA_color = src->AA_color; + dst->AA_dont_blend = src->AA_dont_blend; + + dst->cx1 = src->cx1; + dst->cy1 = src->cy1; + dst->cx2 = src->cx2; + dst->cy2 = src->cy2; + + dst->res_x = src->res_x; + dst->res_y = src->res_y; + + dst->paletteQuantizationMethod = src->paletteQuantizationMethod; + dst->paletteQuantizationSpeed = src->paletteQuantizationSpeed; + dst->paletteQuantizationMinQuality = src->paletteQuantizationMinQuality; + dst->paletteQuantizationMinQuality = src->paletteQuantizationMinQuality; + + dst->interpolation_id = src->interpolation_id; + dst->interpolation = src->interpolation; + + if (src->brush) { + dst->brush = gdImageClone(src->brush); + } + + if (src->tile) { + dst->tile = gdImageClone(src->tile); + } + + if (src->style) { + gdImageSetStyle(dst, src->style, src->styleLength); + } + + for (i = 0; i < gdMaxColors; i++) { + dst->brushColorMap[i] = src->brushColorMap[i]; + dst->tileColorMap[i] = src->tileColorMap[i]; + } + + if (src->polyAllocated > 0) { + dst->polyAllocated = src->polyAllocated; + for (i = 0; i < src->polyAllocated; i++) { + dst->polyInts[i] = src->polyInts[i]; + } + } + + return dst; +} + +/** + * Function: gdImageCopy + * + * Copy an area of an image to another image + * + * Parameters: + * dst - The destination image. + * src - The source image. + * dstX - The x-coordinate of the upper left corner to copy to. + * dstY - The y-coordinate of the upper left corner to copy to. + * srcX - The x-coordinate of the upper left corner to copy from. + * srcY - The y-coordinate of the upper left corner to copy from. + * w - The width of the area to copy. + * h - The height of the area to copy. + * + * See also: + * - <gdImageCopyMerge> + * - <gdImageCopyMergeGray> + */ +BGD_DECLARE(void) gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, + int srcY, int w, int h) +{ + int c; + int x, y; + int tox, toy; + int i; + int colorMap[gdMaxColors]; + + if (dst->trueColor) { + /* 2.0: much easier when the destination is truecolor. */ + /* 2.0.10: needs a transparent-index check that is still valid if + * * the source is not truecolor. Thanks to Frank Warmerdam. + */ + + if (src->trueColor) { + for (y = 0; (y < h); y++) { + for (x = 0; (x < w); x++) { + int c = gdImageGetTrueColorPixel (src, srcX + x, srcY + y); + if (c != src->transparent) { + gdImageSetPixel (dst, dstX + x, dstY + y, c); + } + } + } + } else { + /* source is palette based */ + for (y = 0; (y < h); y++) { + for (x = 0; (x < w); x++) { + int c = gdImageGetPixel (src, srcX + x, srcY + y); + if (c != src->transparent) { + gdImageSetPixel(dst, dstX + x, dstY + y, gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c])); + } + } + } + } + return; + } + + for (i = 0; (i < gdMaxColors); i++) { + colorMap[i] = (-1); + } + toy = dstY; + for (y = srcY; (y < (srcY + h)); y++) { + tox = dstX; + for (x = srcX; (x < (srcX + w)); x++) { + int nc; + int mapTo; + c = gdImageGetPixel (src, x, y); + /* Added 7/24/95: support transparent copies */ + if (gdImageGetTransparent (src) == c) { + tox++; + continue; + } + /* Have we established a mapping for this color? */ + if (src->trueColor) { + /* 2.05: remap to the palette available in the + destination image. This is slow and + works badly, but it beats crashing! Thanks + to Padhrig McCarthy. */ + mapTo = gdImageColorResolveAlpha (dst, + gdTrueColorGetRed (c), + gdTrueColorGetGreen (c), + gdTrueColorGetBlue (c), + gdTrueColorGetAlpha (c)); + } else if (colorMap[c] == (-1)) { + /* If it's the same image, mapping is trivial */ + if (dst == src) { + nc = c; + } else { + /* Get best match possible. This + function never returns error. */ + nc = gdImageColorResolveAlpha (dst, + src->red[c], src->green[c], + src->blue[c], src->alpha[c]); + } + colorMap[c] = nc; + mapTo = colorMap[c]; + } else { + mapTo = colorMap[c]; + } + gdImageSetPixel (dst, tox, toy, mapTo); + tox++; + } + toy++; + } +} + +/** + * Function: gdImageCopyMerge + * + * Copy an area of an image to another image ignoring alpha + * + * The source area will be copied to the destination are by merging the pixels. + * + * Note: + * This function is a substitute for real alpha channel operations, + * so it doesn't pay attention to the alpha channel. + * + * Parameters: + * dst - The destination image. + * src - The source image. + * dstX - The x-coordinate of the upper left corner to copy to. + * dstY - The y-coordinate of the upper left corner to copy to. + * srcX - The x-coordinate of the upper left corner to copy from. + * srcY - The y-coordinate of the upper left corner to copy from. + * w - The width of the area to copy. + * h - The height of the area to copy. + * pct - The percentage in range 0..100. + * + * See also: + * - <gdImageCopy> + * - <gdImageCopyMergeGray> + */ +BGD_DECLARE(void) gdImageCopyMerge (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, + int srcX, int srcY, int w, int h, int pct) +{ + + int c, dc; + int x, y; + int tox, toy; + int ncR, ncG, ncB; + toy = dstY; + for (y = srcY; (y < (srcY + h)); y++) { + tox = dstX; + for (x = srcX; (x < (srcX + w)); x++) { + int nc; + c = gdImageGetPixel (src, x, y); + /* Added 7/24/95: support transparent copies */ + if (gdImageGetTransparent (src) == c) { + tox++; + continue; + } + /* If it's the same image, mapping is trivial */ + if (dst == src) { + nc = c; + } else { + dc = gdImageGetPixel (dst, tox, toy); + + ncR = gdImageRed (src, c) * (pct / 100.0) + + gdImageRed (dst, dc) * ((100 - pct) / 100.0); + ncG = gdImageGreen (src, c) * (pct / 100.0) + + gdImageGreen (dst, dc) * ((100 - pct) / 100.0); + ncB = gdImageBlue (src, c) * (pct / 100.0) + + gdImageBlue (dst, dc) * ((100 - pct) / 100.0); + + /* Find a reasonable color */ + nc = gdImageColorResolve (dst, ncR, ncG, ncB); + } + gdImageSetPixel (dst, tox, toy, nc); + tox++; + } + toy++; + } +} + +/** + * Function: gdImageCopyMergeGray + * + * Copy an area of an image to another image ignoring alpha + * + * The source area will be copied to the grayscaled destination area by merging + * the pixels. + * + * Note: + * This function is a substitute for real alpha channel operations, + * so it doesn't pay attention to the alpha channel. + * + * Parameters: + * dst - The destination image. + * src - The source image. + * dstX - The x-coordinate of the upper left corner to copy to. + * dstY - The y-coordinate of the upper left corner to copy to. + * srcX - The x-coordinate of the upper left corner to copy from. + * srcY - The y-coordinate of the upper left corner to copy from. + * w - The width of the area to copy. + * h - The height of the area to copy. + * pct - The percentage of the source color intensity in range 0..100. + * + * See also: + * - <gdImageCopy> + * - <gdImageCopyMerge> + */ +BGD_DECLARE(void) gdImageCopyMergeGray (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, + int srcX, int srcY, int w, int h, int pct) +{ + + int c, dc; + int x, y; + int tox, toy; + int ncR, ncG, ncB; + float g; + toy = dstY; + for (y = srcY; (y < (srcY + h)); y++) { + tox = dstX; + for (x = srcX; (x < (srcX + w)); x++) { + int nc; + c = gdImageGetPixel (src, x, y); + /* Added 7/24/95: support transparent copies */ + if (gdImageGetTransparent (src) == c) { + tox++; + continue; + } + /* + * If it's the same image, mapping is NOT trivial since we + * merge with greyscale target, but if pct is 100, the grey + * value is not used, so it becomes trivial. pjw 2.0.12. + */ + if (dst == src && pct == 100) { + nc = c; + } else { + dc = gdImageGetPixel (dst, tox, toy); + g = 0.29900 * gdImageRed(dst, dc) + + 0.58700 * gdImageGreen(dst, dc) + 0.11400 * gdImageBlue(dst, dc); + + ncR = gdImageRed (src, c) * (pct / 100.0) + + g * ((100 - pct) / 100.0); + ncG = gdImageGreen (src, c) * (pct / 100.0) + + g * ((100 - pct) / 100.0); + ncB = gdImageBlue (src, c) * (pct / 100.0) + + g * ((100 - pct) / 100.0); + + /* First look for an exact match */ + nc = gdImageColorExact (dst, ncR, ncG, ncB); + if (nc == (-1)) { + /* No, so try to allocate it */ + nc = gdImageColorAllocate (dst, ncR, ncG, ncB); + /* If we're out of colors, go for the + closest color */ + if (nc == (-1)) { + nc = gdImageColorClosest (dst, ncR, ncG, ncB); + } + } + } + gdImageSetPixel (dst, tox, toy, nc); + tox++; + } + toy++; + } +} + +/** + * Function: gdImageCopyResized + * + * Copy a resized area from an image to another image + * + * If the source and destination area differ in size, the area will be resized + * using nearest-neighbor interpolation. + * + * Parameters: + * dst - The destination image. + * src - The source image. + * dstX - The x-coordinate of the upper left corner to copy to. + * dstY - The y-coordinate of the upper left corner to copy to. + * srcX - The x-coordinate of the upper left corner to copy from. + * srcY - The y-coordinate of the upper left corner to copy from. + * dstW - The width of the area to copy to. + * dstH - The height of the area to copy to. + * srcW - The width of the area to copy from. + * srcH - The height of the area to copy from. + * + * See also: + * - <gdImageCopyResampled> + * - <gdImageScale> + */ +BGD_DECLARE(void) gdImageCopyResized (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, + int srcX, int srcY, int dstW, int dstH, int srcW, + int srcH) +{ + int c; + int x, y; + int tox, toy; + int ydest; + int i; + int colorMap[gdMaxColors]; + /* Stretch vectors */ + int *stx; + int *sty; + /* We only need to use floating point to determine the correct + stretch vector for one line's worth. */ + if (overflow2(sizeof (int), srcW)) { + return; + } + if (overflow2(sizeof (int), srcH)) { + return; + } + stx = (int *) gdMalloc (sizeof (int) * srcW); + if (!stx) { + return; + } + + sty = (int *) gdMalloc (sizeof (int) * srcH); + if (!sty) { + gdFree(stx); + return; + } + + /* Fixed by Mao Morimoto 2.0.16 */ + for (i = 0; (i < srcW); i++) { + stx[i] = dstW * (i + 1) / srcW - dstW * i / srcW; + } + for (i = 0; (i < srcH); i++) { + sty[i] = dstH * (i + 1) / srcH - dstH * i / srcH; + } + for (i = 0; (i < gdMaxColors); i++) { + colorMap[i] = (-1); + } + toy = dstY; + for (y = srcY; (y < (srcY + srcH)); y++) { + for (ydest = 0; (ydest < sty[y - srcY]); ydest++) { + tox = dstX; + for (x = srcX; (x < (srcX + srcW)); x++) { + int nc = 0; + int mapTo; + if (!stx[x - srcX]) { + continue; + } + if (dst->trueColor) { + /* 2.0.9: Thorben Kundinger: Maybe the source image is not + a truecolor image */ + if (!src->trueColor) { + int tmp = gdImageGetPixel (src, x, y); + mapTo = gdImageGetTrueColorPixel (src, x, y); + if (gdImageGetTransparent (src) == tmp) { + /* 2.0.21, TK: not tox++ */ + tox += stx[x - srcX]; + continue; + } + } else { + /* TK: old code follows */ + mapTo = gdImageGetTrueColorPixel (src, x, y); + /* Added 7/24/95: support transparent copies */ + if (gdImageGetTransparent (src) == mapTo) { + /* 2.0.21, TK: not tox++ */ + tox += stx[x - srcX]; + continue; + } + } + } else { + c = gdImageGetPixel (src, x, y); + /* Added 7/24/95: support transparent copies */ + if (gdImageGetTransparent (src) == c) { + tox += stx[x - srcX]; + continue; + } + if (src->trueColor) { + /* Remap to the palette available in the + destination image. This is slow and + works badly. */ + mapTo = gdImageColorResolveAlpha (dst, + gdTrueColorGetRed (c), + gdTrueColorGetGreen + (c), + gdTrueColorGetBlue + (c), + gdTrueColorGetAlpha + (c)); + } else { + /* Have we established a mapping for this color? */ + if (colorMap[c] == (-1)) { + /* If it's the same image, mapping is trivial */ + if (dst == src) { + nc = c; + } else { + /* Find or create the best match */ + /* 2.0.5: can't use gdTrueColorGetRed, etc with palette */ + nc = gdImageColorResolveAlpha (dst, + gdImageRed (src, + c), + gdImageGreen + (src, c), + gdImageBlue (src, + c), + gdImageAlpha + (src, c)); + } + colorMap[c] = nc; + } + mapTo = colorMap[c]; + } + } + for (i = 0; (i < stx[x - srcX]); i++) { + gdImageSetPixel (dst, tox, toy, mapTo); + tox++; + } + } + toy++; + } + } + gdFree (stx); + gdFree (sty); +} + +/** + * Function: gdImageCopyRotated + * + * Copy a rotated area from an image to another image + * + * The area is counter-clockwise rotated using nearest-neighbor interpolation. + * + * Parameters: + * dst - The destination image. + * src - The source image. + * dstX - The x-coordinate of the center of the area to copy to. + * dstY - The y-coordinate of the center of the area to copy to. + * srcX - The x-coordinate of the upper left corner to copy from. + * srcY - The y-coordinate of the upper left corner to copy from. + * srcW - The width of the area to copy from. + * srcH - The height of the area to copy from. + * angle - The angle in degrees. + * + * See also: + * - <gdImageRotateInterpolated> + */ +BGD_DECLARE(void) gdImageCopyRotated (gdImagePtr dst, + gdImagePtr src, + double dstX, double dstY, + int srcX, int srcY, + int srcWidth, int srcHeight, int angle) +{ + double dx, dy; + double radius = sqrt (srcWidth * srcWidth + srcHeight * srcHeight); + double aCos = cos (angle * .0174532925); + double aSin = sin (angle * .0174532925); + double scX = srcX + ((double) srcWidth) / 2; + double scY = srcY + ((double) srcHeight) / 2; + int cmap[gdMaxColors]; + int i; + + /* + 2.0.34: transparency preservation. The transparentness of + the transparent color is more important than its hue. + */ + if (src->transparent != -1) { + if (dst->transparent == -1) { + dst->transparent = src->transparent; + } + } + + for (i = 0; (i < gdMaxColors); i++) { + cmap[i] = (-1); + } + for (dy = dstY - radius; (dy <= dstY + radius); dy++) { + for (dx = dstX - radius; (dx <= dstX + radius); dx++) { + double sxd = (dx - dstX) * aCos - (dy - dstY) * aSin; + double syd = (dy - dstY) * aCos + (dx - dstX) * aSin; + int sx = sxd + scX; + int sy = syd + scY; + if ((sx >= srcX) && (sx < srcX + srcWidth) && + (sy >= srcY) && (sy < srcY + srcHeight)) { + int c = gdImageGetPixel (src, sx, sy); + /* 2.0.34: transparency wins */ + if (c == src->transparent) { + gdImageSetPixel (dst, dx, dy, dst->transparent); + } else if (!src->trueColor) { + /* Use a table to avoid an expensive + lookup on every single pixel */ + if (cmap[c] == -1) { + cmap[c] = gdImageColorResolveAlpha (dst, + gdImageRed (src, c), + gdImageGreen (src, + c), + gdImageBlue (src, + c), + gdImageAlpha (src, + c)); + } + gdImageSetPixel (dst, dx, dy, cmap[c]); + } else { + gdImageSetPixel (dst, + dx, dy, + gdImageColorResolveAlpha (dst, + gdImageRed (src, + c), + gdImageGreen + (src, c), + gdImageBlue (src, + c), + gdImageAlpha + (src, c))); + } + } + } + } +} + +/* When gd 1.x was first created, floating point was to be avoided. + These days it is often faster than table lookups or integer + arithmetic. The routine below is shamelessly, gloriously + floating point. TBB */ + +/* 2.0.10: cast instead of floor() yields 35% performance improvement. + Thanks to John Buckman. */ + +#define floor2(exp) ((long) exp) +/*#define floor2(exp) floor(exp)*/ + +/** + * Function: gdImageCopyResampled + * + * Copy a resampled area from an image to another image + * + * If the source and destination area differ in size, the area will be resized + * using bilinear interpolation for truecolor images, and nearest-neighbor + * interpolation for palette images. + * + * Parameters: + * dst - The destination image. + * src - The source image. + * dstX - The x-coordinate of the upper left corner to copy to. + * dstY - The y-coordinate of the upper left corner to copy to. + * srcX - The x-coordinate of the upper left corner to copy from. + * srcY - The y-coordinate of the upper left corner to copy from. + * dstW - The width of the area to copy to. + * dstH - The height of the area to copy to. + * srcW - The width of the area to copy from. + * srcH - The height of the area to copy from. + * + * See also: + * - <gdImageCopyResized> + * - <gdImageScale> + */ +BGD_DECLARE(void) gdImageCopyResampled (gdImagePtr dst, + gdImagePtr src, + int dstX, int dstY, + int srcX, int srcY, + int dstW, int dstH, int srcW, int srcH) +{ + int x, y; + if (!dst->trueColor) { + gdImageCopyResized (dst, src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH); + return; + } + for (y = dstY; (y < dstY + dstH); y++) { + for (x = dstX; (x < dstX + dstW); x++) { + float sy1, sy2, sx1, sx2; + float sx, sy; + float spixels = 0.0; + float red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0; + float alpha_factor, alpha_sum = 0.0, contrib_sum = 0.0; + sy1 = ((float)(y - dstY)) * (float)srcH / (float)dstH; + sy2 = ((float)(y + 1 - dstY)) * (float) srcH / (float) dstH; + sy = sy1; + do { + float yportion; + if (floorf(sy) == floorf(sy1)) { + yportion = 1.0 - (sy - floorf(sy)); + if (yportion > sy2 - sy1) { + yportion = sy2 - sy1; + } + sy = floorf(sy); + } else if (sy == floorf(sy2)) { + yportion = sy2 - floorf(sy2); + } else { + yportion = 1.0; + } + sx1 = ((float)(x - dstX)) * (float) srcW / dstW; + sx2 = ((float)(x + 1 - dstX)) * (float) srcW / dstW; + sx = sx1; + do { + float xportion; + float pcontribution; + int p; + if (floorf(sx) == floorf(sx1)) { + xportion = 1.0 - (sx - floorf(sx)); + if (xportion > sx2 - sx1) { + xportion = sx2 - sx1; + } + sx = floorf(sx); + } else if (sx == floorf(sx2)) { + xportion = sx2 - floorf(sx2); + } else { + xportion = 1.0; + } + pcontribution = xportion * yportion; + p = gdImageGetTrueColorPixel(src, (int) sx + srcX, (int) sy + srcY); + + alpha_factor = ((gdAlphaMax - gdTrueColorGetAlpha(p))) * pcontribution; + red += gdTrueColorGetRed (p) * alpha_factor; + green += gdTrueColorGetGreen (p) * alpha_factor; + blue += gdTrueColorGetBlue (p) * alpha_factor; + alpha += gdTrueColorGetAlpha (p) * pcontribution; + alpha_sum += alpha_factor; + contrib_sum += pcontribution; + spixels += xportion * yportion; + sx += 1.0; + } + while (sx < sx2); + sy += 1.0f; + } + while (sy < sy2); + + if (spixels != 0.0) { + red /= spixels; + green /= spixels; + blue /= spixels; + alpha /= spixels; + } + if ( alpha_sum != 0.0) { + if( contrib_sum != 0.0) { + alpha_sum /= contrib_sum; + } + red /= alpha_sum; + green /= alpha_sum; + blue /= alpha_sum; + } + /* Clamping to allow for rounding errors above */ + if (red > 255.0) { + red = 255.0; + } + if (green > 255.0) { + green = 255.0; + } + if (blue > 255.0f) { + blue = 255.0; + } + if (alpha > gdAlphaMax) { + alpha = gdAlphaMax; + } + gdImageSetPixel(dst, x, y, gdTrueColorAlpha ((int) red, (int) green, (int) blue, (int) alpha)); + } + } +} + +/** + * Group: Polygons + */ + +/** + * Function: gdImagePolygon + * + * Draws a closed polygon + * + * Parameters: + * im - The image. + * p - The vertices as array of <gdPoint>s. + * n - The number of vertices. + * c - The color. + * + * See also: + * - <gdImageOpenPolygon> + * - <gdImageFilledPolygon> + */ +BGD_DECLARE(void) gdImagePolygon (gdImagePtr im, gdPointPtr p, int n, int c) +{ + if (n <= 0) { + return; + } + + + gdImageLine (im, p->x, p->y, p[n - 1].x, p[n - 1].y, c); + gdImageOpenPolygon (im, p, n, c); +} + +/** + * Function: gdImageOpenPolygon + * + * Draws an open polygon + * + * Parameters: + * im - The image. + * p - The vertices as array of <gdPoint>s. + * n - The number of vertices. + * c - The color + * + * See also: + * - <gdImagePolygon> + */ +BGD_DECLARE(void) gdImageOpenPolygon (gdImagePtr im, gdPointPtr p, int n, int c) +{ + int i; + int lx, ly; + if (n <= 0) { + return; + } + + + lx = p->x; + ly = p->y; + for (i = 1; (i < n); i++) { + p++; + gdImageLine (im, lx, ly, p->x, p->y, c); + lx = p->x; + ly = p->y; + } + +} + +/* THANKS to Kirsten Schulz for the polygon fixes! */ + +/* The intersection finding technique of this code could be improved */ +/* by remembering the previous intertersection, and by using the slope. */ +/* That could help to adjust intersections to produce a nice */ +/* interior_extrema. */ + +/** + * Function: gdImageFilledPolygon + * + * Draws a filled polygon + * + * The polygon is filled using the even-odd fillrule what can leave unfilled + * regions inside of self-intersecting polygons. This behavior might change in + * a future version. + * + * Parameters: + * im - The image. + * p - The vertices as array of <gdPoint>s. + * n - The number of vertices. + * c - The color + * + * See also: + * - <gdImagePolygon> + */ +BGD_DECLARE(void) gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int c) +{ + int i; + int j; + int index; + int y; + int miny, maxy, pmaxy; + int x1, y1; + int x2, y2; + int ind1, ind2; + int ints; + int fill_color; + if (n <= 0) { + return; + } + + if (c == gdAntiAliased) { + fill_color = im->AA_color; + } else { + fill_color = c; + } + if (!im->polyAllocated) { + if (overflow2(sizeof (int), n)) { + return; + } + im->polyInts = (int *) gdMalloc (sizeof (int) * n); + if (!im->polyInts) { + return; + } + im->polyAllocated = n; + } + if (im->polyAllocated < n) { + while (im->polyAllocated < n) { + im->polyAllocated *= 2; + } + if (overflow2(sizeof (int), im->polyAllocated)) { + return; + } + im->polyInts = (int *) gdReallocEx (im->polyInts, + sizeof (int) * im->polyAllocated); + if (!im->polyInts) { + return; + } + } + miny = p[0].y; + maxy = p[0].y; + for (i = 1; (i < n); i++) { + if (p[i].y < miny) { + miny = p[i].y; + } + if (p[i].y > maxy) { + maxy = p[i].y; + } + } + /* necessary special case: horizontal line */ + if (n > 1 && miny == maxy) { + x1 = x2 = p[0].x; + for (i = 1; (i < n); i++) { + if (p[i].x < x1) { + x1 = p[i].x; + } else if (p[i].x > x2) { + x2 = p[i].x; + } + } + gdImageLine(im, x1, miny, x2, miny, c); + return; + } + pmaxy = maxy; + /* 2.0.16: Optimization by Ilia Chipitsine -- don't waste time offscreen */ + /* 2.0.26: clipping rectangle is even better */ + if (miny < im->cy1) { + miny = im->cy1; + } + if (maxy > im->cy2) { + maxy = im->cy2; + } + /* Fix in 1.3: count a vertex only once */ + for (y = miny; (y <= maxy); y++) { + ints = 0; + for (i = 0; (i < n); i++) { + if (!i) { + ind1 = n - 1; + ind2 = 0; + } else { + ind1 = i - 1; + ind2 = i; + } + y1 = p[ind1].y; + y2 = p[ind2].y; + if (y1 < y2) { + x1 = p[ind1].x; + x2 = p[ind2].x; + } else if (y1 > y2) { + y2 = p[ind1].y; + y1 = p[ind2].y; + x2 = p[ind1].x; + x1 = p[ind2].x; + } else { + continue; + } + + /* Do the following math as float intermediately, and round to ensure + * that Polygon and FilledPolygon for the same set of points have the + * same footprint. */ + + if ((y >= y1) && (y < y2)) { + im->polyInts[ints++] = (int) ((float) ((y - y1) * (x2 - x1)) / + (float) (y2 - y1) + 0.5 + x1); + } else if ((y == pmaxy) && (y == y2)) { + im->polyInts[ints++] = x2; + } + } + /* + 2.0.26: polygons pretty much always have less than 100 points, + and most of the time they have considerably less. For such trivial + cases, insertion sort is a good choice. Also a good choice for + future implementations that may wish to indirect through a table. + */ + for (i = 1; (i < ints); i++) { + index = im->polyInts[i]; + j = i; + while ((j > 0) && (im->polyInts[j - 1] > index)) { + im->polyInts[j] = im->polyInts[j - 1]; + j--; + } + im->polyInts[j] = index; + } + for (i = 0; (i < (ints-1)); i += 2) { + /* 2.0.29: back to gdImageLine to prevent segfaults when + performing a pattern fill */ + gdImageLine (im, im->polyInts[i], y, im->polyInts[i + 1], y, + fill_color); + } + } + /* If we are drawing this AA, then redraw the border with AA lines. */ + /* This doesn't work as well as I'd like, but it doesn't clash either. */ + if (c == gdAntiAliased) { + gdImagePolygon (im, p, n, c); + } +} + +/** + * Group: other + */ + +static void gdImageSetAAPixelColor(gdImagePtr im, int x, int y, int color, int t); + +/** + * Function: gdImageSetStyle + * + * Sets the style for following drawing operations + * + * Parameters: + * im - The image. + * style - An array of color values. + * noOfPixel - The number of color values. + */ +BGD_DECLARE(void) gdImageSetStyle (gdImagePtr im, int *style, int noOfPixels) +{ + if (im->style) { + gdFree (im->style); + } + if (overflow2(sizeof (int), noOfPixels)) { + return; + } + im->style = (int *) gdMalloc (sizeof (int) * noOfPixels); + if (!im->style) { + return; + } + memcpy (im->style, style, sizeof (int) * noOfPixels); + im->styleLength = noOfPixels; + im->stylePos = 0; +} + +/** + * Function: gdImageSetThickness + * + * Sets the thickness for following drawing operations + * + * Parameters: + * im - The image. + * thickness - The thickness in pixels. + */ +BGD_DECLARE(void) gdImageSetThickness (gdImagePtr im, int thickness) +{ + im->thick = thickness; +} + +/** + * Function: gdImageSetBrush + * + * Sets the brush for following drawing operations + * + * Parameters: + * im - The image. + * brush - The brush image. + */ +BGD_DECLARE(void) gdImageSetBrush (gdImagePtr im, gdImagePtr brush) +{ + int i; + im->brush = brush; + if ((!im->trueColor) && (!im->brush->trueColor)) { + for (i = 0; (i < gdImageColorsTotal (brush)); i++) { + int index; + index = gdImageColorResolveAlpha (im, + gdImageRed (brush, i), + gdImageGreen (brush, i), + gdImageBlue (brush, i), + gdImageAlpha (brush, i)); + im->brushColorMap[i] = index; + } + } +} + +/* + Function: gdImageSetTile +*/ +BGD_DECLARE(void) gdImageSetTile (gdImagePtr im, gdImagePtr tile) +{ + int i; + im->tile = tile; + if ((!im->trueColor) && (!im->tile->trueColor)) { + for (i = 0; (i < gdImageColorsTotal (tile)); i++) { + int index; + index = gdImageColorResolveAlpha (im, + gdImageRed (tile, i), + gdImageGreen (tile, i), + gdImageBlue (tile, i), + gdImageAlpha (tile, i)); + im->tileColorMap[i] = index; + } + } +} + +/** + * Function: gdImageSetAntiAliased + * + * Set the color for subsequent anti-aliased drawing + * + * If <gdAntiAliased> is passed as color to drawing operations that support + * anti-aliased drawing (such as <gdImageLine> and <gdImagePolygon>), the actual + * color to be used can be set with this function. + * + * Example: draw an anti-aliased blue line: + * | gdImageSetAntiAliased(im, gdTrueColorAlpha(0, 0, gdBlueMax, gdAlphaOpaque)); + * | gdImageLine(im, 10,10, 20,20, gdAntiAliased); + * + * Parameters: + * im - The image. + * c - The color. + * + * See also: + * - <gdImageSetAntiAliasedDontBlend> + */ +BGD_DECLARE(void) gdImageSetAntiAliased (gdImagePtr im, int c) +{ + im->AA = 1; + im->AA_color = c; + im->AA_dont_blend = -1; +} + +/** + * Function: gdImageSetAntiAliasedDontBlend + * + * Set the color and "dont_blend" color for subsequent anti-aliased drawing + * + * This extended variant of <gdImageSetAntiAliased> allows to also specify a + * (background) color that will not be blended in anti-aliased drawing + * operations. + * + * Parameters: + * im - The image. + * c - The color. + * dont_blend - Whether to blend. + */ +BGD_DECLARE(void) gdImageSetAntiAliasedDontBlend (gdImagePtr im, int c, int dont_blend) +{ + im->AA = 1; + im->AA_color = c; + im->AA_dont_blend = dont_blend; +} + +/** + * Function: gdImageInterlace + * + * Sets whether an image is interlaced + * + * This is relevant only when saving the image in a format that supports + * interlacing. + * + * Parameters: + * im - The image. + * interlaceArg - Whether the image is interlaced. + * + * See also: + * - <gdImageGetInterlaced> +*/ +BGD_DECLARE(void) gdImageInterlace (gdImagePtr im, int interlaceArg) +{ + im->interlace = interlaceArg; +} + +/** + * Function: gdImageCompare + * + * Compare two images + * + * Parameters: + * im1 - An image. + * im2 - Another image. + * + * Returns: + * A bitmask of <Image Comparison> flags where each set flag signals + * which attributes of the images are different. + */ +BGD_DECLARE(int) gdImageCompare (gdImagePtr im1, gdImagePtr im2) +{ + int x, y; + int p1, p2; + int cmpStatus = 0; + int sx, sy; + + if (im1->interlace != im2->interlace) { + cmpStatus |= GD_CMP_INTERLACE; + } + + if (im1->transparent != im2->transparent) { + cmpStatus |= GD_CMP_TRANSPARENT; + } + + if (im1->trueColor != im2->trueColor) { + cmpStatus |= GD_CMP_TRUECOLOR; + } + + sx = im1->sx; + if (im1->sx != im2->sx) { + cmpStatus |= GD_CMP_SIZE_X + GD_CMP_IMAGE; + if (im2->sx < im1->sx) { + sx = im2->sx; + } + } + + sy = im1->sy; + if (im1->sy != im2->sy) { + cmpStatus |= GD_CMP_SIZE_Y + GD_CMP_IMAGE; + if (im2->sy < im1->sy) { + sy = im2->sy; + } + } + + if (im1->colorsTotal != im2->colorsTotal) { + cmpStatus |= GD_CMP_NUM_COLORS; + } + + for (y = 0; (y < sy); y++) { + for (x = 0; (x < sx); x++) { + p1 = + im1->trueColor ? gdImageTrueColorPixel (im1, x, + y) : + gdImagePalettePixel (im1, x, y); + p2 = + im2->trueColor ? gdImageTrueColorPixel (im2, x, + y) : + gdImagePalettePixel (im2, x, y); + if (gdImageRed (im1, p1) != gdImageRed (im2, p2)) { + cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE; + break; + } + if (gdImageGreen (im1, p1) != gdImageGreen (im2, p2)) { + cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE; + break; + } + if (gdImageBlue (im1, p1) != gdImageBlue (im2, p2)) { + cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE; + break; + } +#if 0 + /* Soon we'll add alpha channel to palettes */ + if (gdImageAlpha (im1, p1) != gdImageAlpha (im2, p2)) { + cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE; + break; + } +#endif + } + if (cmpStatus & GD_CMP_COLOR) { + break; + }; + } + + return cmpStatus; +} + + +/* Thanks to Frank Warmerdam for this superior implementation + of gdAlphaBlend(), which merges alpha in the + destination color much better. */ + +/** + * Function: gdAlphaBlend + * + * Blend two colors + * + * Parameters: + * dst - The color to blend onto. + * src - The color to blend. + * + * See also: + * - <gdImageAlphaBlending> + * - <gdLayerOverlay> + * - <gdLayerMultiply> + */ +BGD_DECLARE(int) gdAlphaBlend (int dst, int src) +{ + int src_alpha = gdTrueColorGetAlpha(src); + int dst_alpha, alpha, red, green, blue; + int src_weight, dst_weight, tot_weight; + + /* -------------------------------------------------------------------- */ + /* Simple cases we want to handle fast. */ + /* -------------------------------------------------------------------- */ + if( src_alpha == gdAlphaOpaque ) + return src; + + dst_alpha = gdTrueColorGetAlpha(dst); + if( src_alpha == gdAlphaTransparent ) + return dst; + if( dst_alpha == gdAlphaTransparent ) + return src; + + /* -------------------------------------------------------------------- */ + /* What will the source and destination alphas be? Note that */ + /* the destination weighting is substantially reduced as the */ + /* overlay becomes quite opaque. */ + /* -------------------------------------------------------------------- */ + src_weight = gdAlphaTransparent - src_alpha; + dst_weight = (gdAlphaTransparent - dst_alpha) * src_alpha / gdAlphaMax; + tot_weight = src_weight + dst_weight; + + /* -------------------------------------------------------------------- */ + /* What red, green and blue result values will we use? */ + /* -------------------------------------------------------------------- */ + alpha = src_alpha * dst_alpha / gdAlphaMax; + + red = (gdTrueColorGetRed(src) * src_weight + + gdTrueColorGetRed(dst) * dst_weight) / tot_weight; + green = (gdTrueColorGetGreen(src) * src_weight + + gdTrueColorGetGreen(dst) * dst_weight) / tot_weight; + blue = (gdTrueColorGetBlue(src) * src_weight + + gdTrueColorGetBlue(dst) * dst_weight) / tot_weight; + + /* -------------------------------------------------------------------- */ + /* Return merged result. */ + /* -------------------------------------------------------------------- */ + return ((alpha << 24) + (red << 16) + (green << 8) + blue); +} + +static int gdAlphaOverlayColor (int src, int dst, int max ); + +/** + * Function: gdLayerOverlay + * + * Overlay two colors + * + * Parameters: + * dst - The color to overlay onto. + * src - The color to overlay. + * + * See also: + * - <gdImageAlphaBlending> + * - <gdAlphaBlend> + * - <gdLayerMultiply> + */ +BGD_DECLARE(int) gdLayerOverlay (int dst, int src) +{ + int a1, a2; + a1 = gdAlphaMax - gdTrueColorGetAlpha(dst); + a2 = gdAlphaMax - gdTrueColorGetAlpha(src); + return ( ((gdAlphaMax - a1*a2/gdAlphaMax) << 24) + + (gdAlphaOverlayColor( gdTrueColorGetRed(src), gdTrueColorGetRed(dst), gdRedMax ) << 16) + + (gdAlphaOverlayColor( gdTrueColorGetGreen(src), gdTrueColorGetGreen(dst), gdGreenMax ) << 8) + + (gdAlphaOverlayColor( gdTrueColorGetBlue(src), gdTrueColorGetBlue(dst), gdBlueMax )) + ); +} + +/* Apply 'overlay' effect - background pixels are colourised by the foreground colour */ +static int gdAlphaOverlayColor (int src, int dst, int max ) +{ + dst = dst << 1; + if( dst > max ) { + /* in the "light" zone */ + return dst + (src << 1) - (dst * src / max) - max; + } else { + /* in the "dark" zone */ + return dst * src / max; + } +} + +/** + * Function: gdLayerMultiply + * + * Overlay two colors with multiply effect + * + * Parameters: + * dst - The color to overlay onto. + * src - The color to overlay. + * + * See also: + * - <gdImageAlphaBlending> + * - <gdAlphaBlend> + * - <gdLayerOverlay> + */ +BGD_DECLARE(int) gdLayerMultiply (int dst, int src) +{ + int a1, a2, r1, r2, g1, g2, b1, b2; + a1 = gdAlphaMax - gdTrueColorGetAlpha(src); + a2 = gdAlphaMax - gdTrueColorGetAlpha(dst); + + r1 = gdRedMax - (a1 * (gdRedMax - gdTrueColorGetRed(src))) / gdAlphaMax; + r2 = gdRedMax - (a2 * (gdRedMax - gdTrueColorGetRed(dst))) / gdAlphaMax; + g1 = gdGreenMax - (a1 * (gdGreenMax - gdTrueColorGetGreen(src))) / gdAlphaMax; + g2 = gdGreenMax - (a2 * (gdGreenMax - gdTrueColorGetGreen(dst))) / gdAlphaMax; + b1 = gdBlueMax - (a1 * (gdBlueMax - gdTrueColorGetBlue(src))) / gdAlphaMax; + b2 = gdBlueMax - (a2 * (gdBlueMax - gdTrueColorGetBlue(dst))) / gdAlphaMax ; + + a1 = gdAlphaMax - a1; + a2 = gdAlphaMax - a2; + return ( ((a1*a2/gdAlphaMax) << 24) + + ((r1*r2/gdRedMax) << 16) + + ((g1*g2/gdGreenMax) << 8) + + ((b1*b2/gdBlueMax)) + ); +} + +/** + * Function: gdImageAlphaBlending + * + * Set the effect for subsequent drawing operations + * + * Note that the effect is used for truecolor images only. + * + * Parameters: + * im - The image. + * alphaBlendingArg - The effect. + * + * See also: + * - <Effects> + */ +BGD_DECLARE(void) gdImageAlphaBlending (gdImagePtr im, int alphaBlendingArg) +{ + im->alphaBlendingFlag = alphaBlendingArg; +} + +/** + * Function: gdImageSaveAlpha + * + * Sets the save alpha flag + * + * The save alpha flag specifies whether the alpha channel of the pixels should + * be saved. This is supported only for image formats that support full alpha + * transparency, e.g. PNG. + */ +BGD_DECLARE(void) gdImageSaveAlpha (gdImagePtr im, int saveAlphaArg) +{ + im->saveAlphaFlag = saveAlphaArg; +} + +/** + * Function: gdImageSetClip + * + * Sets the clipping rectangle + * + * The clipping rectangle restricts the drawing area for following drawing + * operations. + * + * Parameters: + * im - The image. + * x1 - The x-coordinate of the upper left corner. + * y1 - The y-coordinate of the upper left corner. + * x2 - The x-coordinate of the lower right corner. + * y2 - The y-coordinate of the lower right corner. + * + * See also: + * - <gdImageGetClip> + */ +BGD_DECLARE(void) gdImageSetClip (gdImagePtr im, int x1, int y1, int x2, int y2) +{ + if (x1 < 0) { + x1 = 0; + } + if (x1 >= im->sx) { + x1 = im->sx - 1; + } + if (x2 < 0) { + x2 = 0; + } + if (x2 >= im->sx) { + x2 = im->sx - 1; + } + if (y1 < 0) { + y1 = 0; + } + if (y1 >= im->sy) { + y1 = im->sy - 1; + } + if (y2 < 0) { + y2 = 0; + } + if (y2 >= im->sy) { + y2 = im->sy - 1; + } + im->cx1 = x1; + im->cy1 = y1; + im->cx2 = x2; + im->cy2 = y2; +} + +/** + * Function: gdImageGetClip + * + * Gets the current clipping rectangle + * + * Parameters: + * im - The image. + * x1P - (out) The x-coordinate of the upper left corner. + * y1P - (out) The y-coordinate of the upper left corner. + * x2P - (out) The x-coordinate of the lower right corner. + * y2P - (out) The y-coordinate of the lower right corner. + * + * See also: + * - <gdImageSetClip> + */ +BGD_DECLARE(void) gdImageGetClip (gdImagePtr im, int *x1P, int *y1P, int *x2P, int *y2P) +{ + *x1P = im->cx1; + *y1P = im->cy1; + *x2P = im->cx2; + *y2P = im->cy2; +} + +/** + * Function: gdImageSetResolution + * + * Sets the resolution of an image. + * + * Parameters: + * im - The image. + * res_x - The horizontal resolution in DPI. + * res_y - The vertical resolution in DPI. + * + * See also: + * - <gdImageResolutionX> + * - <gdImageResolutionY> + */ +BGD_DECLARE(void) gdImageSetResolution(gdImagePtr im, const unsigned int res_x, const unsigned int res_y) +{ + if (res_x > 0) im->res_x = res_x; + if (res_y > 0) im->res_y = res_y; +} + +/* + * Added on 2003/12 by Pierre-Alain Joye (pajoye@pearfr.org) + * */ +#define BLEND_COLOR(a, nc, c, cc) \ +nc = (cc) + (((((c) - (cc)) * (a)) + ((((c) - (cc)) * (a)) >> 8) + 0x80) >> 8); + +static void gdImageSetAAPixelColor(gdImagePtr im, int x, int y, int color, int t) +{ + int dr,dg,db,p,r,g,b; + + /* 2.0.34: watch out for out of range calls */ + if (!gdImageBoundsSafeMacro(im, x, y)) { + return; + } + p = gdImageGetPixel(im,x,y); + /* TBB: we have to implement the dont_blend stuff to provide + the full feature set of the old implementation */ + if ((p == color) + || ((p == im->AA_dont_blend) + && (t != 0x00))) { + return; + } + dr = gdTrueColorGetRed(color); + dg = gdTrueColorGetGreen(color); + db = gdTrueColorGetBlue(color); + + r = gdTrueColorGetRed(p); + g = gdTrueColorGetGreen(p); + b = gdTrueColorGetBlue(p); + + BLEND_COLOR(t, dr, r, dr); + BLEND_COLOR(t, dg, g, dg); + BLEND_COLOR(t, db, b, db); + im->tpixels[y][x] = gdTrueColorAlpha(dr, dg, db, gdAlphaOpaque); +} + +static void gdImageAALine (gdImagePtr im, int x1, int y1, int x2, int y2, int col) +{ + /* keep them as 32bits */ + long x, y, inc, frac; + long dx, dy,tmp; + int w, wid, wstart; + int thick = im->thick; + + if (!im->trueColor) { + /* TBB: don't crash when the image is of the wrong type */ + gdImageLine(im, x1, y1, x2, y2, col); + return; + } + + /* TBB: use the clipping rectangle */ + if (clip_1d (&x1, &y1, &x2, &y2, im->cx1, im->cx2) == 0) + return; + if (clip_1d (&y1, &x1, &y2, &x2, im->cy1, im->cy2) == 0) + return; + + dx = x2 - x1; + dy = y2 - y1; + + if (dx == 0 && dy == 0) { + /* TBB: allow setting points */ + gdImageSetAAPixelColor(im, x1, y1, col, 0xFF); + return; + } else { + double ag; + /* Cast the long to an int to avoid compiler warnings about truncation. + * This isn't a problem as computed dy/dx values came from ints above. */ + ag = fabs(abs((int)dy) < abs((int)dx) ? cos(atan2(dy, dx)) : sin(atan2(dy, dx))); + if (ag != 0) { + wid = thick / ag; + } else { + wid = 1; + } + if (wid == 0) { + wid = 1; + } + } + + /* Axis aligned lines */ + if (dx == 0) { + gdImageVLine(im, x1, y1, y2, col); + return; + } else if (dy == 0) { + gdImageHLine(im, y1, x1, x2, col); + return; + } + + if (abs((int)dx) > abs((int)dy)) { + if (dx < 0) { + tmp = x1; + x1 = x2; + x2 = tmp; + tmp = y1; + y1 = y2; + y2 = tmp; + dx = x2 - x1; + dy = y2 - y1; + } + y = y1; + inc = (dy * 65536) / dx; + frac = 0; + /* TBB: set the last pixel for consistency (<=) */ + for (x = x1 ; x <= x2 ; x++) { + wstart = y - wid / 2; + for (w = wstart; w < wstart + wid; w++) { + gdImageSetAAPixelColor(im, x , w , col , (frac >> 8) & 0xFF); + gdImageSetAAPixelColor(im, x , w + 1 , col, (~frac >> 8) & 0xFF); + } + frac += inc; + if (frac >= 65536) { + frac -= 65536; + y++; + } else if (frac < 0) { + frac += 65536; + y--; + } + } + } else { + if (dy < 0) { + tmp = x1; + x1 = x2; + x2 = tmp; + tmp = y1; + y1 = y2; + y2 = tmp; + dx = x2 - x1; + dy = y2 - y1; + } + x = x1; + inc = (dx * 65536) / dy; + frac = 0; + /* TBB: set the last pixel for consistency (<=) */ + for (y = y1 ; y <= y2 ; y++) { + wstart = x - wid / 2; + for (w = wstart; w < wstart + wid; w++) { + gdImageSetAAPixelColor(im, w , y , col, (frac >> 8) & 0xFF); + gdImageSetAAPixelColor(im, w + 1, y, col, (~frac >> 8) & 0xFF); + } + frac += inc; + if (frac >= 65536) { + frac -= 65536; + x++; + } else if (frac < 0) { + frac += 65536; + x--; + } + } + } +} + + +/** + * Function: gdImagePaletteToTrueColor + * + * Convert a palette image to true color + * + * Parameters: + * src - The image. + * + * Returns: + * Non-zero if the conversion succeeded, zero otherwise. + * + * See also: + * - <gdImageTrueColorToPalette> + */ +BGD_DECLARE(int) gdImagePaletteToTrueColor(gdImagePtr src) +{ + unsigned int y; + unsigned int yy; + + if (src == NULL) { + return 0; + } + + if (src->trueColor == 1) { + return 1; + } else { + unsigned int x; + const unsigned int sy = gdImageSY(src); + const unsigned int sx = gdImageSX(src); + + src->tpixels = (int **) gdMalloc(sizeof(int *) * sy); + if (src->tpixels == NULL) { + return 0; + } + + for (y = 0; y < sy; y++) { + const unsigned char *src_row = src->pixels[y]; + int * dst_row; + + /* no need to calloc it, we overwrite all pxl anyway */ + src->tpixels[y] = (int *) gdMalloc(sx * sizeof(int)); + if (src->tpixels[y] == NULL) { + goto clean_on_error; + } + + dst_row = src->tpixels[y]; + for (x = 0; x < sx; x++) { + const unsigned char c = *(src_row + x); + if (c == src->transparent) { + *(dst_row + x) = gdTrueColorAlpha(0, 0, 0, 127); + } else { + *(dst_row + x) = gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]); + } + } + } + } + + /* free old palette buffer (y is sy) */ + for (yy = 0; yy < y; yy++) { + gdFree(src->pixels[yy]); + } + gdFree(src->pixels); + src->trueColor = 1; + src->pixels = NULL; + src->alphaBlendingFlag = 0; + src->saveAlphaFlag = 1; + + if (src->transparent >= 0) { + const unsigned char c = src->transparent; + src->transparent = gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]); + } + + return 1; + +clean_on_error: + /* free new true color buffer (y is not allocated, have failed) */ + for (yy = 0; yy < y; yy++) { + gdFree(src->tpixels[yy]); + } + gdFree(src->tpixels); + return 0; +} diff --git a/libmscgen/gd.h b/libmscgen/gd.h new file mode 100644 index 0000000..f768fb5 --- /dev/null +++ b/libmscgen/gd.h @@ -0,0 +1,1649 @@ +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdlib.h> + +#ifndef GD_H +#define GD_H 1 + +/* Version information. This gets parsed by build scripts as well as + * gcc so each #define line in this group must also be splittable on + * whitespace, take the form GD_*_VERSION and contain the magical + * trailing comment. */ +#define GD_MAJOR_VERSION 2 /*version605b5d1778*/ +#define GD_MINOR_VERSION 2 /*version605b5d1778*/ +#define GD_RELEASE_VERSION 4 /*version605b5d1778*/ +#define GD_EXTRA_VERSION "" /*version605b5d1778*/ +/* End parsable section. */ + +/* The version string. This is constructed from the version number + * parts above via macro abuse^Wtrickery. */ +#define GDXXX_VERSION_STR(mjr, mnr, rev, ext) mjr "." mnr "." rev ext +#define GDXXX_STR(s) GDXXX_SSTR(s) /* Two levels needed to expand args. */ +#define GDXXX_SSTR(s) #s + +#define GD_VERSION_STRING \ + GDXXX_VERSION_STR(GDXXX_STR(GD_MAJOR_VERSION), \ + GDXXX_STR(GD_MINOR_VERSION), \ + GDXXX_STR(GD_RELEASE_VERSION), \ + GD_EXTRA_VERSION) + + +/* Do the DLL dance: dllexport when building the DLL, + dllimport when importing from it, nothing when + not on Silly Silly Windows (tm Aardman Productions). */ + +/* 2.0.20: for headers */ + +/* 2.0.24: __stdcall also needed for Visual BASIC + and other languages. This breaks ABI compatibility + with previous DLL revs, but it's necessary. */ + +/* 2.0.29: WIN32 programmers can declare the NONDLL macro if they + wish to build gd as a static library or by directly including + the gd sources in a project. */ + +/* http://gcc.gnu.org/wiki/Visibility */ +#if defined(_WIN32) || defined(CYGWIN) || defined(_WIN32_WCE) +# ifdef BGDWIN32 +# ifdef NONDLL +# define BGD_EXPORT_DATA_PROT +# else +# ifdef __GNUC__ +# define BGD_EXPORT_DATA_PROT __attribute__ ((dllexport)) +# else +# define BGD_EXPORT_DATA_PROT __declspec(dllexport) +# endif +# endif +# else +# ifdef __GNUC__ +# define BGD_EXPORT_DATA_PROT __attribute__ ((dllimport)) +# else +# define BGD_EXPORT_DATA_PROT __declspec(dllimport) +# endif +# endif +# define BGD_STDCALL __stdcall +# define BGD_EXPORT_DATA_IMPL +#else +# if defined(__GNUC__) || defined(__clang__) +# define BGD_EXPORT_DATA_PROT __attribute__ ((visibility ("default"))) +# define BGD_EXPORT_DATA_IMPL __attribute__ ((visibility ("hidden"))) +# else +# define BGD_EXPORT_DATA_PROT +# define BGD_EXPORT_DATA_IMPL +# endif +# define BGD_STDCALL +#endif + +#define BGD_DECLARE(rt) BGD_EXPORT_DATA_PROT rt BGD_STDCALL + +/* VS2012+ disable keyword macroizing unless _ALLOW_KEYWORD_MACROS is set + We define inline, snprintf, and strcasecmp if they're missing +*/ +#ifdef _MSC_VER +# define _ALLOW_KEYWORD_MACROS +# ifndef inline +# define inline __inline +# endif +# ifndef strcasecmp +# define strcasecmp _stricmp +# endif +#if _MSC_VER < 1900 + extern int snprintf(char*, size_t, const char*, ...); +#endif +#endif + +#ifdef __cplusplus + extern "C" + { +#endif + +/* gd.h: declarations file for the graphic-draw module. + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. This software is provided "AS IS." Thomas Boutell and + * Boutell.Com, Inc. disclaim all warranties, either express or implied, + * including but not limited to implied warranties of merchantability and + * fitness for a particular purpose, with respect to this code and accompanying + * documentation. */ + +/* stdio is needed for file I/O. */ +#include <stdio.h> +#include <stdarg.h> +//#include "gd_io.h" + +/* The maximum number of palette entries in palette-based images. + In the wonderful new world of gd 2.0, you can of course have + many more colors when using truecolor mode. */ + +#define gdMaxColors 256 + +/* Image type. See functions below; you will not need to change + the elements directly. Use the provided macros to + access sx, sy, the color table, and colorsTotal for + read-only purposes. */ + +/* If 'truecolor' is set true, the image is truecolor; + pixels are represented by integers, which + must be 32 bits wide or more. + + True colors are repsented as follows: + + ARGB + + Where 'A' (alpha channel) occupies only the + LOWER 7 BITS of the MSB. This very small + loss of alpha channel resolution allows gd 2.x + to keep backwards compatibility by allowing + signed integers to be used to represent colors, + and negative numbers to represent special cases, + just as in gd 1.x. */ + +#define gdAlphaMax 127 +#define gdAlphaOpaque 0 +#define gdAlphaTransparent 127 +#define gdRedMax 255 +#define gdGreenMax 255 +#define gdBlueMax 255 + +/** + * Group: Color Decomposition + */ + +/** + * Macro: gdTrueColorGetAlpha + * + * Gets the alpha channel value + * + * Parameters: + * c - The color + * + * See also: + * - <gdTrueColorAlpha> + */ +#define gdTrueColorGetAlpha(c) (((c) & 0x7F000000) >> 24) + +/** + * Macro: gdTrueColorGetRed + * + * Gets the red channel value + * + * Parameters: + * c - The color + * + * See also: + * - <gdTrueColorAlpha> + */ +#define gdTrueColorGetRed(c) (((c) & 0xFF0000) >> 16) + +/** + * Macro: gdTrueColorGetGreen + * + * Gets the green channel value + * + * Parameters: + * c - The color + * + * See also: + * - <gdTrueColorAlpha> + */ +#define gdTrueColorGetGreen(c) (((c) & 0x00FF00) >> 8) + +/** + * Macro: gdTrueColorGetBlue + * + * Gets the blue channel value + * + * Parameters: + * c - The color + * + * See also: + * - <gdTrueColorAlpha> + */ +#define gdTrueColorGetBlue(c) ((c) & 0x0000FF) + +/** + * Group: Effects + * + * The layering effect + * + * When pixels are drawn the new colors are "mixed" with the background + * depending on the effect. + * + * Note that the effect does not apply to palette images, where pixels + * are always replaced. + * + * Modes: + * gdEffectReplace - replace pixels + * gdEffectAlphaBlend - blend pixels, see <gdAlphaBlend> + * gdEffectNormal - default mode; same as gdEffectAlphaBlend + * gdEffectOverlay - overlay pixels, see <gdLayerOverlay> + * gdEffectMultiply - overlay pixels with multiply effect, see + * <gdLayerMultiply> + * + * See also: + * - <gdImageAlphaBlending> + */ +#define gdEffectReplace 0 +#define gdEffectAlphaBlend 1 +#define gdEffectNormal 2 +#define gdEffectOverlay 3 +#define gdEffectMultiply 4 + +#define GD_TRUE 1 +#define GD_FALSE 0 + +#define GD_EPSILON 1e-6 +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif + +/* This function accepts truecolor pixel values only. The + source color is composited with the destination color + based on the alpha channel value of the source color. + The resulting color is opaque. */ + +BGD_DECLARE(int) gdAlphaBlend (int dest, int src); +BGD_DECLARE(int) gdLayerOverlay (int dest, int src); +BGD_DECLARE(int) gdLayerMultiply (int dest, int src); + + +/** + * Group: Color Quantization + * + * Enum: gdPaletteQuantizationMethod + * + * Constants: + * GD_QUANT_DEFAULT - GD_QUANT_LIQ if libimagequant is available, + * GD_QUANT_JQUANT otherwise. + * GD_QUANT_JQUANT - libjpeg's old median cut. Fast, but only uses 16-bit + * color. + * GD_QUANT_NEUQUANT - NeuQuant - approximation using Kohonen neural network. + * GD_QUANT_LIQ - A combination of algorithms used in libimagequant + * aiming for the highest quality at cost of speed. + * + * Note that GD_QUANT_JQUANT does not retain the alpha channel, and + * GD_QUANT_NEUQUANT does not support dithering. + * + * See also: + * - <gdImageTrueColorToPaletteSetMethod> + */ +enum gdPaletteQuantizationMethod { + GD_QUANT_DEFAULT = 0, + GD_QUANT_JQUANT = 1, + GD_QUANT_NEUQUANT = 2, + GD_QUANT_LIQ = 3 +}; + + +/** + * Group: Transform + * + * Constants: gdInterpolationMethod + * + * GD_BELL - Bell + * GD_BESSEL - Bessel + * GD_BILINEAR_FIXED - fixed point bilinear + * GD_BICUBIC - Bicubic + * GD_BICUBIC_FIXED - fixed point bicubic integer + * GD_BLACKMAN - Blackman + * GD_BOX - Box + * GD_BSPLINE - BSpline + * GD_CATMULLROM - Catmullrom + * GD_GAUSSIAN - Gaussian + * GD_GENERALIZED_CUBIC - Generalized cubic + * GD_HERMITE - Hermite + * GD_HAMMING - Hamming + * GD_HANNING - Hannig + * GD_MITCHELL - Mitchell + * GD_NEAREST_NEIGHBOUR - Nearest neighbour interpolation + * GD_POWER - Power + * GD_QUADRATIC - Quadratic + * GD_SINC - Sinc + * GD_TRIANGLE - Triangle + * GD_WEIGHTED4 - 4 pixels weighted bilinear interpolation + * GD_LINEAR - bilinear interpolation + * + * See also: + * - <gdImageSetInterpolationMethod> + * - <gdImageGetInterpolationMethod> + */ +typedef enum { + GD_DEFAULT = 0, + GD_BELL, + GD_BESSEL, + GD_BILINEAR_FIXED, + GD_BICUBIC, + GD_BICUBIC_FIXED, + GD_BLACKMAN, + GD_BOX, + GD_BSPLINE, + GD_CATMULLROM, + GD_GAUSSIAN, + GD_GENERALIZED_CUBIC, + GD_HERMITE, + GD_HAMMING, + GD_HANNING, + GD_MITCHELL, + GD_NEAREST_NEIGHBOUR, + GD_POWER, + GD_QUADRATIC, + GD_SINC, + GD_TRIANGLE, + GD_WEIGHTED4, + GD_LINEAR, + GD_METHOD_COUNT = 23 +} gdInterpolationMethod; + +/* define struct with name and func ptr and add it to gdImageStruct gdInterpolationMethod interpolation; */ + +/* Interpolation function ptr */ +typedef double (* interpolation_method )(double); + + +/* + Group: Types + + typedef: gdImage + + typedef: gdImagePtr + + The data structure in which gd stores images. <gdImageCreate>, + <gdImageCreateTrueColor> and the various image file-loading functions + return a pointer to this type, and the other functions expect to + receive a pointer to this type as their first argument. + + *gdImagePtr* is a pointer to *gdImage*. + + See also: + <Accessor Macros> + + (Previous versions of this library encouraged directly manipulating + the contents ofthe struct but we are attempting to move away from + this practice so the fields are no longer documented here. If you + need to poke at the internals of this struct, feel free to look at + *gd.h*.) +*/ +typedef struct gdImageStruct { + /* Palette-based image pixels */ + unsigned char **pixels; + int sx; + int sy; + /* These are valid in palette images only. See also + 'alpha', which appears later in the structure to + preserve binary backwards compatibility */ + int colorsTotal; + int red[gdMaxColors]; + int green[gdMaxColors]; + int blue[gdMaxColors]; + int open[gdMaxColors]; + /* For backwards compatibility, this is set to the + first palette entry with 100% transparency, + and is also set and reset by the + gdImageColorTransparent function. Newer + applications can allocate palette entries + with any desired level of transparency; however, + bear in mind that many viewers, notably + many web browsers, fail to implement + full alpha channel for PNG and provide + support for full opacity or transparency only. */ + int transparent; + int *polyInts; + int polyAllocated; + struct gdImageStruct *brush; + struct gdImageStruct *tile; + int brushColorMap[gdMaxColors]; + int tileColorMap[gdMaxColors]; + int styleLength; + int stylePos; + int *style; + int interlace; + /* New in 2.0: thickness of line. Initialized to 1. */ + int thick; + /* New in 2.0: alpha channel for palettes. Note that only + Macintosh Internet Explorer and (possibly) Netscape 6 + really support multiple levels of transparency in + palettes, to my knowledge, as of 2/15/01. Most + common browsers will display 100% opaque and + 100% transparent correctly, and do something + unpredictable and/or undesirable for levels + in between. TBB */ + int alpha[gdMaxColors]; + /* Truecolor flag and pixels. New 2.0 fields appear here at the + end to minimize breakage of existing object code. */ + int trueColor; + int **tpixels; + /* Should alpha channel be copied, or applied, each time a + pixel is drawn? This applies to truecolor images only. + No attempt is made to alpha-blend in palette images, + even if semitransparent palette entries exist. + To do that, build your image as a truecolor image, + then quantize down to 8 bits. */ + int alphaBlendingFlag; + /* Should the alpha channel of the image be saved? This affects + PNG at the moment; other future formats may also + have that capability. JPEG doesn't. */ + int saveAlphaFlag; + + /* There should NEVER BE ACCESSOR MACROS FOR ITEMS BELOW HERE, so this + part of the structure can be safely changed in new releases. */ + + /* 2.0.12: anti-aliased globals. 2.0.26: just a few vestiges after + switching to the fast, memory-cheap implementation from PHP-gd. */ + int AA; + int AA_color; + int AA_dont_blend; + + /* 2.0.12: simple clipping rectangle. These values + must be checked for safety when set; please use + gdImageSetClip */ + int cx1; + int cy1; + int cx2; + int cy2; + + /* 2.1.0: allows to specify resolution in dpi */ + unsigned int res_x; + unsigned int res_y; + + /* Selects quantization method, see gdImageTrueColorToPaletteSetMethod() and gdPaletteQuantizationMethod enum. */ + int paletteQuantizationMethod; + /* speed/quality trade-off. 1 = best quality, 10 = best speed. 0 = method-specific default. + Applicable to GD_QUANT_LIQ and GD_QUANT_NEUQUANT. */ + int paletteQuantizationSpeed; + /* Image will remain true-color if conversion to palette cannot achieve given quality. + Value from 1 to 100, 1 = ugly, 100 = perfect. Applicable to GD_QUANT_LIQ.*/ + int paletteQuantizationMinQuality; + /* Image will use minimum number of palette colors needed to achieve given quality. Must be higher than paletteQuantizationMinQuality + Value from 1 to 100, 1 = ugly, 100 = perfect. Applicable to GD_QUANT_LIQ.*/ + int paletteQuantizationMaxQuality; + gdInterpolationMethod interpolation_id; + interpolation_method interpolation; +} +gdImage; + +typedef gdImage *gdImagePtr; + + +/* Point type for use in polygon drawing. */ + +/** + * Group: Types + * + * typedef: gdPointF + * Defines a point in a 2D coordinate system using floating point + * values. + * x - Floating point position (increase from left to right) + * y - Floating point Row position (increase from top to bottom) + * + * typedef: gdPointFPtr + * Pointer to a <gdPointF> + * + * See also: + * <gdImageCreate>, <gdImageCreateTrueColor>, + **/ +typedef struct +{ + double x, y; +} +gdPointF, *gdPointFPtr; + + +/* + Group: Types + + typedef: gdFont + + typedef: gdFontPtr + + A font structure, containing the bitmaps of all characters in a + font. Used to declare the characteristics of a font. Text-output + functions expect these as their second argument, following the + <gdImagePtr> argument. <gdFontGetSmall> and <gdFontGetLarge> both + return one. + + You can provide your own font data by providing such a structure and + the associated pixel array. You can determine the width and height + of a single character in a font by examining the w and h members of + the structure. If you will not be creating your own fonts, you will + not need to concern yourself with the rest of the components of this + structure. + + Please see the files gdfontl.c and gdfontl.h for an example of + the proper declaration of this structure. + + > typedef struct { + > // # of characters in font + > int nchars; + > // First character is numbered... (usually 32 = space) + > int offset; + > // Character width and height + > int w; + > int h; + > // Font data; array of characters, one row after another. + > // Easily included in code, also easily loaded from + > // data files. + > char *data; + > } gdFont; + + gdFontPtr is a pointer to gdFont. + +*/ +typedef struct { + /* # of characters in font */ + int nchars; + /* First character is numbered... (usually 32 = space) */ + int offset; + /* Character width and height */ + int w; + int h; + /* Font data; array of characters, one row after another. + Easily included in code, also easily loaded from + data files. */ + char *data; +} +gdFont; + +/* Text functions take these. */ +typedef gdFont *gdFontPtr; + +typedef void(*gdErrorMethod)(int, const char *, va_list); + +BGD_DECLARE(void) gdSetErrorMethod(gdErrorMethod); +BGD_DECLARE(void) gdClearErrorMethod(void); + +/* For backwards compatibility only. Use gdImageSetStyle() + for MUCH more flexible line drawing. Also see + gdImageSetBrush(). */ +#define gdDashSize 4 + +/** + * Group: Colors + * + * Colors are always of type int which is supposed to be at least 32 bit large. + * + * Kinds of colors: + * true colors - ARGB values where the alpha channel is stored as most + * significant, and the blue channel as least significant + * byte. Note that the alpha channel only uses the 7 least + * significant bits. + * Don't rely on the internal representation, though, and + * use <gdTrueColorAlpha> to compose a truecolor value, and + * <gdTrueColorGetAlpha>, <gdTrueColorGetRed>, + * <gdTrueColorGetGreen> and <gdTrueColorGetBlue> to access + * the respective channels. + * palette indexes - The index of a color palette entry (0-255). + * special colors - As listed in the following section. + * + * Constants: Special Colors + * gdStyled - use the current style, see <gdImageSetStyle> + * gdBrushed - use the current brush, see <gdImageSetBrush> + * gdStyledBrushed - use the current style and brush + * gdTiled - use the current tile, see <gdImageSetTile> + * gdTransparent - indicate transparency, what is not the same as the + * transparent color index; used for lines only + * gdAntiAliased - draw anti aliased + */ + +#define gdStyled (-2) +#define gdBrushed (-3) +#define gdStyledBrushed (-4) +#define gdTiled (-5) +#define gdTransparent (-6) +#define gdAntiAliased (-7) + +/* Functions to manipulate images. */ + +/* Creates a palette-based image (up to 256 colors). */ +BGD_DECLARE(gdImagePtr) gdImageCreate (int sx, int sy); + +/* An alternate name for the above (2.0). */ +#define gdImageCreatePalette gdImageCreate + +/* Creates a truecolor image (millions of colors). */ +BGD_DECLARE(gdImagePtr) gdImageCreateTrueColor (int sx, int sy); + +/* Creates an image from various file types. These functions + return a palette or truecolor image based on the + nature of the file being loaded. Truecolor PNG + stays truecolor; palette PNG stays palette-based; + JPEG is always truecolor. */ +BGD_DECLARE(gdImagePtr) gdImageCreateFromPng (FILE * fd); +//BGD_DECLARE(gdImagePtr) gdImageCreateFromPngCtx (gdIOCtxPtr in); +BGD_DECLARE(gdImagePtr) gdImageCreateFromPngPtr (int size, void *data); + +/* These read the first frame only */ +BGD_DECLARE(gdImagePtr) gdImageCreateFromGif (FILE * fd); +//BGD_DECLARE(gdImagePtr) gdImageCreateFromGifCtx (gdIOCtxPtr in); +BGD_DECLARE(gdImagePtr) gdImageCreateFromGifPtr (int size, void *data); +BGD_DECLARE(gdImagePtr) gdImageCreateFromWBMP (FILE * inFile); +//BGD_DECLARE(gdImagePtr) gdImageCreateFromWBMPCtx (gdIOCtx * infile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromWBMPPtr (int size, void *data); +BGD_DECLARE(gdImagePtr) gdImageCreateFromJpeg (FILE * infile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegEx (FILE * infile, int ignore_warning); +//BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegCtx (gdIOCtx * infile); +//BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegCtxEx (gdIOCtx * infile, int ignore_warning); +BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegPtr (int size, void *data); +BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegPtrEx (int size, void *data, int ignore_warning); +BGD_DECLARE(gdImagePtr) gdImageCreateFromWebp (FILE * inFile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromWebpPtr (int size, void *data); +//BGD_DECLARE(gdImagePtr) gdImageCreateFromWebpCtx (gdIOCtx * infile); + +BGD_DECLARE(gdImagePtr) gdImageCreateFromTiff(FILE *inFile); +//BGD_DECLARE(gdImagePtr) gdImageCreateFromTiffCtx(gdIOCtx *infile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromTiffPtr(int size, void *data); + +BGD_DECLARE(gdImagePtr) gdImageCreateFromTga( FILE * fp ); +//BGD_DECLARE(gdImagePtr) gdImageCreateFromTgaCtx(gdIOCtx* ctx); +BGD_DECLARE(gdImagePtr) gdImageCreateFromTgaPtr(int size, void *data); + +BGD_DECLARE(gdImagePtr) gdImageCreateFromBmp (FILE * inFile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromBmpPtr (int size, void *data); +//BGD_DECLARE(gdImagePtr) gdImageCreateFromBmpCtx (gdIOCtxPtr infile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromFile(const char *filename); + + +/* + Group: Types + + typedef: gdSource + + typedef: gdSourcePtr + + *Note:* This interface is *obsolete* and kept only for + *compatibility. Use <gdIOCtx> instead. + + Represents a source from which a PNG can be read. Programmers who + do not wish to read PNGs from a file can provide their own + alternate input mechanism, using the <gdImageCreateFromPngSource> + function. See the documentation of that function for an example of + the proper use of this type. + + > typedef struct { + > int (*source) (void *context, char *buffer, int len); + > void *context; + > } gdSource, *gdSourcePtr; + + The source function must return -1 on error, otherwise the number + of bytes fetched. 0 is EOF, not an error! + + 'context' will be passed to your source function. + +*/ +typedef struct { + int (*source) (void *context, char *buffer, int len); + void *context; +} +gdSource, *gdSourcePtr; + +/* Deprecated in favor of gdImageCreateFromPngCtx */ +BGD_DECLARE(gdImagePtr) gdImageCreateFromPngSource (gdSourcePtr in); + +BGD_DECLARE(gdImagePtr) gdImageCreateFromGd (FILE * in); +//BGD_DECLARE(gdImagePtr) gdImageCreateFromGdCtx (gdIOCtxPtr in); +BGD_DECLARE(gdImagePtr) gdImageCreateFromGdPtr (int size, void *data); + +BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2 (FILE * in); +//BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2Ctx (gdIOCtxPtr in); +BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2Ptr (int size, void *data); + +BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2Part (FILE * in, int srcx, int srcy, int w, + int h); +//BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2PartCtx (gdIOCtxPtr in, int srcx, int srcy, +// int w, int h); +BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2PartPtr (int size, void *data, int srcx, int srcy, + int w, int h); +/* 2.0.10: prototype was missing */ +BGD_DECLARE(gdImagePtr) gdImageCreateFromXbm (FILE * in); +//BGD_DECLARE(void) gdImageXbmCtx(gdImagePtr image, char* file_name, int fg, gdIOCtx * out); + +/* NOTE: filename, not FILE */ +BGD_DECLARE(gdImagePtr) gdImageCreateFromXpm (char *filename); + +BGD_DECLARE(void) gdImageDestroy (gdImagePtr im); + +/* Replaces or blends with the background depending on the + most recent call to gdImageAlphaBlending and the + alpha channel value of 'color'; default is to overwrite. + Tiling and line styling are also implemented + here. All other gd drawing functions pass through this call, + allowing for many useful effects. + Overlay and multiply effects are used when gdImageAlphaBlending + is passed gdEffectOverlay and gdEffectMultiply */ + +BGD_DECLARE(void) gdImageSetPixel (gdImagePtr im, int x, int y, int color); +/* FreeType 2 text output with hook to extra flags */ + +BGD_DECLARE(int) gdImageGetPixel (gdImagePtr im, int x, int y); +BGD_DECLARE(int) gdImageGetTrueColorPixel (gdImagePtr im, int x, int y); + +BGD_DECLARE(void) gdImageAABlend (gdImagePtr im); + +BGD_DECLARE(void) gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color); + +/* For backwards compatibility only. Use gdImageSetStyle() + for much more flexible line drawing. */ +BGD_DECLARE(void) gdImageDashedLine (gdImagePtr im, int x1, int y1, int x2, int y2, + int color); +/* Corners specified (not width and height). Upper left first, lower right + second. */ +BGD_DECLARE(void) gdImageRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, + int color); +/* Solid bar. Upper left corner first, lower right corner second. */ +BGD_DECLARE(void) gdImageFilledRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, + int color); +BGD_DECLARE(void) gdImageSetClip(gdImagePtr im, int x1, int y1, int x2, int y2); +BGD_DECLARE(void) gdImageGetClip(gdImagePtr im, int *x1P, int *y1P, int *x2P, int *y2P); +BGD_DECLARE(void) gdImageSetResolution(gdImagePtr im, const unsigned int res_x, const unsigned int res_y); +BGD_DECLARE(int) gdImageBoundsSafe (gdImagePtr im, int x, int y); +BGD_DECLARE(void) gdImageChar (gdImagePtr im, gdFontPtr f, int x, int y, int c, + int color); +BGD_DECLARE(void) gdImageCharUp (gdImagePtr im, gdFontPtr f, int x, int y, int c, + int color); +BGD_DECLARE(void) gdImageString (gdImagePtr im, gdFontPtr f, int x, int y, + unsigned char *s, int color); +BGD_DECLARE(void) gdImageStringUp (gdImagePtr im, gdFontPtr f, int x, int y, + unsigned char *s, int color); +BGD_DECLARE(void) gdImageString16 (gdImagePtr im, gdFontPtr f, int x, int y, + unsigned short *s, int color); +BGD_DECLARE(void) gdImageStringUp16 (gdImagePtr im, gdFontPtr f, int x, int y, + unsigned short *s, int color); + +/* 2.0.16: for thread-safe use of gdImageStringFT and friends, + call this before allowing any thread to call gdImageStringFT. + Otherwise it is invoked by the first thread to invoke + gdImageStringFT, with a very small but real risk of a race condition. + Return 0 on success, nonzero on failure to initialize freetype. */ +BGD_DECLARE(int) gdFontCacheSetup (void); + +/* Optional: clean up after application is done using fonts in + gdImageStringFT(). */ +BGD_DECLARE(void) gdFontCacheShutdown (void); +/* 2.0.20: for backwards compatibility. A few applications did start calling + this function when it first appeared although it was never documented. + Simply invokes gdFontCacheShutdown. */ +BGD_DECLARE(void) gdFreeFontCache (void); + +/* Calls gdImageStringFT. Provided for backwards compatibility only. */ +BGD_DECLARE(char *) gdImageStringTTF (gdImage * im, int *brect, int fg, char *fontlist, + double ptsize, double angle, int x, int y, + char *string); + +/* FreeType 2 text output */ +BGD_DECLARE(char *) gdImageStringFT (gdImage * im, int *brect, int fg, char *fontlist, + double ptsize, double angle, int x, int y, + char *string); + + +/* + Group: Types + + typedef: gdFTStringExtra + + typedef: gdFTStringExtraPtr + + A structure and associated pointer type used to pass additional + parameters to the <gdImageStringFTEx> function. See + <gdImageStringFTEx> for the structure definition. + + Thanks to Wez Furlong. +*/ + +/* 2.0.5: provides an extensible way to pass additional parameters. + Thanks to Wez Furlong, sorry for the delay. */ +typedef struct { + int flags; /* Logical OR of gdFTEX_ values */ + double linespacing; /* fine tune line spacing for '\n' */ + int charmap; /* TBB: 2.0.12: may be gdFTEX_Unicode, + gdFTEX_Shift_JIS, gdFTEX_Big5, + or gdFTEX_Adobe_Custom; + when not specified, maps are searched + for in the above order. */ + int hdpi; /* if (flags & gdFTEX_RESOLUTION) */ + int vdpi; /* if (flags & gdFTEX_RESOLUTION) */ + char *xshow; /* if (flags & gdFTEX_XSHOW) + then, on return, xshow is a malloc'ed + string containing xshow position data for + the last string. + + NB. The caller is responsible for gdFree'ing + the xshow string. + */ + char *fontpath; /* if (flags & gdFTEX_RETURNFONTPATHNAME) + then, on return, fontpath is a malloc'ed + string containing the actual font file path name + used, which can be interesting when fontconfig + is in use. + + The caller is responsible for gdFree'ing the + fontpath string. + */ + +} +gdFTStringExtra, *gdFTStringExtraPtr; + +#define gdFTEX_LINESPACE 1 +#define gdFTEX_CHARMAP 2 +#define gdFTEX_RESOLUTION 4 +#define gdFTEX_DISABLE_KERNING 8 +#define gdFTEX_XSHOW 16 +/* The default unless gdFTUseFontConfig(1); has been called: + fontlist is a full or partial font file pathname or list thereof + (i.e. just like before 2.0.29) */ +#define gdFTEX_FONTPATHNAME 32 +/* Necessary to use fontconfig patterns instead of font pathnames + as the fontlist argument, unless gdFTUseFontConfig(1); has + been called. New in 2.0.29 */ +#define gdFTEX_FONTCONFIG 64 +/* Sometimes interesting when fontconfig is used: the fontpath + element of the structure above will contain a gdMalloc'd string + copy of the actual font file pathname used, if this flag is set + when the call is made */ +#define gdFTEX_RETURNFONTPATHNAME 128 + +/* If flag is nonzero, the fontlist parameter to gdImageStringFT + and gdImageStringFTEx shall be assumed to be a fontconfig font pattern + if fontconfig was compiled into gd. This function returns zero + if fontconfig is not available, nonzero otherwise. */ +BGD_DECLARE(int) gdFTUseFontConfig(int flag); + +/* These are NOT flags; set one in 'charmap' if you set the + gdFTEX_CHARMAP bit in 'flags'. */ +#define gdFTEX_Unicode 0 +#define gdFTEX_Shift_JIS 1 +#define gdFTEX_Big5 2 +#define gdFTEX_Adobe_Custom 3 + +BGD_DECLARE(char *) gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist, + double ptsize, double angle, int x, int y, + char *string, gdFTStringExtraPtr strex); + + +/* + Group: Types + + typedef: gdPoint + + typedef: gdPointPtr + + Represents a point in the coordinate space of the image; used by + <gdImagePolygon>, <gdImageOpenPolygon> and <gdImageFilledPolygon> + for polygon drawing. + + > typedef struct { + > int x, y; + > } gdPoint, *gdPointPtr; + +*/ +typedef struct { + int x, y; +} +gdPoint, *gdPointPtr; + +/** + * Typedef: gdRect + * + * A rectangle in the coordinate space of the image + * + * Members: + * x - The x-coordinate of the upper left corner. + * y - The y-coordinate of the upper left corner. + * width - The width. + * height - The height. + * + * Typedef: gdRectPtr + * + * A pointer to a <gdRect> + */ +typedef struct { + int x, y; + int width, height; +} +gdRect, *gdRectPtr; + + +BGD_DECLARE(void) gdImagePolygon (gdImagePtr im, gdPointPtr p, int n, int c); +BGD_DECLARE(void) gdImageOpenPolygon (gdImagePtr im, gdPointPtr p, int n, int c); +BGD_DECLARE(void) gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int c); + +/* These functions still work with truecolor images, + for which they never return error. */ +BGD_DECLARE(int) gdImageColorAllocate (gdImagePtr im, int r, int g, int b); +/* gd 2.0: palette entries with non-opaque transparency are permitted. */ +BGD_DECLARE(int) gdImageColorAllocateAlpha (gdImagePtr im, int r, int g, int b, int a); +/* Assumes opaque is the preferred alpha channel value */ +BGD_DECLARE(int) gdImageColorClosest (gdImagePtr im, int r, int g, int b); +/* Closest match taking all four parameters into account. + A slightly different color with the same transparency + beats the exact same color with radically different + transparency */ +BGD_DECLARE(int) gdImageColorClosestAlpha (gdImagePtr im, int r, int g, int b, int a); +/* An alternate method */ +BGD_DECLARE(int) gdImageColorClosestHWB (gdImagePtr im, int r, int g, int b); +/* Returns exact, 100% opaque matches only */ +BGD_DECLARE(int) gdImageColorExact (gdImagePtr im, int r, int g, int b); +/* Returns an exact match only, including alpha */ +BGD_DECLARE(int) gdImageColorExactAlpha (gdImagePtr im, int r, int g, int b, int a); +/* Opaque only */ +BGD_DECLARE(int) gdImageColorResolve (gdImagePtr im, int r, int g, int b); +/* Based on gdImageColorExactAlpha and gdImageColorClosestAlpha */ +BGD_DECLARE(int) gdImageColorResolveAlpha (gdImagePtr im, int r, int g, int b, int a); + +/* A simpler way to obtain an opaque truecolor value for drawing on a + truecolor image. Not for use with palette images! */ + +#define gdTrueColor(r, g, b) (((r) << 16) + \ + ((g) << 8) + \ + (b)) + +/** + * Group: Color Composition + * + * Macro: gdTrueColorAlpha + * + * Compose a truecolor value from its components + * + * Parameters: + * r - The red channel (0-255) + * g - The green channel (0-255) + * b - The blue channel (0-255) + * a - The alpha channel (0-127, where 127 is fully transparent, and 0 is + * completely opaque). + * + * See also: + * - <gdTrueColorGetAlpha> + * - <gdTrueColorGetRed> + * - <gdTrueColorGetGreen> + * - <gdTrueColorGetBlue> + * - <gdImageColorExactAlpha> + */ +#define gdTrueColorAlpha(r, g, b, a) (((a) << 24) + \ + ((r) << 16) + \ + ((g) << 8) + \ + (b)) + +BGD_DECLARE(void) gdImageColorDeallocate (gdImagePtr im, int color); + +/* Converts a truecolor image to a palette-based image, + using a high-quality two-pass quantization routine + which attempts to preserve alpha channel information + as well as R/G/B color information when creating + a palette. If ditherFlag is set, the image will be + dithered to approximate colors better, at the expense + of some obvious "speckling." colorsWanted can be + anything up to 256. If the original source image + includes photographic information or anything that + came out of a JPEG, 256 is strongly recommended. + + Better yet, don't use these function -- write real + truecolor PNGs and JPEGs. The disk space gain of + conversion to palette is not great (for small images + it can be negative) and the quality loss is ugly. + + DIFFERENCES: gdImageCreatePaletteFromTrueColor creates and + returns a new image. gdImageTrueColorToPalette modifies + an existing image, and the truecolor pixels are discarded. + + gdImageTrueColorToPalette() returns TRUE on success, FALSE on failure. +*/ + +BGD_DECLARE(gdImagePtr) gdImageCreatePaletteFromTrueColor (gdImagePtr im, int ditherFlag, + int colorsWanted); + +BGD_DECLARE(int) gdImageTrueColorToPalette (gdImagePtr im, int ditherFlag, + int colorsWanted); + +BGD_DECLARE(int) gdImagePaletteToTrueColor(gdImagePtr src); + +/* An attempt at getting the results of gdImageTrueColorToPalette to + * look a bit more like the original (im1 is the original and im2 is + * the palette version */ + +BGD_DECLARE(int) gdImageColorMatch(gdImagePtr im1, gdImagePtr im2); + +/* Selects quantization method used for subsequent gdImageTrueColorToPalette calls. + See gdPaletteQuantizationMethod enum (e.g. GD_QUANT_NEUQUANT, GD_QUANT_LIQ). + Speed is from 1 (highest quality) to 10 (fastest). + Speed 0 selects method-specific default (recommended). + + Returns FALSE if the given method is invalid or not available. +*/ +BGD_DECLARE(int) gdImageTrueColorToPaletteSetMethod (gdImagePtr im, int method, int speed); + +/* + Chooses quality range that subsequent call to gdImageTrueColorToPalette will aim for. + Min and max quality is in range 1-100 (1 = ugly, 100 = perfect). Max must be higher than min. + If palette cannot represent image with at least min_quality, then image will remain true-color. + If palette can represent image with quality better than max_quality, then lower number of colors will be used. + This function has effect only when GD_QUANT_LIQ method has been selected and the source image is true-color. +*/ +BGD_DECLARE(void) gdImageTrueColorToPaletteSetQuality (gdImagePtr im, int min_quality, int max_quality); + +/* Specifies a color index (if a palette image) or an + RGB color (if a truecolor image) which should be + considered 100% transparent. FOR TRUECOLOR IMAGES, + THIS IS IGNORED IF AN ALPHA CHANNEL IS BEING + SAVED. Use gdImageSaveAlpha(im, 0); to + turn off the saving of a full alpha channel in + a truecolor image. Note that gdImageColorTransparent + is usually compatible with older browsers that + do not understand full alpha channels well. TBB */ +BGD_DECLARE(void) gdImageColorTransparent (gdImagePtr im, int color); + +BGD_DECLARE(void) gdImagePaletteCopy (gdImagePtr dst, gdImagePtr src); + +typedef int (*gdCallbackImageColor)(gdImagePtr im, int src); + +BGD_DECLARE(int) gdImageColorReplace(gdImagePtr im, int src, int dst); +BGD_DECLARE(int) gdImageColorReplaceThreshold(gdImagePtr im, int src, int dst, float threshold); +BGD_DECLARE(int) gdImageColorReplaceArray(gdImagePtr im, int len, int *src, int *dst); +BGD_DECLARE(int) gdImageColorReplaceCallback(gdImagePtr im, gdCallbackImageColor callback); + +BGD_DECLARE(void) gdImageGif (gdImagePtr im, FILE * out); +BGD_DECLARE(void) gdImagePng (gdImagePtr im, FILE * out); +//BGD_DECLARE(void) gdImagePngCtx (gdImagePtr im, gdIOCtx * out); +//BGD_DECLARE(void) gdImageGifCtx (gdImagePtr im, gdIOCtx * out); +BGD_DECLARE(void) gdImageTiff(gdImagePtr im, FILE *outFile); +BGD_DECLARE(void *) gdImageTiffPtr(gdImagePtr im, int *size); +//BGD_DECLARE(void) gdImageTiffCtx(gdImagePtr image, gdIOCtx *out); + +BGD_DECLARE(void *) gdImageBmpPtr(gdImagePtr im, int *size, int compression); +BGD_DECLARE(void) gdImageBmp(gdImagePtr im, FILE *outFile, int compression); +//BGD_DECLARE(void) gdImageBmpCtx(gdImagePtr im, gdIOCtxPtr out, int compression); + +/* 2.0.12: Compression level: 0-9 or -1, where 0 is NO COMPRESSION at all, + 1 is FASTEST but produces larger files, 9 provides the best + compression (smallest files) but takes a long time to compress, and + -1 selects the default compiled into the zlib library. */ +BGD_DECLARE(void) gdImagePngEx (gdImagePtr im, FILE * out, int level); +//BGD_DECLARE(void) gdImagePngCtxEx (gdImagePtr im, gdIOCtx * out, int level); + +BGD_DECLARE(void) gdImageWBMP (gdImagePtr image, int fg, FILE * out); +//BGD_DECLARE(void) gdImageWBMPCtx (gdImagePtr image, int fg, gdIOCtx * out); + +BGD_DECLARE(int) gdImageFile(gdImagePtr im, const char *filename); +BGD_DECLARE(int) gdSupportsFileType(const char *filename, int writing); + + +/* Guaranteed to correctly free memory returned by the gdImage*Ptr + functions */ +BGD_DECLARE(void) gdFree (void *m); + +/* Best to free this memory with gdFree(), not free() */ +BGD_DECLARE(void *) gdImageWBMPPtr (gdImagePtr im, int *size, int fg); + +/* 100 is highest quality (there is always a little loss with JPEG). + 0 is lowest. 10 is about the lowest useful setting. */ +BGD_DECLARE(void) gdImageJpeg (gdImagePtr im, FILE * out, int quality); +//BGD_DECLARE(void) gdImageJpegCtx (gdImagePtr im, gdIOCtx * out, int quality); + +/* Best to free this memory with gdFree(), not free() */ +BGD_DECLARE(void *) gdImageJpegPtr (gdImagePtr im, int *size, int quality); + +BGD_DECLARE(void) gdImageWebpEx (gdImagePtr im, FILE * outFile, int quantization); +BGD_DECLARE(void) gdImageWebp (gdImagePtr im, FILE * outFile); +BGD_DECLARE(void *) gdImageWebpPtr (gdImagePtr im, int *size); +BGD_DECLARE(void *) gdImageWebpPtrEx (gdImagePtr im, int *size, int quantization); +//BGD_DECLARE(void) gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quantization); + + +/** + * Group: GifAnim + * + * Legal values for Disposal. gdDisposalNone is always used by + * the built-in optimizer if previm is passed. + * + * Constants: gdImageGifAnim + * + * gdDisposalUnknown - Not recommended + * gdDisposalNone - Preserve previous frame + * gdDisposalRestoreBackground - First allocated color of palette + * gdDisposalRestorePrevious - Restore to before start of frame + * + * See also: + * - <gdImageGifAnimAdd> + */ +enum { + gdDisposalUnknown, + gdDisposalNone, + gdDisposalRestoreBackground, + gdDisposalRestorePrevious +}; + +BGD_DECLARE(void) gdImageGifAnimBegin(gdImagePtr im, FILE *outFile, int GlobalCM, int Loops); +BGD_DECLARE(void) gdImageGifAnimAdd(gdImagePtr im, FILE *outFile, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm); +BGD_DECLARE(void) gdImageGifAnimEnd(FILE *outFile); +//BGD_DECLARE(void) gdImageGifAnimBeginCtx(gdImagePtr im, gdIOCtx *out, int GlobalCM, int Loops); +//BGD_DECLARE(void) gdImageGifAnimAddCtx(gdImagePtr im, gdIOCtx *out, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm); +//BGD_DECLARE(void) gdImageGifAnimEndCtx(gdIOCtx *out); +BGD_DECLARE(void *) gdImageGifAnimBeginPtr(gdImagePtr im, int *size, int GlobalCM, int Loops); +BGD_DECLARE(void *) gdImageGifAnimAddPtr(gdImagePtr im, int *size, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm); +BGD_DECLARE(void *) gdImageGifAnimEndPtr(int *size); + + + +/* + Group: Types + + typedef: gdSink + + typedef: gdSinkPtr + + *Note:* This interface is *obsolete* and kept only for + *compatibility*. Use <gdIOCtx> instead. + + Represents a "sink" (destination) to which a PNG can be + written. Programmers who do not wish to write PNGs to a file can + provide their own alternate output mechanism, using the + <gdImagePngToSink> function. See the documentation of that + function for an example of the proper use of this type. + + > typedef struct { + > int (*sink) (void *context, char *buffer, int len); + > void *context; + > } gdSink, *gdSinkPtr; + + The _sink_ function must return -1 on error, otherwise the number of + bytes written, which must be equal to len. + + _context_ will be passed to your sink function. + +*/ + +typedef struct { + int (*sink) (void *context, const char *buffer, int len); + void *context; +} +gdSink, *gdSinkPtr; + +BGD_DECLARE(void) gdImagePngToSink (gdImagePtr im, gdSinkPtr out); + +BGD_DECLARE(void) gdImageGd (gdImagePtr im, FILE * out); +BGD_DECLARE(void) gdImageGd2 (gdImagePtr im, FILE * out, int cs, int fmt); + +/* Best to free this memory with gdFree(), not free() */ +BGD_DECLARE(void *) gdImageGifPtr (gdImagePtr im, int *size); + +/* Best to free this memory with gdFree(), not free() */ +BGD_DECLARE(void *) gdImagePngPtr (gdImagePtr im, int *size); +BGD_DECLARE(void *) gdImagePngPtrEx (gdImagePtr im, int *size, int level); + +/* Best to free this memory with gdFree(), not free() */ +BGD_DECLARE(void *) gdImageGdPtr (gdImagePtr im, int *size); + +/* Best to free this memory with gdFree(), not free() */ +BGD_DECLARE(void *) gdImageGd2Ptr (gdImagePtr im, int cs, int fmt, int *size); + +/* Style is a bitwise OR ( | operator ) of these. + gdArc and gdChord are mutually exclusive; + gdChord just connects the starting and ending + angles with a straight line, while gdArc produces + a rounded edge. gdPie is a synonym for gdArc. + gdNoFill indicates that the arc or chord should be + outlined, not filled. gdEdged, used together with + gdNoFill, indicates that the beginning and ending + angles should be connected to the center; this is + a good way to outline (rather than fill) a + 'pie slice'. */ +#define gdArc 0 +#define gdPie gdArc +#define gdChord 1 +#define gdNoFill 2 +#define gdEdged 4 + +BGD_DECLARE(void) gdImageFilledArc (gdImagePtr im, int cx, int cy, int w, int h, int s, + int e, int color, int style); +BGD_DECLARE(void) gdImageArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, + int color); +BGD_DECLARE(void) gdImageEllipse(gdImagePtr im, int cx, int cy, int w, int h, int color); +BGD_DECLARE(void) gdImageFilledEllipse (gdImagePtr im, int cx, int cy, int w, int h, + int color); +BGD_DECLARE(void) gdImageFillToBorder (gdImagePtr im, int x, int y, int border, + int color); +BGD_DECLARE(void) gdImageFill (gdImagePtr im, int x, int y, int color); +BGD_DECLARE(void) gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, + int srcX, int srcY, int w, int h); +BGD_DECLARE(void) gdImageCopyMerge (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, + int srcX, int srcY, int w, int h, int pct); +BGD_DECLARE(void) gdImageCopyMergeGray (gdImagePtr dst, gdImagePtr src, int dstX, + int dstY, int srcX, int srcY, int w, int h, + int pct); + +/* Stretches or shrinks to fit, as needed. Does NOT attempt + to average the entire set of source pixels that scale down onto the + destination pixel. */ +BGD_DECLARE(void) gdImageCopyResized (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, + int srcX, int srcY, int dstW, int dstH, int srcW, + int srcH); + +/* gd 2.0: stretches or shrinks to fit, as needed. When called with a + truecolor destination image, this function averages the + entire set of source pixels that scale down onto the + destination pixel, taking into account what portion of the + destination pixel each source pixel represents. This is a + floating point operation, but this is not a performance issue + on modern hardware, except for some embedded devices. If the + destination is a palette image, gdImageCopyResized is + substituted automatically. */ +BGD_DECLARE(void) gdImageCopyResampled (gdImagePtr dst, gdImagePtr src, int dstX, + int dstY, int srcX, int srcY, int dstW, int dstH, + int srcW, int srcH); + +/* gd 2.0.8: gdImageCopyRotated is added. Source + is a rectangle, with its upper left corner at + srcX and srcY. Destination is the *center* of + the rotated copy. Angle is in degrees, same as + gdImageArc. Floating point destination center + coordinates allow accurate rotation of + objects of odd-numbered width or height. */ +BGD_DECLARE(void) gdImageCopyRotated (gdImagePtr dst, + gdImagePtr src, + double dstX, double dstY, + int srcX, int srcY, + int srcWidth, int srcHeight, int angle); + +BGD_DECLARE(gdImagePtr) gdImageClone (gdImagePtr src); + +BGD_DECLARE(void) gdImageSetBrush (gdImagePtr im, gdImagePtr brush); +BGD_DECLARE(void) gdImageSetTile (gdImagePtr im, gdImagePtr tile); +BGD_DECLARE(void) gdImageSetAntiAliased (gdImagePtr im, int c); +BGD_DECLARE(void) gdImageSetAntiAliasedDontBlend (gdImagePtr im, int c, int dont_blend); +BGD_DECLARE(void) gdImageSetStyle (gdImagePtr im, int *style, int noOfPixels); +/* Line thickness (defaults to 1). Affects lines, ellipses, + rectangles, polygons and so forth. */ +BGD_DECLARE(void) gdImageSetThickness (gdImagePtr im, int thickness); +/* On or off (1 or 0) for all three of these. */ +BGD_DECLARE(void) gdImageInterlace (gdImagePtr im, int interlaceArg); +BGD_DECLARE(void) gdImageAlphaBlending (gdImagePtr im, int alphaBlendingArg); +BGD_DECLARE(void) gdImageSaveAlpha (gdImagePtr im, int saveAlphaArg); + +BGD_DECLARE(gdImagePtr) gdImageNeuQuant(gdImagePtr im, const int max_color, int sample_factor); + +enum gdPixelateMode { + GD_PIXELATE_UPPERLEFT, + GD_PIXELATE_AVERAGE +}; + +BGD_DECLARE(int) gdImagePixelate(gdImagePtr im, int block_size, const unsigned int mode); + +typedef struct { + int sub; + int plus; + unsigned int num_colors; + int *colors; + unsigned int seed; +} gdScatter, *gdScatterPtr; + +BGD_DECLARE(int) gdImageScatter(gdImagePtr im, int sub, int plus); +BGD_DECLARE(int) gdImageScatterColor(gdImagePtr im, int sub, int plus, int colors[], unsigned int num_colors); +BGD_DECLARE(int) gdImageScatterEx(gdImagePtr im, gdScatterPtr s); +BGD_DECLARE(int) gdImageSmooth(gdImagePtr im, float weight); +BGD_DECLARE(int) gdImageMeanRemoval(gdImagePtr im); +BGD_DECLARE(int) gdImageEmboss(gdImagePtr im); +BGD_DECLARE(int) gdImageGaussianBlur(gdImagePtr im); +BGD_DECLARE(int) gdImageEdgeDetectQuick(gdImagePtr src); +BGD_DECLARE(int) gdImageSelectiveBlur( gdImagePtr src); +BGD_DECLARE(int) gdImageConvolution(gdImagePtr src, float filter[3][3], float filter_div, float offset); +BGD_DECLARE(int) gdImageColor(gdImagePtr src, const int red, const int green, const int blue, const int alpha); +BGD_DECLARE(int) gdImageContrast(gdImagePtr src, double contrast); +BGD_DECLARE(int) gdImageBrightness(gdImagePtr src, int brightness); +BGD_DECLARE(int) gdImageGrayScale(gdImagePtr src); +BGD_DECLARE(int) gdImageNegate(gdImagePtr src); + +BGD_DECLARE(gdImagePtr) gdImageCopyGaussianBlurred(gdImagePtr src, int radius, + double sigma); + + +/** + * Group: Accessor Macros + */ + +/** + * Macro: gdImageTrueColor + * + * Whether an image is a truecolor image. + * + * Parameters: + * im - The image. + * + * Returns: + * Non-zero if the image is a truecolor image, zero for palette images. + */ +#define gdImageTrueColor(im) ((im)->trueColor) + +/** + * Macro: gdImageSX + * + * Gets the width (in pixels) of an image. + * + * Parameters: + * im - The image. + */ +#define gdImageSX(im) ((im)->sx) + +/** + * Macro: gdImageSY + * + * Gets the height (in pixels) of an image. + * + * Parameters: + * im - The image. + */ +#define gdImageSY(im) ((im)->sy) + +/** + * Macro: gdImageColorsTotal + * + * Gets the number of colors in the palette. + * + * This macro is only valid for palette images. + * + * Parameters: + * im - The image + */ +#define gdImageColorsTotal(im) ((im)->colorsTotal) + +/** + * Macro: gdImageRed + * + * Gets the red component value of a given color. + * + * Parameters: + * im - The image. + * c - The color. + */ +#define gdImageRed(im, c) ((im)->trueColor ? gdTrueColorGetRed(c) : \ + (im)->red[(c)]) + +/** + * Macro: gdImageGreen + * + * Gets the green component value of a given color. + * + * Parameters: + * im - The image. + * c - The color. + */ +#define gdImageGreen(im, c) ((im)->trueColor ? gdTrueColorGetGreen(c) : \ + (im)->green[(c)]) + +/** + * Macro: gdImageBlue + * + * Gets the blue component value of a given color. + * + * Parameters: + * im - The image. + * c - The color. + */ +#define gdImageBlue(im, c) ((im)->trueColor ? gdTrueColorGetBlue(c) : \ + (im)->blue[(c)]) + +/** + * Macro: gdImageAlpha + * + * Gets the alpha component value of a given color. + * + * Parameters: + * im - The image. + * c - The color. + */ +#define gdImageAlpha(im, c) ((im)->trueColor ? gdTrueColorGetAlpha(c) : \ + (im)->alpha[(c)]) + +/** + * Macro: gdImageGetTransparent + * + * Gets the transparent color of the image. + * + * Parameters: + * im - The image. + * + * See also: + * - <gdImageColorTransparent> + */ +#define gdImageGetTransparent(im) ((im)->transparent) + +/** + * Macro: gdImageGetInterlaced + * + * Whether an image is interlaced. + * + * Parameters: + * im - The image. + * + * Returns: + * Non-zero for interlaced images, zero otherwise. + * + * See also: + * - <gdImageInterlace> + */ +#define gdImageGetInterlaced(im) ((im)->interlace) + +/** + * Macro: gdImagePalettePixel + * + * Gets the color of a pixel. + * + * Calling this macro is only valid for palette images. + * No bounds checking is done for the coordinates. + * + * Parameters: + * im - The image. + * x - The x-coordinate. + * y - The y-coordinate. + * + * See also: + * - <gdImageTrueColorPixel> + * - <gdImageGetPixel> + */ +#define gdImagePalettePixel(im, x, y) (im)->pixels[(y)][(x)] + +/** + * Macro: gdImageTrueColorPixel + * + * Gets the color of a pixel. + * + * Calling this macro is only valid for truecolor images. + * No bounds checking is done for the coordinates. + * + * Parameters: + * im - The image. + * x - The x-coordinate. + * y - The y-coordinate. + * + * See also: + * - <gdImagePalettePixel> + * - <gdImageGetTrueColorPixel> + */ +#define gdImageTrueColorPixel(im, x, y) (im)->tpixels[(y)][(x)] + +/** + * Macro: gdImageResolutionX + * + * Gets the horizontal resolution in DPI. + * + * Parameters: + * im - The image. + * + * See also: + * - <gdImageResolutionY> + * - <gdImageSetResolution> + */ +#define gdImageResolutionX(im) (im)->res_x + +/** + * Macro: gdImageResolutionY + * + * Gets the vertical resolution in DPI. + * + * Parameters: + * im - The image. + * + * See also: + * - <gdImageResolutionX> + * - <gdImageSetResolution> + */ +#define gdImageResolutionY(im) (im)->res_y + +/* I/O Support routines. */ + +//BGD_DECLARE(gdIOCtx *) gdNewFileCtx (FILE *); +/* If data is null, size is ignored and an initial data buffer is + allocated automatically. NOTE: this function assumes gd has the right + to free or reallocate "data" at will! Also note that gd will free + "data" when the IO context is freed. If data is not null, it must point + to memory allocated with gdMalloc, or by a call to gdImage[something]Ptr. + If not, see gdNewDynamicCtxEx for an alternative. */ +//BGD_DECLARE(gdIOCtx *) gdNewDynamicCtx (int size, void *data); +/* 2.0.21: if freeFlag is nonzero, gd will free and/or reallocate "data" as + needed as described above. If freeFlag is zero, gd will never free + or reallocate "data", which means that the context should only be used + for *reading* an image from a memory buffer, or writing an image to a + memory buffer which is already large enough. If the memory buffer is + not large enough and an image write is attempted, the write operation + will fail. Those wishing to write an image to a buffer in memory have + a much simpler alternative in the gdImage[something]Ptr functions. */ +//BGD_DECLARE(gdIOCtx *) gdNewDynamicCtxEx (int size, void *data, int freeFlag); +//BGD_DECLARE(gdIOCtx *) gdNewSSCtx (gdSourcePtr in, gdSinkPtr out); +//BGD_DECLARE(void *) gdDPExtractData (struct gdIOCtx *ctx, int *size); + +#define GD2_CHUNKSIZE 128 +#define GD2_CHUNKSIZE_MIN 64 +#define GD2_CHUNKSIZE_MAX 4096 + +#define GD2_VERS 2 +#define GD2_ID "gd2" + +#define GD2_FMT_RAW 1 +#define GD2_FMT_COMPRESSED 2 + +/* Image comparison definitions */ +BGD_DECLARE(int) gdImageCompare (gdImagePtr im1, gdImagePtr im2); + +BGD_DECLARE(void) gdImageFlipHorizontal(gdImagePtr im); +BGD_DECLARE(void) gdImageFlipVertical(gdImagePtr im); +BGD_DECLARE(void) gdImageFlipBoth(gdImagePtr im); + +#define GD_FLIP_HORINZONTAL 1 +#define GD_FLIP_VERTICAL 2 +#define GD_FLIP_BOTH 3 + +/** + * Group: Crop + * + * Constants: gdCropMode + * GD_CROP_DEFAULT - Default crop mode (4 corners or background) + * GD_CROP_TRANSPARENT - Crop using the transparent color + * GD_CROP_BLACK - Crop black borders + * GD_CROP_WHITE - Crop white borders + * GD_CROP_SIDES - Crop using colors of the 4 corners + * + * See also: + * - <gdImageCropAuto> + **/ +enum gdCropMode { + GD_CROP_DEFAULT = 0, + GD_CROP_TRANSPARENT, + GD_CROP_BLACK, + GD_CROP_WHITE, + GD_CROP_SIDES, + GD_CROP_THRESHOLD +}; + +BGD_DECLARE(gdImagePtr) gdImageCrop(gdImagePtr src, const gdRect *crop); +BGD_DECLARE(gdImagePtr) gdImageCropAuto(gdImagePtr im, const unsigned int mode); +BGD_DECLARE(gdImagePtr) gdImageCropThreshold(gdImagePtr im, const unsigned int color, const float threshold); + +BGD_DECLARE(int) gdImageSetInterpolationMethod(gdImagePtr im, gdInterpolationMethod id); +BGD_DECLARE(gdInterpolationMethod) gdImageGetInterpolationMethod(gdImagePtr im); + +BGD_DECLARE(gdImagePtr) gdImageScale(const gdImagePtr src, const unsigned int new_width, const unsigned int new_height); + +BGD_DECLARE(gdImagePtr) gdImageRotateInterpolated(const gdImagePtr src, const float angle, int bgcolor); + +typedef enum { + GD_AFFINE_TRANSLATE = 0, + GD_AFFINE_SCALE, + GD_AFFINE_ROTATE, + GD_AFFINE_SHEAR_HORIZONTAL, + GD_AFFINE_SHEAR_VERTICAL +} gdAffineStandardMatrix; + +BGD_DECLARE(int) gdAffineApplyToPointF (gdPointFPtr dst, const gdPointFPtr src, const double affine[6]); +BGD_DECLARE(int) gdAffineInvert (double dst[6], const double src[6]); +BGD_DECLARE(int) gdAffineFlip (double dst_affine[6], const double src_affine[6], const int flip_h, const int flip_v); +BGD_DECLARE(int) gdAffineConcat (double dst[6], const double m1[6], const double m2[6]); + +BGD_DECLARE(int) gdAffineIdentity (double dst[6]); +BGD_DECLARE(int) gdAffineScale (double dst[6], const double scale_x, const double scale_y); +BGD_DECLARE(int) gdAffineRotate (double dst[6], const double angle); +BGD_DECLARE(int) gdAffineShearHorizontal (double dst[6], const double angle); +BGD_DECLARE(int) gdAffineShearVertical(double dst[6], const double angle); +BGD_DECLARE(int) gdAffineTranslate (double dst[6], const double offset_x, const double offset_y); +BGD_DECLARE(double) gdAffineExpansion (const double src[6]); +BGD_DECLARE(int) gdAffineRectilinear (const double src[6]); +BGD_DECLARE(int) gdAffineEqual (const double matrix1[6], const double matrix2[6]); +BGD_DECLARE(int) gdTransformAffineGetImage(gdImagePtr *dst, const gdImagePtr src, gdRectPtr src_area, const double affine[6]); +BGD_DECLARE(int) gdTransformAffineCopy(gdImagePtr dst, int dst_x, int dst_y, const gdImagePtr src, gdRectPtr src_region, const double affine[6]); +/* +gdTransformAffineCopy(gdImagePtr dst, int x0, int y0, int x1, int y1, + const gdImagePtr src, int src_width, int src_height, + const double affine[6]); +*/ +BGD_DECLARE(int) gdTransformAffineBoundingBox(gdRectPtr src, const double affine[6], gdRectPtr bbox); + +/** + * Group: Image Comparison + * + * Constants: + * GD_CMP_IMAGE - Actual image IS different + * GD_CMP_NUM_COLORS - Number of colors in pallette differ + * GD_CMP_COLOR - Image colors differ + * GD_CMP_SIZE_X - Image width differs + * GD_CMP_SIZE_Y - Image heights differ + * GD_CMP_TRANSPARENT - Transparent color differs + * GD_CMP_BACKGROUND - Background color differs + * GD_CMP_INTERLACE - Interlaced setting differs + * GD_CMP_TRUECOLOR - Truecolor vs palette differs + * + * See also: + * - <gdImageCompare> + */ +#define GD_CMP_IMAGE 1 +#define GD_CMP_NUM_COLORS 2 +#define GD_CMP_COLOR 4 +#define GD_CMP_SIZE_X 8 +#define GD_CMP_SIZE_Y 16 +#define GD_CMP_TRANSPARENT 32 +#define GD_CMP_BACKGROUND 64 +#define GD_CMP_INTERLACE 128 +#define GD_CMP_TRUECOLOR 256 + +/* resolution affects ttf font rendering, particularly hinting */ +#define GD_RESOLUTION 96 /* pixels per inch */ + + +/* Version information functions */ +BGD_DECLARE(int) gdMajorVersion(void); +BGD_DECLARE(int) gdMinorVersion(void); +BGD_DECLARE(int) gdReleaseVersion(void); +BGD_DECLARE(const char *) gdExtraVersion(void); +BGD_DECLARE(const char *) gdVersionString(void); + + +#ifdef __cplusplus +} +#endif + +/* newfangled special effects */ +//#include "gdfx.h" + +#endif /* GD_H */ + +#ifdef __cplusplus +} +#endif diff --git a/libmscgen/gd_color.c b/libmscgen/gd_color.c new file mode 100644 index 0000000..ba0efd8 --- /dev/null +++ b/libmscgen/gd_color.c @@ -0,0 +1,35 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gd.h" +#include "gd_color.h" + +/** + * The threshold method works relatively well but it can be improved. + * Maybe L*a*b* and Delta-E will give better results (and a better + * granularity). + */ +int gdColorMatch(gdImagePtr im, int col1, int col2, float threshold) +{ + const int dr = gdImageRed(im, col1) - gdImageRed(im, col2); + const int dg = gdImageGreen(im, col1) - gdImageGreen(im, col2); + const int db = gdImageBlue(im, col1) - gdImageBlue(im, col2); + const int da = gdImageAlpha(im, col1) - gdImageAlpha(im, col2); + const int dist = dr * dr + dg * dg + db * db + da * da; + + return (100.0 * dist / 195075) < threshold; +} + +/* + * To be implemented when we have more image formats. + * Buffer like gray8 gray16 or rgb8 will require some tweak + * and can be done in this function (called from the autocrop + * function. (Pierre) + */ +#if 0 +static int colors_equal (const int col1, const in col2) +{ + +} +#endif diff --git a/libmscgen/gd_color.h b/libmscgen/gd_color.h new file mode 100644 index 0000000..08b06ce --- /dev/null +++ b/libmscgen/gd_color.h @@ -0,0 +1,14 @@ +#ifndef GD_COLOR_H +#define GD_COLOR_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + + int gdColorMatch(gdImagePtr im, int col1, int col2, float threshold); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmscgen/gd_errors.h b/libmscgen/gd_errors.h new file mode 100644 index 0000000..4ecee94 --- /dev/null +++ b/libmscgen/gd_errors.h @@ -0,0 +1,46 @@ +#ifndef GD_ERRORS_H +#define GD_ERRORS_H + +#ifndef _WIN32 +# include <syslog.h> +#else +/* + * priorities/facilities are encoded into a single 32-bit quantity, where the + * bottom 3 bits are the priority (0-7) and the top 28 bits are the facility + * (0-big number). Both the priorities and the facilities map roughly + * one-to-one to strings in the syslogd(8) source code. This mapping is + * included in this file. + * + * priorities (these are ordered) + */ +# define LOG_EMERG 0 /* system is unusable */ +# define LOG_ALERT 1 /* action must be taken immediately */ +# define LOG_CRIT 2 /* critical conditions */ +# define LOG_ERR 3 /* error conditions */ +# define LOG_WARNING 4 /* warning conditions */ +# define LOG_NOTICE 5 /* normal but significant condition */ +# define LOG_INFO 6 /* informational */ +# define LOG_DEBUG 7 /* debug-level messages */ +#endif + +/* +LOG_EMERG system is unusable +LOG_ALERT action must be taken immediately +LOG_CRIT critical conditions +LOG_ERR error conditions +LOG_WARNING warning conditions +LOG_NOTICE normal, but significant, condition +LOG_INFO informational message +LOG_DEBUG debug-level message +*/ + +#define GD_ERROR LOG_ERR +#define GD_WARNING LOG_WARNING +#define GD_NOTICE LOG_NOTICE +#define GD_INFO LOG_INFO +#define GD_DEBUG LOG_DEBUG + +void gd_error(const char *format, ...); +void gd_error_ex(int priority, const char *format, ...); + +#endif diff --git a/libmscgen/gd_intern.h b/libmscgen/gd_intern.h new file mode 100644 index 0000000..86d817e --- /dev/null +++ b/libmscgen/gd_intern.h @@ -0,0 +1,90 @@ +#ifndef GD_INTERN_H +#define GD_INTERN_H + +#ifdef HAVE_LIMITS_H +#include <limits.h> +#endif + + +#ifndef MAXPATHLEN +# ifdef PATH_MAX +# define MAXPATHLEN PATH_MAX +# elif defined(MAX_PATH) +# define MAXPATHLEN MAX_PATH +# else +# if defined(__GNU__) +# define MAXPATHLEN 4096 +# else +# define MAXPATHLEN 256 /* Should be safe for any weird systems that do not define it */ +# endif +# endif +#endif + +#ifdef HAVE_STDINT_H +# include <stdint.h> +#else +# if defined(HAVE_INTTYPES_H) +# include <inttypes.h> +# else +# include "msinttypes/inttypes.h" +# endif +#endif + +#include "gd.h" + +#ifndef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) +#endif +#define MIN3(a,b,c) ((a)<(b)?(MIN(a,c)):(MIN(b,c))) +#ifndef MAX +#define MAX(a,b) ((a)<(b)?(b):(a)) +#endif +#define MAX3(a,b,c) ((a)<(b)?(MAX(b,c)):(MAX(a,c))) + + +typedef enum { + HORIZONTAL, + VERTICAL, +} gdAxis; + +/* Convert a double to an unsigned char, rounding to the nearest + * integer and clamping the result between 0 and max. The absolute + * value of clr must be less than the maximum value of an unsigned + * short. */ +static inline unsigned char +uchar_clamp(double clr, unsigned char max) { + unsigned short result; + + //assert(fabs(clr) <= SHRT_MAX); + + /* Casting a negative float to an unsigned short is undefined. + * However, casting a float to a signed truncates toward zero and + * casting a negative signed value to an unsigned of the same size + * results in a bit-identical value (assuming twos-complement + * arithmetic). This is what we want: all legal negative values + * for clr will be greater than 255. */ + + /* Convert and clamp. */ + result = (unsigned short)(short)(clr + 0.5); + if (result > max) { + result = (clr < 0) ? 0 : max; + }/* if */ + + return result; +}/* uchar_clamp*/ + + +/* Internal prototypes: */ + +/* gd_rotate.c */ +gdImagePtr gdImageRotate90(gdImagePtr src, int ignoretransparent); +gdImagePtr gdImageRotate180(gdImagePtr src, int ignoretransparent); +gdImagePtr gdImageRotate270(gdImagePtr src, int ignoretransparent); + + + + + + +#endif + diff --git a/libmscgen/gd_lodepng.c b/libmscgen/gd_lodepng.c new file mode 100644 index 0000000..b8ed22b --- /dev/null +++ b/libmscgen/gd_lodepng.c @@ -0,0 +1,35 @@ +#include "gd.h" +#include "lodepng.h" + +BGD_DECLARE(void) gdImagePng (gdImagePtr im, FILE * outFile) +{ + unsigned char *buffer; + size_t bufferSize; + int **ptpixels = im->tpixels; + unsigned char *pixelBuffer = (unsigned char *)malloc(3*im->sx*im->sy); + unsigned char *pOut = pixelBuffer; + int x,y; + for (y=0;y<im->sy;y++) + { + int *pThisRow = *ptpixels++; + for (x=0;x<im->sx;x++) + { + int thisPixel = *pThisRow++; + *pOut++ = gdTrueColorGetRed(thisPixel); + *pOut++ = gdTrueColorGetGreen(thisPixel); + *pOut++ = gdTrueColorGetBlue(thisPixel); + } + } + // TODO: convert ptPixels into pixelBuffer... + LodePNG_Encoder encoder; + LodePNG_Encoder_init(&encoder); + encoder.infoPng.color.colorType = 2; // 2=RGB 24 bit + encoder.infoRaw.color.colorType = 2; // 2=RGB 24 bit + LodePNG_encode(&encoder, &buffer, &bufferSize, pixelBuffer, im->sx, im->sy); + // write bufferSize bytes from buffer into outFile + fwrite(buffer,1,bufferSize,outFile); + LodePNG_Encoder_cleanup(&encoder); + free(buffer); + free(pixelBuffer); +} + diff --git a/libmscgen/gd_security.c b/libmscgen/gd_security.c new file mode 100644 index 0000000..0051ebf --- /dev/null +++ b/libmscgen/gd_security.c @@ -0,0 +1,32 @@ +/* + * gd_security.c + * + * Implements buffer overflow check routines. + * + * Written 2004, Phil Knirsch. + * Based on netpbm fixes by Alan Cox. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include "gd.h" +#include "gd_errors.h" + +int overflow2(int a, int b) +{ + if(a <= 0 || b <= 0) { + gd_error_ex(GD_WARNING, "one parameter to a memory allocation multiplication is negative or zero, failing operation gracefully\n"); + return 1; + } + if(a > INT_MAX / b) { + gd_error_ex(GD_WARNING, "product of memory allocation multiplication would exceed INT_MAX, failing operation gracefully\n"); + return 1; + } + return 0; +} diff --git a/libmscgen/gdfonts.c b/libmscgen/gdfonts.c new file mode 100644 index 0000000..e184e36 --- /dev/null +++ b/libmscgen/gdfonts.c @@ -0,0 +1,3890 @@ +/* + This is a header file for gd font, generated using + bdftogd version 0.5 by Jan Pazdziora, adelton@fi.muni.cz + from bdf font + -misc-fixed-medium-r-semicondensed-sans-12-116-75-75-c-60-iso8859-2 + at Thu Jan 8 14:13:20 1998. + No copyright info was found in the original bdf. + */ + +/** + * File: Small Font + * + * A small ISO-8859-2 raster font (7x13 pixels). + * + * The font is supposed to be used with <gdImageChar> and <gdImageString> + * and their variants. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gdfonts.h" + +char gdFontSmallData[] = { + /* Char 0 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 1 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 2 */ + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 0, 1, + 1, 0, 1, 0, 1, 0, + 0, 1, 0, 1, 0, 1, + 1, 0, 1, 0, 1, 0, + 0, 1, 0, 1, 0, 1, + 1, 0, 1, 0, 1, 0, + 0, 1, 0, 1, 0, 1, + 1, 0, 1, 0, 1, 0, + 0, 1, 0, 1, 0, 1, + 1, 0, 1, 0, 1, 0, + 0, 1, 0, 1, 0, 1, + 1, 0, 1, 0, 1, 0, + + /* Char 3 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 1, 0, 0, 0, + 1, 0, 1, 0, 0, 0, + 1, 1, 1, 0, 0, 0, + 1, 0, 1, 0, 0, 0, + 1, 0, 1, 0, 0, 0, + 0, 0, 1, 1, 1, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 4 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 1, 1, 1, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 5 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 1, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 6 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 0, 0, 0, + 0, 0, 1, 1, 1, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 7 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, + 1, 0, 0, 1, 0, 0, + 1, 0, 0, 1, 0, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 8 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 9 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 0, 0, 1, 0, + 1, 0, 1, 0, 1, 0, + 1, 0, 0, 1, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, + + /* Char 10 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 11 */ + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 1, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 12 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + + /* Char 13 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, 1, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + + /* Char 14 */ + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 15 */ + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 1, 1, 1, 1, 1, 1, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + + /* Char 16 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 17 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 18 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 19 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 20 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 21 */ + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 1, 1, 1, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + + /* Char 22 */ + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 1, 1, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + + /* Char 23 */ + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 24 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + + /* Char 25 */ + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + + /* Char 26 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 27 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 28 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 1, 0, 1, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 1, 0, 1, 0, 0, + 1, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 29 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 1, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 30 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, + 0, 1, 0, 0, 1, 0, + 0, 1, 0, 0, 0, 0, + 1, 1, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 1, 0, + 1, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 31 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 32 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 33 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 34 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 35 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 1, 0, 1, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 1, 0, 1, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 1, 0, 1, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 36 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 1, 1, 1, 0, + 1, 0, 1, 0, 0, 0, + 1, 0, 1, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 1, 0, 1, 0, + 0, 0, 1, 0, 1, 0, + 1, 1, 1, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 37 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 1, 0, + 1, 0, 1, 0, 1, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 1, 0, 1, 0, 1, 0, + 1, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 38 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 1, 0, 1, 0, 0, 0, + 1, 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 1, 0, 1, 0, 0, 0, + 1, 0, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 0, + 0, 1, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 39 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 40 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 41 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 42 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 1, 0, 1, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 43 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 44 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 45 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 46 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, + 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 47 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 48 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 49 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 1, 0, 0, 0, + 1, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 50 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 51 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 52 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 1, 1, 0, 0, + 0, 1, 0, 1, 0, 0, + 1, 0, 0, 1, 0, 0, + 1, 0, 0, 1, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 53 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 54 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, 0, + 0, 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 55 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 56 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 57 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, 0, + 1, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 58 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, + 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, + 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 59 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, + 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 60 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 61 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 62 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 63 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 64 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 1, 1, 0, + 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, + 1, 0, 1, 1, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 65 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 66 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 67 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 68 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 69 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 70 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 71 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 1, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 72 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 73 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 74 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 1, 0, 0, 1, 0, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 75 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 1, 0, 0, + 1, 0, 1, 0, 0, 0, + 1, 1, 1, 0, 0, 0, + 1, 0, 0, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 76 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 77 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 0, 1, 1, 0, + 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 78 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 0, 0, 1, 0, + 1, 1, 0, 0, 1, 0, + 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, + 1, 0, 0, 1, 1, 0, + 1, 0, 0, 1, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 79 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 80 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 81 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 1, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 82 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 1, 1, 0, 0, + 1, 0, 1, 0, 0, 0, + 1, 0, 0, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 83 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 84 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 85 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 86 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 0, 1, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 87 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, + 1, 1, 0, 1, 1, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 88 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 89 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 0, 1, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 90 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 91 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 92 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 93 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 94 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 95 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 96 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 97 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 98 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 1, 1, 0, 0, + 1, 1, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 0, 0, 1, 0, + 1, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 99 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 100 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 1, 0, + 0, 1, 1, 0, 1, 0, + 1, 0, 0, 1, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 101 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 102 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, + 0, 1, 0, 0, 1, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 103 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + + /* Char 104 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 1, 1, 0, 0, + 1, 1, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 105 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 106 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 1, 0, 0, 1, 0, 0, + 1, 0, 0, 1, 0, 0, + 0, 1, 1, 0, 0, 0, + + /* Char 107 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 1, 0, 0, + 1, 0, 1, 0, 0, 0, + 1, 1, 0, 0, 0, 0, + 1, 0, 1, 0, 0, 0, + 1, 0, 0, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 108 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 109 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 0, 1, 0, 0, + 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 110 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 1, 1, 0, 0, + 1, 1, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 111 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 112 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 1, 1, 0, 0, + 1, 1, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 0, 0, 1, 0, + 1, 0, 1, 1, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + + /* Char 113 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 1, 0, + 1, 0, 0, 1, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 1, 0, + + /* Char 114 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 1, 1, 0, 0, + 1, 1, 0, 0, 1, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 115 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 116 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 1, 0, + 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 117 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 118 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 0, 1, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 119 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 120 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 121 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, 0, + 1, 1, 1, 0, 0, 0, + + /* Char 122 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 123 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 1, 1, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 124 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 125 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 1, 1, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 126 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 1, 0, + 1, 0, 1, 0, 1, 0, + 1, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 127 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 128 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 129 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 130 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 131 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 132 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 133 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 134 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 135 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 136 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 137 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 138 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 139 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 140 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 141 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 142 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 143 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 144 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 145 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 146 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 147 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 148 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 149 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 150 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 151 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 152 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 153 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 154 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 155 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 156 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 157 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 158 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 159 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 160 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 161 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 1, 1, + + /* Char 162 */ + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 163 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 1, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 164 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 165 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, 0, + 1, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 166 */ + 0, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 167 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, + 0, 1, 0, 0, 1, 0, + 0, 1, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, + 0, 1, 0, 0, 1, 0, + 0, 1, 0, 0, 1, 0, + 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 1, 0, 0, 1, 0, + 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 168 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 169 */ + 0, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 170 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + + /* Char 171 */ + 0, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 172 */ + 0, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 173 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 174 */ + 0, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 175 */ + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 176 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, + 0, 1, 0, 0, 1, 0, + 0, 1, 0, 0, 1, 0, + 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 177 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 1, 1, + + /* Char 178 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 1, 1, 0, + + /* Char 179 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 180 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 181 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, + 0, 1, 1, 0, 0, 1, + 0, 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 182 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 183 */ + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 184 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 1, 1, 0, 0, 0, + + /* Char 185 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 186 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + + /* Char 187 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 1, 0, + 0, 1, 0, 1, 0, 0, + 0, 1, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 1, 0, + 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 188 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 189 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 1, + 0, 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 190 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 191 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 192 */ + 0, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 1, 1, 0, 0, + 1, 0, 1, 0, 0, 0, + 1, 0, 0, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 193 */ + 0, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 194 */ + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 195 */ + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 196 */ + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 197 */ + 0, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 198 */ + 0, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 199 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 1, 1, 0, 0, 0, + + /* Char 200 */ + 0, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 201 */ + 0, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 202 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 1, 1, 0, + + /* Char 203 */ + 0, 1, 0, 1, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 204 */ + 0, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 205 */ + 0, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 206 */ + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 207 */ + 0, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 208 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, + 0, 1, 0, 0, 1, 0, + 0, 1, 0, 0, 1, 0, + 1, 1, 1, 0, 1, 0, + 0, 1, 0, 0, 1, 0, + 0, 1, 0, 0, 1, 0, + 0, 1, 0, 0, 1, 0, + 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 209 */ + 0, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 0, 0, 1, 0, + 1, 1, 0, 0, 1, 0, + 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, + 1, 0, 0, 1, 1, 0, + 1, 0, 0, 1, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 210 */ + 0, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 0, 0, 1, 0, + 1, 1, 0, 0, 1, 0, + 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, + 1, 0, 0, 1, 1, 0, + 1, 0, 0, 1, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 211 */ + 0, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 212 */ + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 213 */ + 0, 0, 1, 0, 0, 1, + 0, 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 214 */ + 0, 1, 0, 1, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 215 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 216 */ + 0, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 1, 1, 0, 0, + 1, 0, 1, 0, 0, 0, + 1, 0, 0, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 217 */ + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 218 */ + 0, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 219 */ + 0, 0, 1, 0, 0, 1, + 0, 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 220 */ + 0, 1, 0, 1, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 221 */ + 0, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 0, 1, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 222 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + + /* Char 223 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 0, 0, 1, 0, + 1, 0, 1, 1, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 224 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 1, 1, 0, 0, + 1, 1, 0, 0, 1, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 225 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 226 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 227 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 228 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 1, 0, + 0, 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 229 */ + 0, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 230 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 231 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 1, 1, 0, 0, 0, + + /* Char 232 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 233 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 234 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 1, 1, 0, + + /* Char 235 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 236 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 237 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 238 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 239 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 1, + 0, 0, 0, 1, 1, 0, + 0, 0, 0, 1, 0, 0, + 0, 1, 0, 1, 0, 0, + 1, 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, 0, + 1, 0, 0, 1, 0, 0, + 1, 0, 0, 1, 0, 0, + 0, 1, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 240 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 1, 1, 1, + 0, 0, 0, 0, 1, 0, + 0, 1, 1, 0, 1, 0, + 1, 0, 0, 1, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 241 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 1, 1, 0, 0, + 1, 1, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 242 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 1, 1, 0, 0, + 1, 1, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 243 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 244 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 245 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 246 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 247 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 248 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 1, 1, 0, 0, + 1, 1, 0, 0, 1, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 249 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 250 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 251 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 252 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 1, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + /* Char 253 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, + 1, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, 0, + 1, 1, 1, 0, 0, 0, + + /* Char 254 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 1, 0, + 0, 0, 1, 1, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, + + /* Char 255 */ + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + + +}; + +gdFont gdFontSmallRep = { + 256, + 0, + 6, + 13, + gdFontSmallData +}; + +BGD_EXPORT_DATA_PROT gdFontPtr gdFontSmall = &gdFontSmallRep; + +/** + * Function: gdFontGetSmall + * + * Returns the built-in small font. + */ +BGD_DECLARE(gdFontPtr) +gdFontGetSmall (void) +{ + return gdFontSmall; +} + +/* This file has not been truncated. */ diff --git a/libmscgen/gdfonts.h b/libmscgen/gdfonts.h new file mode 100644 index 0000000..b5127e9 --- /dev/null +++ b/libmscgen/gdfonts.h @@ -0,0 +1,27 @@ +#ifndef _GDFONTS_H_ +#define _GDFONTS_H_ 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + This is a header file for gd font, generated using + bdftogd version 0.5 by Jan Pazdziora, adelton@fi.muni.cz + from bdf font + -misc-fixed-medium-r-semicondensed-sans-12-116-75-75-c-60-iso8859-2 + at Thu Jan 8 14:13:20 1998. + No copyright info was found in the original bdf. + */ + +#include "gd.h" + +extern BGD_EXPORT_DATA_PROT gdFontPtr gdFontSmall; +BGD_DECLARE(gdFontPtr) gdFontGetSmall(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmscgen/gdfontt.c b/libmscgen/gdfontt.c new file mode 100644 index 0000000..e7bb345 --- /dev/null +++ b/libmscgen/gdfontt.c @@ -0,0 +1,2613 @@ + + +/* + This is a header file for gd font, generated using + bdftogd version 0.5 by Jan Pazdziora, adelton@fi.muni.cz + from bdf font + -Misc-Fixed-Medium-R-Normal--8-80-75-75-C-50-ISO8859-2 + at Thu Jan 8 13:49:54 1998. + The original bdf was holding following copyright: + "Libor Skarvada, libor@informatics.muni.cz" + */ + +/** + * File: Tiny Font + * + * A very small ISO-8859-2 raster font (5x8 pixels). + * + * The font is supposed to be used with <gdImageChar> and <gdImageString> + * and their variants. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gdfontt.h" + +char gdFontTinyData[] = { + /* Char 0 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 1 */ + 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 1, 1, 1, 0, + 1, 1, 1, 1, 1, + 0, 1, 1, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 2 */ + 0, 1, 0, 1, 0, + 1, 0, 1, 0, 0, + 0, 1, 0, 1, 0, + 1, 0, 1, 0, 0, + 0, 1, 0, 1, 0, + 1, 0, 1, 0, 0, + 0, 1, 0, 1, 0, + 1, 0, 1, 0, 0, + + /* Char 3 */ + 0, 1, 0, 1, 0, + 0, 1, 0, 1, 0, + 0, 1, 1, 1, 0, + 0, 1, 0, 1, 0, + 0, 1, 0, 1, 0, + 0, 0, 1, 1, 1, + 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, + + /* Char 4 */ + 1, 1, 1, 0, 0, + 1, 0, 0, 0, 0, + 1, 1, 0, 0, 0, + 1, 0, 1, 1, 1, + 1, 0, 1, 0, 0, + 0, 0, 1, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + + /* Char 5 */ + 0, 1, 1, 0, 0, + 1, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, + 0, 0, 1, 0, 1, + 0, 0, 1, 1, 0, + 0, 0, 1, 0, 1, + + /* Char 6 */ + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 1, 1, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 0, 0, + 0, 0, 1, 1, 0, + 0, 0, 1, 0, 0, + + /* Char 7 */ + 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, + 1, 0, 1, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 8 */ + 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 9 */ + 1, 0, 0, 1, 0, + 1, 1, 0, 1, 0, + 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 1, 1, + + /* Char 10 */ + 1, 0, 1, 0, 0, + 1, 0, 1, 0, 0, + 1, 0, 1, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, + + /* Char 11 */ + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 12 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 1, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + + /* Char 13 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + + /* Char 14 */ + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 15 */ + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 1, 1, 1, 1, 1, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + + /* Char 16 */ + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 17 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 18 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 19 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 20 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 21 */ + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + + /* Char 22 */ + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 1, 1, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + + /* Char 23 */ + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 24 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + + /* Char 25 */ + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + + /* Char 26 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 27 */ + 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 28 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, + 0, 1, 0, 1, 0, + 0, 1, 0, 1, 0, + 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 29 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, + 1, 1, 1, 1, 1, + 0, 0, 1, 0, 0, + 1, 1, 1, 1, 1, + 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 30 */ + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, + 0, 1, 0, 0, 1, + 1, 1, 1, 0, 0, + 0, 1, 0, 0, 0, + 0, 1, 0, 0, 1, + 1, 0, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 31 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 32 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 33 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 34 */ + 0, 0, 0, 0, 0, + 0, 1, 0, 1, 0, + 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 35 */ + 0, 1, 0, 1, 0, + 0, 1, 0, 1, 0, + 1, 1, 1, 1, 1, + 0, 1, 0, 1, 0, + 1, 1, 1, 1, 1, + 0, 1, 0, 1, 0, + 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 36 */ + 0, 0, 1, 0, 0, + 0, 1, 1, 1, 0, + 1, 0, 1, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 1, 0, 1, + 0, 1, 1, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 37 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 1, 0, 0, 1, + 1, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 1, 1, + 1, 0, 0, 1, 1, + 0, 0, 0, 0, 0, + + /* Char 38 */ + 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 1, 0, + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 1, + 0, 0, 0, 0, 0, + + /* Char 39 */ + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 40 */ + 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 41 */ + 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 42 */ + 0, 0, 0, 0, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 1, 1, 1, 1, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 43 */ + 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 1, 1, 1, 1, 1, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 44 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 45 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 46 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 47 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, + 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 48 */ + 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 1, 0, + 0, 1, 0, 1, 0, + 0, 1, 0, 1, 0, + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 49 */ + 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 1, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 50 */ + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 51 */ + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 52 */ + 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 1, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 53 */ + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, + 1, 1, 1, 0, 0, + 0, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 54 */ + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 1, 0, 0, + 1, 1, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 55 */ + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 56 */ + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 57 */ + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 1, 1, 0, + 0, 1, 0, 1, 0, + 0, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 58 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 59 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, + 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, + + /* Char 60 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 61 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 62 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 63 */ + 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 1, 0, + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 64 */ + 0, 0, 1, 1, 0, + 0, 1, 0, 0, 1, + 1, 0, 0, 1, 1, + 1, 0, 1, 0, 1, + 1, 0, 1, 0, 1, + 1, 0, 0, 1, 0, + 0, 1, 0, 0, 0, + 0, 0, 1, 1, 0, + + /* Char 65 */ + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 1, 1, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 66 */ + 0, 0, 0, 0, 0, + 1, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 67 */ + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 68 */ + 0, 0, 0, 0, 0, + 1, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 69 */ + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, + 1, 1, 1, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 70 */ + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, + 1, 1, 1, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 71 */ + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 0, 0, + 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 72 */ + 0, 0, 0, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 1, 1, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 73 */ + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 74 */ + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, + 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 75 */ + 0, 0, 0, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 1, 0, 0, + 1, 1, 0, 0, 0, + 1, 0, 1, 0, 0, + 1, 0, 1, 0, 0, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 76 */ + 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 77 */ + 0, 0, 0, 0, 0, + 1, 0, 0, 1, 0, + 1, 1, 1, 1, 0, + 1, 1, 1, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 78 */ + 0, 0, 0, 0, 0, + 1, 0, 0, 1, 0, + 1, 1, 0, 1, 0, + 1, 1, 1, 1, 0, + 1, 0, 1, 1, 0, + 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 79 */ + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 80 */ + 0, 0, 0, 0, 0, + 1, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 1, 1, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 81 */ + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 1, 0, 1, 0, + 1, 0, 1, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 1, 0, + + /* Char 82 */ + 0, 0, 0, 0, 0, + 1, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 1, 1, 0, 0, + 1, 0, 1, 0, 0, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 83 */ + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 1, 0, + 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 84 */ + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 85 */ + 0, 0, 0, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 86 */ + 0, 0, 0, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 87 */ + 0, 0, 0, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 1, 1, 1, 0, + 1, 1, 1, 1, 0, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 88 */ + 0, 0, 0, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 89 */ + 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, + 1, 0, 0, 0, 1, + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 90 */ + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 91 */ + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 92 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, + 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, + + /* Char 93 */ + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 94 */ + 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 95 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, + + /* Char 96 */ + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 97 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 1, 1, 0, + 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 98 */ + 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 99 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 100 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 1, 1, 0, + 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 101 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 1, 1, 0, + 1, 1, 0, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 102 */ + 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 1, 0, + 0, 1, 0, 0, 0, + 1, 1, 1, 0, 0, + 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 103 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + + /* Char 104 */ + 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 105 */ + 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 106 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + + /* Char 107 */ + 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 1, 0, + 1, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 108 */ + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 109 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 1, 0, 1, 0, + 1, 0, 1, 0, 1, + 1, 0, 1, 0, 1, + 1, 0, 0, 0, 1, + 0, 0, 0, 0, 0, + + /* Char 110 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 0, 1, 0, 0, + 1, 1, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 111 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 112 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 1, 1, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + + /* Char 113 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 1, 0, + 0, 0, 0, 1, 0, + + /* Char 114 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 0, 1, 0, 0, + 1, 1, 0, 1, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 115 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 1, 1, 0, 0, 0, + 0, 0, 1, 1, 0, + 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 116 */ + 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, + 1, 1, 1, 0, 0, + 0, 1, 0, 0, 0, + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 117 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 1, 1, 0, + 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 118 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 0, 1, 0, + 0, 1, 0, 1, 0, + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 119 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, + 1, 0, 1, 0, 1, + 1, 0, 1, 0, 1, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 120 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 121 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + + /* Char 122 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 123 */ + 0, 0, 1, 1, 0, + 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, + 1, 1, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 124 */ + 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 125 */ + 0, 1, 1, 0, 0, + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 1, 1, + 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 126 */ + 0, 0, 0, 0, 0, + 0, 1, 0, 1, 0, + 1, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 127 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 128 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 129 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 130 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 131 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 132 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 133 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 134 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 135 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 136 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 137 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 138 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 139 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 140 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 141 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 142 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 143 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 144 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 145 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 146 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 147 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 148 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 149 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 150 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 151 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 152 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 153 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 154 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 155 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 156 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 157 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 158 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 159 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 160 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 161 */ + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 1, 1, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 1, 1, 0, + 0, 0, 0, 1, 1, + + /* Char 162 */ + 1, 0, 0, 0, 1, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 163 */ + 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 1, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 1, 0, 0, 0, + 1, 1, 0, 0, 0, + 0, 1, 1, 1, 1, + 0, 0, 0, 0, 0, + + /* Char 164 */ + 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, + 0, 1, 1, 1, 0, + 0, 1, 0, 1, 0, + 0, 1, 1, 1, 0, + 1, 0, 0, 0, 1, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 165 */ + 0, 0, 1, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 1, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 166 */ + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 1, 1, 0, + 1, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 1, 0, + 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 167 */ + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, + 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + + /* Char 168 */ + 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 169 */ + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 1, 1, 0, + 1, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 1, 0, + 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 170 */ + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 1, 0, + 1, 1, 1, 0, 0, + 0, 1, 0, 0, 0, + + /* Char 171 */ + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + 1, 1, 1, 1, 1, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 172 */ + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 173 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 174 */ + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 175 */ + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 176 */ + 0, 0, 1, 0, 0, + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 177 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 1, 1, 0, + 0, 1, 0, 1, 0, + 0, 0, 0, 1, 1, + + /* Char 178 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 1, 1, + + /* Char 179 */ + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 0, 0, 1, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 180 */ + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 181 */ + 0, 0, 0, 1, 1, + 1, 1, 0, 0, 1, + 0, 1, 0, 1, 0, + 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, + 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 182 */ + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 1, 1, 0, 0, 0, + 0, 0, 1, 1, 0, + 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 183 */ + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 184 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + + /* Char 185 */ + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 1, 1, 0, 0, 0, + 0, 0, 1, 1, 0, + 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 186 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 1, 1, 0, 0, 0, + 0, 0, 1, 1, 0, + 1, 1, 1, 0, 0, + 0, 1, 0, 0, 0, + + /* Char 187 */ + 0, 0, 0, 1, 1, + 0, 1, 0, 0, 1, + 0, 1, 0, 1, 0, + 1, 1, 1, 0, 0, + 0, 1, 0, 0, 0, + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 188 */ + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 189 */ + 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 190 */ + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 191 */ + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 192 */ + 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, + 1, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 1, 1, 0, 0, + 1, 0, 1, 0, 0, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 193 */ + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 1, 1, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 194 */ + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 1, 1, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 195 */ + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 1, 1, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 196 */ + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 1, 1, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 197 */ + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 198 */ + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 199 */ + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 1, 1, 0, 0, 0, + + /* Char 200 */ + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 201 */ + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, + 1, 1, 1, 0, 0, + 1, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 202 */ + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, + 1, 1, 1, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 0, 1, 1, + + /* Char 203 */ + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, + 1, 1, 1, 0, 0, + 1, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 204 */ + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, + 1, 1, 1, 0, 0, + 1, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 205 */ + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 206 */ + 0, 0, 1, 0, 0, + 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 207 */ + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + 1, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 208 */ + 0, 0, 0, 0, 0, + 1, 1, 1, 0, 0, + 0, 1, 0, 1, 0, + 1, 1, 0, 1, 0, + 0, 1, 0, 1, 0, + 0, 1, 0, 1, 0, + 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 209 */ + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 1, 0, 1, 0, + 1, 1, 1, 1, 0, + 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 210 */ + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 1, 0, 1, 0, + 1, 1, 1, 1, 0, + 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 211 */ + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 212 */ + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 213 */ + 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 214 */ + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 215 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 216 */ + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + 1, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 1, 1, 0, 0, + 1, 0, 1, 0, 0, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 217 */ + 0, 1, 1, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 218 */ + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 219 */ + 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 220 */ + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 221 */ + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 1, 0, 0, 0, 1, + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 222 */ + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, + + /* Char 223 */ + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 1, 0, 1, 0, + 1, 0, 1, 0, 0, + 1, 0, 0, 0, 0, + + /* Char 224 */ + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 1, 0, 1, 0, 0, + 1, 1, 0, 1, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 225 */ + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 1, 1, 0, + 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 226 */ + 0, 0, 1, 0, 0, + 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 1, 1, 0, + 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 227 */ + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 1, 1, 0, + 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 228 */ + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 1, 1, 0, + 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 229 */ + 0, 0, 0, 0, 1, + 0, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 230 */ + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 231 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 1, 1, 1, 0, 0, + + /* Char 232 */ + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 233 */ + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 1, 1, 0, + 1, 1, 0, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 234 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 1, 1, 0, + 1, 1, 0, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 1, 1, + + /* Char 235 */ + 0, 0, 0, 0, 0, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 1, 1, 0, + 1, 1, 0, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 236 */ + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 1, 1, 0, + 1, 1, 0, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 237 */ + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 238 */ + 0, 0, 1, 0, 0, + 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 239 */ + 0, 0, 0, 1, 1, + 0, 0, 1, 0, 1, + 0, 0, 1, 0, 1, + 0, 1, 1, 0, 0, + 1, 0, 1, 0, 0, + 1, 0, 1, 0, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 240 */ + 0, 0, 0, 1, 0, + 0, 0, 1, 1, 1, + 0, 0, 0, 1, 0, + 0, 1, 1, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 1, 1, 0, + 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 241 */ + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 1, 0, 1, 0, 0, + 1, 1, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 242 */ + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 1, 0, 1, 0, 0, + 1, 1, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 243 */ + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 244 */ + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 245 */ + 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 246 */ + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 247 */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 248 */ + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 1, 0, 1, 0, 0, + 1, 1, 0, 1, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + /* Char 249 */ + 0, 1, 1, 0, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 1, 1, 0, + 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 250 */ + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 1, 1, 0, + 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 251 */ + 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 1, 1, 0, + 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 252 */ + 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 1, 1, 0, + 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, + + /* Char 253 */ + 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + + /* Char 254 */ + 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, + 1, 1, 1, 0, 0, + 0, 1, 0, 0, 0, + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 1, 0, 0, + + /* Char 255 */ + 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + +}; + +gdFont gdFontTinyRep = { + 256, + 0, + 5, + 8, + gdFontTinyData +}; + +BGD_EXPORT_DATA_PROT gdFontPtr gdFontTiny = &gdFontTinyRep; + +/** + * Function: gdFontGetTiny + * + * Returns the built-in tiny font. + */ +BGD_DECLARE(gdFontPtr) +gdFontGetTiny (void) +{ + return gdFontTiny; +} + +/* This file has not been truncated. */ diff --git a/libmscgen/gdfontt.h b/libmscgen/gdfontt.h new file mode 100644 index 0000000..d61b01f --- /dev/null +++ b/libmscgen/gdfontt.h @@ -0,0 +1,28 @@ +#ifndef _GDFONTT_H_ +#define _GDFONTT_H_ 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + This is a header file for gd font, generated using + bdftogd version 0.5 by Jan Pazdziora, adelton@fi.muni.cz + from bdf font + -Misc-Fixed-Medium-R-Normal--8-80-75-75-C-50-ISO8859-2 + at Thu Jan 8 13:49:54 1998. + The original bdf was holding following copyright: + "Libor Skarvada, libor@informatics.muni.cz" + */ + +#include "gd.h" + +extern BGD_EXPORT_DATA_PROT gdFontPtr gdFontTiny; +BGD_DECLARE(gdFontPtr) gdFontGetTiny(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmscgen/gdhelpers.c b/libmscgen/gdhelpers.c new file mode 100644 index 0000000..20fff5c --- /dev/null +++ b/libmscgen/gdhelpers.c @@ -0,0 +1,118 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gd.h" +#include "gdhelpers.h" +#include <stdlib.h> +#include <string.h> + +#include <sys/types.h> +#include <ctype.h> + +/* TBB: gd_strtok_r is not portable; provide an implementation */ + +#define SEP_TEST (separators[*((unsigned char *) s)]) + +char * +gd_strtok_r (char *s, char *sep, char **state) +{ + char separators[256]; + char *result = 0; + memset (separators, 0, sizeof (separators)); + while (*sep) { + separators[*((unsigned char *) sep)] = 1; + sep++; + } + if (!s) { + /* Pick up where we left off */ + s = *state; + } + /* 1. EOS */ + if (!(*s)) { + *state = s; + return 0; + } + /* 2. Leading separators, if any */ + if (SEP_TEST) { + do { + s++; + } while (SEP_TEST); + /* 2a. EOS after separators only */ + if (!(*s)) { + *state = s; + return 0; + } + } + /* 3. A token */ + result = s; + do { + /* 3a. Token at end of string */ + if (!(*s)) { + *state = s; + return result; + } + s++; + } while (!SEP_TEST); + /* 4. Terminate token and skip trailing separators */ + *s = '\0'; + do { + s++; + } while (SEP_TEST); + /* 5. Return token */ + *state = s; + return result; +} + +void * gdCalloc (size_t nmemb, size_t size) +{ + return calloc (nmemb, size); +} + +void * +gdMalloc (size_t size) +{ + return malloc (size); +} + +void * +gdRealloc (void *ptr, size_t size) +{ + return realloc (ptr, size); +} + +void * +gdReallocEx (void *ptr, size_t size) +{ + void *newPtr = gdRealloc (ptr, size); + if (!newPtr && ptr) + gdFree(ptr); + return newPtr; +} + +/* + Function: gdFree + + Frees memory that has been allocated by libgd functions. + + Unless more specialized functions exists (for instance, <gdImageDestroy>), + all memory that has been allocated by public libgd functions has to be + freed by calling <gdFree>, and not by free(3), because libgd internally + doesn't use alloc(3) and friends but rather its own allocation functions, + which are, however, not publicly available. + + Parameters: + + ptr - Pointer to the memory space to free. If it is NULL, no operation is + performed. + + Returns: + + Nothing. +*/ +BGD_DECLARE(void) gdFree (void *ptr) +{ + free (ptr); +} + + diff --git a/libmscgen/gdhelpers.h b/libmscgen/gdhelpers.h new file mode 100644 index 0000000..2a96b8b --- /dev/null +++ b/libmscgen/gdhelpers.h @@ -0,0 +1,76 @@ +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef GDHELPERS_H +#define GDHELPERS_H 1 + + /* sys/types.h is needed for size_t on Sparc-SunOS-4.1 */ +#ifndef _WIN32_WCE +#include <sys/types.h> +#else +#include <stdlib.h> +#endif /* _WIN32_WCE */ + + /* TBB: strtok_r is not universal; provide an implementation of it. */ + + char * gd_strtok_r (char *s, char *sep, char **state); + + /* These functions wrap memory management. gdFree is + in gd.h, where callers can utilize it to correctly + free memory allocated by these functions with the + right version of free(). */ + void *gdCalloc (size_t nmemb, size_t size); + void *gdMalloc (size_t size); + void *gdRealloc (void *ptr, size_t size); + /* The extended version of gdReallocEx will free *ptr if the + * realloc fails */ + void *gdReallocEx (void *ptr, size_t size); + + /* Returns nonzero if multiplying the two quantities will + result in integer overflow. Also returns nonzero if + either quantity is negative. By Phil Knirsch based on + netpbm fixes by Alan Cox. */ + + int overflow2(int a, int b); + + /* 2.0.16: portable mutex support for thread safety. */ +#if defined(CPP_SHARP) +# define gdMutexDeclare(x) +# define gdMutexSetup(x) +# define gdMutexShutdown(x) +# define gdMutexLock(x) +# define gdMutexUnlock(x) +#elif defined(_WIN32) + /* 2.0.18: must include windows.h to get CRITICAL_SECTION. */ +# include <windows.h> +# define gdMutexDeclare(x) CRITICAL_SECTION x +# define gdMutexSetup(x) InitializeCriticalSection(&x) +# define gdMutexShutdown(x) DeleteCriticalSection(&x) +# define gdMutexLock(x) EnterCriticalSection(&x) +# define gdMutexUnlock(x) LeaveCriticalSection(&x) +#elif defined(HAVE_PTHREAD) +# include <pthread.h> +# define gdMutexDeclare(x) pthread_mutex_t x +# define gdMutexSetup(x) pthread_mutex_init(&x, 0) +# define gdMutexShutdown(x) pthread_mutex_destroy(&x) +# define gdMutexLock(x) pthread_mutex_lock(&x) +# define gdMutexUnlock(x) pthread_mutex_unlock(&x) +#else +# define gdMutexDeclare(x) +# define gdMutexSetup(x) +# define gdMutexShutdown(x) +# define gdMutexLock(x) +# define gdMutexUnlock(x) +#endif /* _WIN32 || HAVE_PTHREAD */ + +#define DPCM2DPI(dpcm) (unsigned int)((dpcm)*2.54 + 0.5) +#define DPM2DPI(dpm) (unsigned int)((dpm)*0.0254 + 0.5) +#define DPI2DPCM(dpi) (unsigned int)((dpi)/2.54 + 0.5) +#define DPI2DPM(dpi) (unsigned int)((dpi)/0.0254 + 0.5) + +#endif /* GDHELPERS_H */ + +#ifdef __cplusplus +} +#endif diff --git a/libmscgen/gdtables.c b/libmscgen/gdtables.c new file mode 100644 index 0000000..7753b21 --- /dev/null +++ b/libmscgen/gdtables.c @@ -0,0 +1,726 @@ + +const int gdCosT[] = { + 1024, + 1023, + 1023, + 1022, + 1021, + 1020, + 1018, + 1016, + 1014, + 1011, + 1008, + 1005, + 1001, + 997, + 993, + 989, + 984, + 979, + 973, + 968, + 962, + 955, + 949, + 942, + 935, + 928, + 920, + 912, + 904, + 895, + 886, + 877, + 868, + 858, + 848, + 838, + 828, + 817, + 806, + 795, + 784, + 772, + 760, + 748, + 736, + 724, + 711, + 698, + 685, + 671, + 658, + 644, + 630, + 616, + 601, + 587, + 572, + 557, + 542, + 527, + 512, + 496, + 480, + 464, + 448, + 432, + 416, + 400, + 383, + 366, + 350, + 333, + 316, + 299, + 282, + 265, + 247, + 230, + 212, + 195, + 177, + 160, + 142, + 124, + 107, + 89, + 71, + 53, + 35, + 17, + 0, + -17, + -35, + -53, + -71, + -89, + -107, + -124, + -142, + -160, + -177, + -195, + -212, + -230, + -247, + -265, + -282, + -299, + -316, + -333, + -350, + -366, + -383, + -400, + -416, + -432, + -448, + -464, + -480, + -496, + -512, + -527, + -542, + -557, + -572, + -587, + -601, + -616, + -630, + -644, + -658, + -671, + -685, + -698, + -711, + -724, + -736, + -748, + -760, + -772, + -784, + -795, + -806, + -817, + -828, + -838, + -848, + -858, + -868, + -877, + -886, + -895, + -904, + -912, + -920, + -928, + -935, + -942, + -949, + -955, + -962, + -968, + -973, + -979, + -984, + -989, + -993, + -997, + -1001, + -1005, + -1008, + -1011, + -1014, + -1016, + -1018, + -1020, + -1021, + -1022, + -1023, + -1023, + -1024, + -1023, + -1023, + -1022, + -1021, + -1020, + -1018, + -1016, + -1014, + -1011, + -1008, + -1005, + -1001, + -997, + -993, + -989, + -984, + -979, + -973, + -968, + -962, + -955, + -949, + -942, + -935, + -928, + -920, + -912, + -904, + -895, + -886, + -877, + -868, + -858, + -848, + -838, + -828, + -817, + -806, + -795, + -784, + -772, + -760, + -748, + -736, + -724, + -711, + -698, + -685, + -671, + -658, + -644, + -630, + -616, + -601, + -587, + -572, + -557, + -542, + -527, + -512, + -496, + -480, + -464, + -448, + -432, + -416, + -400, + -383, + -366, + -350, + -333, + -316, + -299, + -282, + -265, + -247, + -230, + -212, + -195, + -177, + -160, + -142, + -124, + -107, + -89, + -71, + -53, + -35, + -17, + 0, + 17, + 35, + 53, + 71, + 89, + 107, + 124, + 142, + 160, + 177, + 195, + 212, + 230, + 247, + 265, + 282, + 299, + 316, + 333, + 350, + 366, + 383, + 400, + 416, + 432, + 448, + 464, + 480, + 496, + 512, + 527, + 542, + 557, + 572, + 587, + 601, + 616, + 630, + 644, + 658, + 671, + 685, + 698, + 711, + 724, + 736, + 748, + 760, + 772, + 784, + 795, + 806, + 817, + 828, + 838, + 848, + 858, + 868, + 877, + 886, + 895, + 904, + 912, + 920, + 928, + 935, + 942, + 949, + 955, + 962, + 968, + 973, + 979, + 984, + 989, + 993, + 997, + 1001, + 1005, + 1008, + 1011, + 1014, + 1016, + 1018, + 1020, + 1021, + 1022, + 1023, + 1023 +}; + +const int gdSinT[] = { + 0, + 17, + 35, + 53, + 71, + 89, + 107, + 124, + 142, + 160, + 177, + 195, + 212, + 230, + 247, + 265, + 282, + 299, + 316, + 333, + 350, + 366, + 383, + 400, + 416, + 432, + 448, + 464, + 480, + 496, + 512, + 527, + 542, + 557, + 572, + 587, + 601, + 616, + 630, + 644, + 658, + 671, + 685, + 698, + 711, + 724, + 736, + 748, + 760, + 772, + 784, + 795, + 806, + 817, + 828, + 838, + 848, + 858, + 868, + 877, + 886, + 895, + 904, + 912, + 920, + 928, + 935, + 942, + 949, + 955, + 962, + 968, + 973, + 979, + 984, + 989, + 993, + 997, + 1001, + 1005, + 1008, + 1011, + 1014, + 1016, + 1018, + 1020, + 1021, + 1022, + 1023, + 1023, + 1024, + 1023, + 1023, + 1022, + 1021, + 1020, + 1018, + 1016, + 1014, + 1011, + 1008, + 1005, + 1001, + 997, + 993, + 989, + 984, + 979, + 973, + 968, + 962, + 955, + 949, + 942, + 935, + 928, + 920, + 912, + 904, + 895, + 886, + 877, + 868, + 858, + 848, + 838, + 828, + 817, + 806, + 795, + 784, + 772, + 760, + 748, + 736, + 724, + 711, + 698, + 685, + 671, + 658, + 644, + 630, + 616, + 601, + 587, + 572, + 557, + 542, + 527, + 512, + 496, + 480, + 464, + 448, + 432, + 416, + 400, + 383, + 366, + 350, + 333, + 316, + 299, + 282, + 265, + 247, + 230, + 212, + 195, + 177, + 160, + 142, + 124, + 107, + 89, + 71, + 53, + 35, + 17, + 0, + -17, + -35, + -53, + -71, + -89, + -107, + -124, + -142, + -160, + -177, + -195, + -212, + -230, + -247, + -265, + -282, + -299, + -316, + -333, + -350, + -366, + -383, + -400, + -416, + -432, + -448, + -464, + -480, + -496, + -512, + -527, + -542, + -557, + -572, + -587, + -601, + -616, + -630, + -644, + -658, + -671, + -685, + -698, + -711, + -724, + -736, + -748, + -760, + -772, + -784, + -795, + -806, + -817, + -828, + -838, + -848, + -858, + -868, + -877, + -886, + -895, + -904, + -912, + -920, + -928, + -935, + -942, + -949, + -955, + -962, + -968, + -973, + -979, + -984, + -989, + -993, + -997, + -1001, + -1005, + -1008, + -1011, + -1014, + -1016, + -1018, + -1020, + -1021, + -1022, + -1023, + -1023, + -1024, + -1023, + -1023, + -1022, + -1021, + -1020, + -1018, + -1016, + -1014, + -1011, + -1008, + -1005, + -1001, + -997, + -993, + -989, + -984, + -979, + -973, + -968, + -962, + -955, + -949, + -942, + -935, + -928, + -920, + -912, + -904, + -895, + -886, + -877, + -868, + -858, + -848, + -838, + -828, + -817, + -806, + -795, + -784, + -772, + -760, + -748, + -736, + -724, + -711, + -698, + -685, + -671, + -658, + -644, + -630, + -616, + -601, + -587, + -572, + -557, + -542, + -527, + -512, + -496, + -480, + -464, + -448, + -432, + -416, + -400, + -383, + -366, + -350, + -333, + -316, + -299, + -282, + -265, + -247, + -230, + -212, + -195, + -177, + -160, + -142, + -124, + -107, + -89, + -71, + -53, + -35, + -17 +}; diff --git a/libmscgen/mscgen_adraw.c b/libmscgen/mscgen_adraw.c new file mode 100644 index 0000000..8e638a5 --- /dev/null +++ b/libmscgen/mscgen_adraw.c @@ -0,0 +1,140 @@ +/*************************************************************************** + * + * $Id: adraw.c 161 2010-10-26 20:17:16Z Michael.McTernan $ + * + * This file is part of mscgen, a message sequence chart renderer. + * Copyright (C) 2005 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + **************************************************************************/ + +/*************************************************************************** + * Include Files + ***************************************************************************/ + +#include "mscgen_config.h" +#include <math.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include "mscgen_adraw_int.h" + +/*************************************************************************** + * Functions + ***************************************************************************/ + +Boolean ADrawOpen(unsigned int w, + unsigned int h, + const char *file, + const char *fontName, + ADrawOutputType type, + struct ADrawTag *outContext) +{ + assert(outContext); + + switch(type) + { + case ADRAW_FMT_NULL: + return NullInit(outContext); + + case ADRAW_FMT_PNG: +#if !defined(REMOVE_PNG_OUTPUT) + return GdoInit(w, h, file, fontName, outContext); +#else + fprintf(stderr, "Built with REMOVE_PNG_OUTPUT; PNG output is not supported\n"); + return FALSE; +#endif + case ADRAW_FMT_EPS: + return PsInit(w, h, file, outContext); + + case ADRAW_FMT_SVG: + return SvgInit(w, h, file, outContext); + + default: + return FALSE; + } +} + + +ADrawColour ADrawGetColour(const char *colour) +{ + assert(colour != NULL); + + /* Check if an RGB value has been specified */ + if(*colour == '#') + { + unsigned int c = ADRAW_COL_BLACK; + + if(sscanf(&colour[1], "%x", &c) == 1) + { + return (ADrawColour)c; + } + } + else /* Check for name matches */ + { + static const struct + { + char *name; + ADrawColour col; + } + colourMap[] = + { + { "WHITE", ADRAW_COL_WHITE }, + { "BLACK", ADRAW_COL_BLACK }, + { "RED", ADRAW_COL_RED }, + { "ORANGE", ADRAW_COL_ORANGE }, + { "YELLOW", ADRAW_COL_YELLOW }, + { "GREEN", ADRAW_COL_GREEN }, + { "BLUE", ADRAW_COL_BLUE }, + { "INDIGO", ADRAW_COL_INDIGO }, + { "VIOLET", ADRAW_COL_VIOLET }, + { "SILVER", ADRAW_COL_SILVER }, + { "LIME", ADRAW_COL_LIME }, + { "GRAY", ADRAW_COL_GRAY }, + { "OLIVE", ADRAW_COL_OLIVE }, + { "MAROON", ADRAW_COL_MAROON }, + { "NAVY", ADRAW_COL_NAVY }, + { "PURPLE", ADRAW_COL_PURPLE }, + { "TEAL", ADRAW_COL_TEAL }, + { "FUCHSIA", ADRAW_COL_FUCHSIA }, + { "AQUA", ADRAW_COL_AQUA } + }; + + unsigned int t; + + for(t = 0; t < sizeof(colourMap) / sizeof(colourMap[0]); t++) + { + if(strcasecmp(colour, colourMap[t].name) == 0) + { + return colourMap[t].col; + } + } + } + + /* Default to black if all else failed */ + return ADRAW_COL_BLACK; +} + + +void ADrawComputeArcPoint(float cx, float cy, float w, float h, float degrees, + unsigned int *x, unsigned int *y) +{ + float rad = (float)((degrees * M_PI) / 180.0f); + + *x = (unsigned int)round(cx + ((w / 2.0f) * cos(rad))); + *y = (unsigned int)round(cy + ((h / 2.0f) * sin(rad))); +} + +/* END OF FILE */ diff --git a/libmscgen/mscgen_adraw.h b/libmscgen/mscgen_adraw.h new file mode 100644 index 0000000..b2e11a3 --- /dev/null +++ b/libmscgen/mscgen_adraw.h @@ -0,0 +1,300 @@ +/*************************************************************************** + * + * $Id: adraw.h 161 2010-10-26 20:17:16Z Michael.McTernan $ + * + * This file is part of mscgen, a message sequence chart renderer. + * Copyright (C) 2005 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + **************************************************************************/ + +#ifndef MSCGEN_ADRAW_H +#define MSCGEN_ADRAW_H + +#include "mscgen_bool.h" + +/*************************************************************************** + * Types + ***************************************************************************/ + +/** Output format types. + * Enumerated types for output formats. + */ +typedef enum +{ + /** Null output format. + * This allows all the graphics commands to be called, but does nothing. + */ + ADRAW_FMT_NULL = 0, + + /** Generate a PNG. */ + ADRAW_FMT_PNG, + + /** Generate Encapsulated Postscript. */ + ADRAW_FMT_EPS, + + /** Scalable Vector Graphics. */ + ADRAW_FMT_SVG +} +ADrawOutputType; + + +/** Supported colours. + * Enumerated type to describe colours. + * + * The 16 basic HTML colours at http://www.w3.org/TR/html4/types.html#h-6.5 + * are defined as well as a few other common colour names. + */ +typedef enum +{ + ADRAW_COL_WHITE = 0x00ffffff, + ADRAW_COL_BLACK = 0x00000000, + ADRAW_COL_RED = 0x00ff0000, + ADRAW_COL_ORANGE = 0x00ffb000, + ADRAW_COL_YELLOW = 0x00ffff00, + ADRAW_COL_GREEN = 0x0000ff00, + ADRAW_COL_BLUE = 0x000000ff, + ADRAW_COL_INDIGO = 0x00440088, + ADRAW_COL_VIOLET = 0x00d02090, + ADRAW_COL_SILVER = 0x00C0C0C0, + ADRAW_COL_LIME = 0x0000FF00, + ADRAW_COL_GRAY = 0x00808080, + ADRAW_COL_OLIVE = 0x00808000, + ADRAW_COL_MAROON = 0x00800000, + ADRAW_COL_NAVY = 0x00000080, + ADRAW_COL_PURPLE = 0x00800080, + ADRAW_COL_TEAL = 0x00008080, + ADRAW_COL_FUCHSIA = 0x00FF00FF, + ADRAW_COL_AQUA = 0x0000FFFF, + + ADRAW_COL_INVALID = 0xff000000, +} +ADrawColour; + + +/** Basic font sizes. + * Enumerated type for different font sizes. + */ +typedef enum +{ + ADRAW_FONT_TINY = 0, + ADRAW_FONT_SMALL +} +ADrawFontSize; + + +/** An ADraw context. + * This is the main structure used for accessing ADraw functions. + * ADrawOpen() returns an instance of this structure that can then be used + * to render to some device. Once drawing is complete, ADrawClose() should + * be called to reclaim resources and finalise any output. + * + * All the functions assume that 0,0 is in the top-left corner of the image, + * and that the dimensions grow towards w,y at the bottom-right corner. + */ +typedef struct ADrawTag +{ + /** Draw a line. + * Draw a solid straight line between two points. + * \param ctx The drawing context. + * \param x1 The first x co-ordinate, + * \param y1 The first y co-ordinate, + * \param x2 The second x co-ordinate, + * \param y2 The second y co-ordinate, + */ + void (*line) (struct ADrawTag *ctx, + unsigned int x1, + unsigned int y1, + unsigned int x2, + unsigned int y2); + + /** Draw a dotted line. + * Draw a dotted straight line between two points. + * \param ctx The drawing context. + * \param x1 The first x co-ordinate, + * \param y1 The first y co-ordinate, + * \param x2 The second x co-ordinate, + * \param y2 The second y co-ordinate, + */ + void (*dottedLine) (struct ADrawTag *ctx, + unsigned int x1, + unsigned int y1, + unsigned int x2, + unsigned int y2); + + /** Left aligned text. + * Write a single line of text that will end at some co-ordinates. + * \param ctx The drawing context. + * \param x The position at which the text should terminate. + * \param y The position above which the text will lie. + * \param string The string to write. + */ + void (*textL) (struct ADrawTag *ctx, + unsigned int x, + unsigned int y, + const char *string); + + /** Center aligned text. + * Write a single line of text that will center on some co-ordinates. + * \param ctx The drawing context. + * \param x The position at which the text should be centered. + * \param y The position above which the text will lie. + * \param string The string to write. + */ + void (*textC) (struct ADrawTag *ctx, + unsigned int x, + unsigned int y, + const char *string); + + /** Right aligned text. + * Write a single line of text that will start at some co-ordinates. + * \param ctx The drawing context. + * \param x The position at which the text should start. + * \param y The position above which the text will lie. + * \param string The string to write. + */ + void (*textR) (struct ADrawTag *ctx, + unsigned int x, + unsigned int y, + const char *string); + + /** Determine the width of some string. + * \param ctx The drawing context. + * \param string The string for which the width should be determined. + * \returns The width of the passed string as it would be rendered + * by the current drawing context. + */ + unsigned int (*textWidth) (struct ADrawTag *ctx, + const char *string); + + /** Determine the height of text in the current font. + * \param ctx The drawing context. + * + */ + int (*textHeight) (struct ADrawTag *ctx); + + void (*filledRectangle)(struct ADrawTag *ctx, + unsigned int x1, + unsigned int y1, + unsigned int x2, + unsigned int y2); + + void (*filledTriangle)(struct ADrawTag *ctx, + unsigned int x1, + unsigned int y1, + unsigned int x2, + unsigned int y2, + unsigned int x3, + unsigned int y3); + + void (*filledCircle)(struct ADrawTag *ctx, + unsigned int x, + unsigned int y, + unsigned int r); + + /** Draw an arc. + * This draws an arc centred at (cx,cy) which fits in a box of \a w by \a h. + * The arc is drawn from \a s degrees to \a e degrees. + * \note 0 degrees points east on the page and 90 degrees is south. + * + */ + void (*arc) (struct ADrawTag *ctx, + unsigned int cx, + unsigned int cy, + unsigned int w, + unsigned int h, + unsigned int s, + unsigned int e); + + void (*dottedArc) (struct ADrawTag *ctx, + unsigned int cx, + unsigned int cy, + unsigned int w, + unsigned int h, + unsigned int s, + unsigned int e); + + void (*setPen) (struct ADrawTag *ctx, + ADrawColour col); + + void (*setBgPen) (struct ADrawTag *ctx, + ADrawColour col); + + void (*setFontSize) (struct ADrawTag *ctx, + ADrawFontSize size); + + Boolean (*close) (struct ADrawTag *context); + + /* Internal context, not accessible by the user */ + void *internal; +} +ADraw; + +/*************************************************************************** + * Functions + ***************************************************************************/ + +/** Create a new drawing context. + * This will create a drawing context with some dimensions, and some format. + * After this has been called, the function pointers in the returned structure + * can be called together with a pointer to the structure itself to cause + * image functions to be executed. + * + * \param[in] w The width of the output image. + * \param[in] h The height of the ouput image. + * \param[in] file The file to which the image should be written. + * \param[in] fontName The name of the font to use for rendering. + * \param[in] type The output type to generate. + * \param[in, out] *outContext Pointer to an \a ADraw structure to populate + * with values. + * \retval Boolean On error, #FALSE will be returned. + */ +Boolean ADrawOpen(unsigned int w, + unsigned int h, + const char *file, + const char *fontName, + ADrawOutputType type, + struct ADrawTag *outContext); + +/** Given a string name for a colour, return the corresponding ADrawColour. + * + * \param[in] colour The string representation of the colour that is sought. + */ +ADrawColour ADrawGetColour(const char *colour); + +/** Compute the position of a point on an arc. + * This allows co-ordinates on arc drawn using arc() or dottedArc() to be + * computed. The centre and bounding box for the arc are supplied as well + * as an angular offset. + * + * \param[in] cx Center of the arc. + * \param[in] cy Center of the arc. + * \param[in] w Arc x-diameter (width). + * \param[in] h Arc y-diameter (height). + * \param[in] degrees Position on the arc to be returned. + * \param[in,out] x Pointer to fill with x coordinate. + * \param[in,out] y Pointer to fill with y coordinate. + */ +void ADrawComputeArcPoint(float cx, + float cy, + float w, + float h, + float degrees, + unsigned int *x, + unsigned int *y); + +#endif /* MSCGEN_ADRAW_H */ + +/* END OF FILE */ diff --git a/libmscgen/mscgen_adraw_int.h b/libmscgen/mscgen_adraw_int.h new file mode 100644 index 0000000..6f79ca4 --- /dev/null +++ b/libmscgen/mscgen_adraw_int.h @@ -0,0 +1,65 @@ +/*************************************************************************** + * + * $Id: adraw_int.h 115 2010-08-19 09:58:45Z Michael.McTernan $ + * + * This file is part of mscgen, a message sequence chart renderer. + * Copyright (C) 2005 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + **************************************************************************/ + +#ifndef MSCGEN_ADRAW_INT_H +#define MSCGEN_ADRAW_INT_H + +#include "mscgen_adraw.h" + +/*************************************************************************** + * Preprocessor Macros + ***************************************************************************/ + +/* Define macro to supress unused parameter warnings */ +#ifndef UNUSED +# ifdef __GNUC__ +# define UNUSED __attribute__((unused)) +# else +# define UNUSED +# endif +#endif + +/*************************************************************************** + * Functions + ***************************************************************************/ + +Boolean NullInit(struct ADrawTag *outContext); + +Boolean GdoInit(unsigned int w, + unsigned int h, + const char *file, + const char *fontName, + struct ADrawTag *outContext); + +Boolean PsInit(unsigned int w, + unsigned int h, + const char *file, + struct ADrawTag *outContext); + +Boolean SvgInit(unsigned int w, + unsigned int h, + const char *file, + struct ADrawTag *outContext); + +#endif /* MSCGEN_ADRAW_INT_H */ + +/* END OF FILE */ diff --git a/libmscgen/mscgen_api.c b/libmscgen/mscgen_api.c new file mode 100644 index 0000000..0f6052a --- /dev/null +++ b/libmscgen/mscgen_api.c @@ -0,0 +1,1874 @@ +#include "mscgen_api.h" +#include "mscgen_config.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#ifdef HAVE_LIMITS_H +#include <limits.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <errno.h> +#include <ctype.h> +#include <assert.h> +#include "mscgen_lexer.h" +#include "mscgen_adraw.h" +#include "mscgen_msc.h" +#include "mscgen_safe.h" + +/*************************************************************************** + * Macro definitions + ***************************************************************************/ + +#define M_Max(a, b) (((a) > (b)) ? (a) : (b)) +#define M_Min(a, b) (((a) < (b)) ? (a) : (b)) + +/*************************************************************************** + * Types + ***************************************************************************/ + +/** Structure for holding global options. + * This structure groups all the options that affect the text output into + * one structure. + */ +typedef struct GlobalOptionsTag +{ + /** Ideal width of output canvas. + * If this value allows the entitySpacing to be increased, then + * entitySpacing will be set to the larger value of it's original + * value and idealCanvasWidth / number of entities. + */ + unsigned int idealCanvasWidth; + + /** Horizontal spacing between entities. */ + unsigned int entitySpacing; + + /** Gap at the top of the page. */ + unsigned int entityHeadGap; + + /** Vertical spacing between arcs. */ + unsigned int arcSpacing; + + /** Arc gradient. + * Y offset of arc head, relative to tail, in pixels. + */ + int arcGradient; + + /** Gap between adjacent boxes. */ + unsigned int boxSpacing; + + /** Minimum distance between box edges and text. */ + unsigned int boxInternalBorder; + + /** Radius of rounded box corner arcs. */ + unsigned int rboxArc; + + /** Size of 'corner' added to note boxes. */ + unsigned int noteCorner; + + /** Anguluar box slope in pixels. */ + unsigned int aboxSlope; + + /** If TRUE, wrap arc text as well as box contents. */ + Boolean wordWrapArcLabels; + + /** Horizontal width of the arrow heads. */ + unsigned int arrowWidth; + + /** Vertical depth of the arrow heads. */ + unsigned int arrowHeight; + + /** Height of an arc which loops back to itself. */ + unsigned int loopArcHeight; + + /** Horizontal gap between text and horizontal lines. */ + unsigned int textHGapPre; + + /** Horizontal gap between text and horizontal lines. */ + unsigned int textHGapPost; +} +GlobalOptions; + +/** Information about each out row. + */ +typedef struct +{ + /** Minimum Y value. */ + unsigned int ymin; + + /** Y position of the arc on the row. */ + unsigned int arcliney; + + /** Maximum Y value. */ + unsigned int ymax; + + /** Maximum lines of text on the row. */ + unsigned int maxTextLines; +} +RowInfo; + + +typedef struct ContextTag +{ + GlobalOptions opts; + ADraw drw; +} Context; + + +/*************************************************************************** + * Local Variables. + ***************************************************************************/ + +static const GlobalOptions gDefaultOpts = +{ + 600, /* idealCanvasWidth */ + + 80, /* entitySpacing */ + 20, /* entityHeadGap */ + 6, /* arcSpacing */ + 0, /* arcGradient */ + 8, /* boxSpacing */ + 4, /* boxInternalBorder */ + 6, /* rboxArc */ + 12, /* noteCorner */ + 6, /* aboxSlope */ + FALSE, /* wordWrapArcLabels */ + + /* Arrow options */ + 10, 6, + + /* loopArcHeight */ + 12, + + /* textHGapPre, textHGapPost */ + 2, 2 +}; + + +/*************************************************************************** + * Functions + ***************************************************************************/ + +/** Count the number of lines in some string. + * This counts line breaks that are written as a literal '\n' in the line to + * determine how many lines of output are needed. + * + * \param[in] l Pointer to the input string to inspect. + * \returns The count of '\n' characters appearing in the input string + 1. + */ +static unsigned int countLines(const char *l) +{ + unsigned int c = 1; + + do + { + c++; + + l = strstr(l, "\\n"); + if (l) l += 2; + } while (l != NULL); + + return c; +} + +/** Check if some arc type indicates a box. + */ +static Boolean isBoxArc(const MscArcType a) +{ + return a == MSC_ARC_BOX || a == MSC_ARC_RBOX || + a == MSC_ARC_ABOX || a== MSC_ARC_NOTE; +} + +/** Get the skip value in pixels for some the current arc in the Msc. + */ +static int getArcGradient(Context *ctx, Msc m, const RowInfo *rowInfo, unsigned int row) +{ + const char *s = MscGetCurrentArcAttrib(m, MSC_ATTR_ARC_SKIP); + unsigned int v = ctx->opts.arcGradient; + + if (s != NULL && rowInfo != NULL) + { + const unsigned int rowCount = MscGetNumArcs(m) - MscGetNumParallelArcs(m); + unsigned int skip; + + if (sscanf(s, "%u", &skip) == 1) + { + unsigned int ystart = rowInfo[row].arcliney; + unsigned int yend = rowInfo[M_Min(rowCount - 1, row + skip)].arcliney; + + v += yend - ystart; + } + else + { + fprintf(stderr, "Warning: Non-integer arcskip value: %s\n", s); + } + } + + return v; +} + + +/** Check if some arc name indicates a broadcast entity. + */ +static Boolean isBroadcastArc(const char *entity) +{ + return entity != NULL && (strcmp(entity, "*") == 0); +} + +/** Free memory allocated for the label lines. + */ +static void freeLabelLines(unsigned int n, char **lines) +{ + while (n > 0) + { + n--; + free(lines[n]); + } + + free(lines); +} + + +/** Word wrap a line of text until the first line is less than \a width wide. + * This removes words from the input line and builds them into a 2nd new + * string until the input line is shorter than the supplied width. The + * input string is directly truncated, while the remaining characters are + * returned in a new memory allocation. On return, the input line of text + * will be shorter than \a width, while the newly returned string will contain + * all the remaining characters. + * + * If the input line is already shorter than \a width, the function returns + * NULL and does not modify the input line of text. + * + * \param[in,out] l Input line of text which maybe modified if needed. + * \param[in] width Maximum allowable text line width. + * \returns NULL if \a l was already less then \a width long, + * otherwise a new string giving the remained of the string. + */ +static char *splitStringToWidth(Context *ctx, char *l, unsigned int width) +{ + char *p = l + strlen(l); + char *orig = NULL; + int m, n; + + if (ctx->drw.textWidth(&ctx->drw, l) > width) + { + /* Duplicate the original string */ + orig = strdup_s(l); + + /* Now remove words from the line until it fits the available width */ + do + { + /* Skip back 1 word */ + while (!isspace(*p) && p > l) + { + p--; + } + + if (p > l) + { + *p = '\0'; + } + } + while (ctx->drw.textWidth(&ctx->drw, l) > width && p > l); + + /* Check if the first word is bigger than the available space; + * we need to hyphenate in this case. + */ + if (p == l) + { + const unsigned int hyphenWidth = ctx->drw.textWidth(&ctx->drw, "-"); + + /* Find the end of the first word */ + while (!isspace(*p) && *p != '\0') + { + p++; + } + + /* Start removing characters from the word */ + do + { + *p = '\0'; + p--; + } + while (ctx->drw.textWidth(&ctx->drw, l) + hyphenWidth > width && p > l); + + /* Add a hyphen */ + *p = '-'; + } + + /* Copy the remaining line to the start of the string */ + m = 0; + n = (p - l); + + while (isspace(orig[n]) && orig[n] != '\0') + { + n++; + } + + do + { + orig[m++] = orig[n++]; + } + while (orig[m - 1] != '\0'); + } + + return orig; +} + + +/** Split an input arc label into lines, word-wrapping if needed. + * This takes the literal label supplied from the input and splits it into an + * array of char * text lines. Splitting is first done according to literal + * '\n' character sequences added by the user, then according to word wrapping + * to fit available space, if appropriate. + * + * \param[in] m The MSC for which the lines are to be split. + * \param[in] arcType The type of the arc being labelled. + * \param[in,out] lines Pointer to be filled with output line array. + * \param[in] label Original arc label from input file. + * \param[in] startCol Column in which the arc starts. + * \param[in] endCol Column in which the arc ends, or -1 for broadcast arcs. + * + * \note The returned strings and array must be free()'d. freeLabelLines() can + * be used for this purpose. + */ +static unsigned int computeLabelLines(Context *ctx, + Msc m, + const MscArcType arcType, + char ***lines, + const char *label, + int startCol, + int endCol) +{ + unsigned int width; + unsigned int nAllocLines = 8; + char **retLines = malloc_s(sizeof(char *) * nAllocLines); + unsigned int c = 0; + + assert(startCol >= 0 && startCol < (signed)MscGetNumEntities(m)); + assert(startCol >= -1 && startCol < (signed)MscGetNumEntities(m)); + + /* Compute available width for text */ + if (isBoxArc(arcType) || ctx->opts.wordWrapArcLabels) + { + if (endCol == -1) + { + /* This is a special case for a broadcast arc */ + width = ctx->opts.entitySpacing * MscGetNumEntities(m); + } + else if (startCol < endCol) + { + width = ctx->opts.entitySpacing * (1 + (endCol - startCol)); + } + else + { + width = ctx->opts.entitySpacing * (1 + (startCol - endCol)); + } + + /* Reduce the width due to the box borders */ + if (isBoxArc(arcType)) + { + width -= (ctx->opts.boxSpacing + ctx->opts.boxInternalBorder) * 2; + } + + if (arcType == MSC_ARC_NOTE) + { + width -= ctx->opts.noteCorner; + } + } + else + { + width = UINT_MAX; + } + + /* Split the input label into lines */ + while (label != NULL) + { + /* First split around user specified lines with literal '\n' */ + char *nextLine = strstr(label, "\\n"); + if (nextLine) + { + const int lineLen = nextLine - label; + + /* Allocate storage and duplicate the line */ + retLines[c] = malloc_s(lineLen + 1); + memcpy(retLines[c], label, lineLen); + retLines[c][lineLen] = '\0'; + + /* Advance the label */ + label = nextLine + 2; + } + else + { + /* Duplicate the final line */ + retLines[c] = strdup_s(label); + label = NULL; + } + + /* Now split the line as required to wrap into the space available */ + do + { + /* Check if more storage maybe needed */ + if (c + 2 >= nAllocLines) + { + nAllocLines += 8; + retLines = realloc_s(retLines, sizeof(char *) * nAllocLines); + } + + retLines[c + 1] = splitStringToWidth(ctx, retLines[c], width); + c++; + } + while (retLines[c] != NULL); + } + + /* Return the array of lines and the count */ + *lines = retLines; + + return c; +} + + + +/** Compute the output canvas size required for some MSC. + * This computes the dimensions for the canvas as well as the height for each + * row. + * + * \param[in] m The MSC to analyse. + * \param[in,out] w Pointer to be filled with the output width. + * \param[in,out] h Pointer to be filled with the output height. + * \returns An array giving the height of each row. + */ +static RowInfo *computeCanvasSize(Context *ctx, + Msc m, + unsigned int *w, + unsigned int *h) +{ + const unsigned int rowCount = MscGetNumArcs(m) - MscGetNumParallelArcs(m); + const unsigned int textHeight = ctx->drw.textHeight(&ctx->drw); + RowInfo *rowHeight; + unsigned int nextYmin, ymin, ymax, yskipmax, row; + + /* Allocate storage for the height of each row */ + rowHeight = zalloc_s(sizeof(RowInfo) * rowCount); + row = 0; + + nextYmin = ymin = ctx->opts.entityHeadGap; + yskipmax = 0; + + MscResetArcIterator(m); + do + { + const MscArcType arcType = MscGetCurrentArcType(m); + const int arcGradient = isBoxArc(arcType) ? 0 : getArcGradient(ctx, m, NULL, 0); + char **arcLabelLines = NULL; + unsigned int arcLabelLineCount = 0; + int startCol = -1, endCol = -1; + + if (arcType == MSC_ARC_PARALLEL) + { + assert(row > 0); + + row--; + + ymin = rowHeight[row].ymin; + nextYmin = rowHeight[row].ymax; + } + else + { + /* Get the entity indices */ + if (arcType != MSC_ARC_DISCO && arcType != MSC_ARC_DIVIDER && arcType != MSC_ARC_SPACE) + { + startCol = MscGetEntityIndex(m, MscGetCurrentArcSource(m)); + endCol = MscGetEntityIndex(m, MscGetCurrentArcDest(m)); + } + else + { + /* Discontinuity or parallel arc spans whole chart */ + startCol = 0; + endCol = MscGetNumEntities(m) - 1; + } + + /* Work out how the label fits the gap between entities */ + arcLabelLineCount = computeLabelLines(ctx, m, arcType, &arcLabelLines, + MscGetCurrentArcAttrib(m, MSC_ATTR_LABEL), + startCol, endCol); + + assert(row < rowCount); + + /* Update the max line count for the row */ + if (arcLabelLineCount > rowHeight[row].maxTextLines) + { + rowHeight[row].maxTextLines = arcLabelLineCount; + } + + freeLabelLines(arcLabelLineCount, arcLabelLines); + + /* Compute the height of this arc */ + if (arcType != MSC_ARC_DISCO && arcType != MSC_ARC_DIVIDER && arcType != MSC_ARC_SPACE) + { + ymax = ymin + ctx->opts.arcSpacing; + ymax += (M_Max(rowHeight[row].maxTextLines, 2) * textHeight); + } + else + { + ymax = ymin + ctx->opts.arcSpacing; + ymax += (M_Max(rowHeight[row].maxTextLines, 1) * textHeight); + } + + /* Update next potential row start */ + if (ymax > nextYmin) + { + nextYmin = ymax; + } + + /* Compute the dimensions for the completed row */ + rowHeight[row].ymin = ymin; + rowHeight[row].ymax = nextYmin - ctx->opts.arcSpacing; + rowHeight[row].arcliney = rowHeight[row].ymin + (rowHeight[row].ymax - rowHeight[row].ymin) / 2; + row++; + + /* Start new row */ + ymin = nextYmin; + } + + /* Keep a track of where the gradient may cause the graph to end */ + if (ymax + arcGradient > ymax) + { + yskipmax = ymax + arcGradient; + } + + } + while (MscNextArc(m)); + + if (ymax < yskipmax) + ymax = yskipmax; + + /* Set the return values */ + *w = MscGetNumEntities(m) * ctx->opts.entitySpacing; + *h = ymax; + + return rowHeight; +} + +/** Add a point to the output imagemap. + * If \a ismap and \a url are non-NULL, this function will add a rectangle + * to the imagemap according to the parameters passed. + * + * \param ismap The file to which the imagemap should be rendered. + * \param url The URL to which the imagemap area should link. + * \param x1 The x coordinate for the upper left point. + * \param y2 The y coordinate for the upper left point. + * \param x2 The x coordinate for the lower right point. + * \param y2 The y coordinate for the lower right point. + */ +static void ismapRect(FILE *ismap, + const char *url, + unsigned int x1, + unsigned int y1, + unsigned int x2, + unsigned int y2) +{ + if(ismap && url) + { + assert(x1 <= x2); assert(y1 <= y2); + + fprintf(ismap, + "rect %s %d,%d %d,%d\n", + url, + x1, y1, + x2, y2); + } +#if 0 + /* For debug render a cross onto the output */ + drw.line(&drw, x1, y1, x2, y2); + drw.line(&drw, x2, y1, x1, y2); +#endif +} + + +/** Get some line from a string containing '\n' delimiters. + * Given a string that contains literal '\n' delimiters, return a subset in + * a passed buffer that gives the nth line. + * + * \param[in] string The string to parse. + * \param[in] line The line number to return from the string, which should + * count from 0. + * \param[in] out Pointer to a buffer to fill with line data. + * \param[in] outLen The length of the buffer pointed to by \a out, in bytes. + * \returns A pointer to \a out. + */ +static char *getLine(const char *string, + unsigned int line, + char *const out, + const unsigned int outLen) +{ + const char *lineStart, *lineEnd; + unsigned int lineLen; + + /* Setup for the loop */ + lineEnd = NULL; + line++; + + do + { + /* Check if this is the first or a repeat iteration */ + if(lineEnd) + { + lineStart = lineEnd + 2; + } + else + { + lineStart = string; + } + + /* Search for next delimited */ + lineEnd = strstr(lineStart, "\\n"); + + line--; + } + while (line > 0 && lineEnd != NULL); + + /* Determine the length of the line */ + if(lineEnd != NULL) + { + lineLen = lineEnd - lineStart; + } + else + { + lineLen = strlen(string) - (lineStart - string); + } + + /* Clamp the length to the buffer */ + if(lineLen > outLen - 1) + { + lineLen = outLen - 1; + } + + /* Copy desired characters */ + memcpy(out, lineStart, lineLen); + + /* NULL terminate */ + out[lineLen] = '\0'; + + return out; +} + + +/** Render some entity text. + * Draw the text for some entity. + * \param ismap If not \a NULL, write an ismap description here. + * \param x The x position at which the entity text should be centered. + * \param y The y position where the text should be placed. + * \param entLabel The label to render, which maybe \a NULL in which case + * no ouput is produced. + * \param entUrl The URL for rendering the label as a hyperlink. This + * maybe \a NULL if not required. + * \param entId The text identifier for the arc. + * \param entIdUrl The URL for rendering the test identifier as a hyperlink. + * This maybe \a NULL if not required. + * \param entColour The text colour name or specification for the entity text. + * If NULL, use default colouring scheme. + * \param entBgColour The text background colour name or specification for the + * entity text. If NULL, use default colouring scheme. + */ +static void entityText(Context *ctx, + FILE *ismap, + unsigned int x, + unsigned int y, + const char *entLabel, + const char *entUrl, + const char *entId, + const char *entIdUrl, + const char *entColour, + const char *entBgColour) +{ + if(entLabel) + { + const unsigned int lines = countLines(entLabel); + unsigned int l; + char lineBuffer[1024]; + + /* Adjust y to be above the writing line */ + y -= ctx->drw.textHeight(&ctx->drw) * (lines - 1); + + for (l = 0; l < lines - 1; l++) + { + char *lineLabel = getLine(entLabel, l, lineBuffer, sizeof(lineBuffer)); + unsigned int width = ctx->drw.textWidth(&ctx->drw, lineLabel); + + /* Push text down one line */ + y += ctx->drw.textHeight(&ctx->drw); + + /* Check if a URL is associated */ + if(entUrl) + { + /* If no explict colour has been set, make URLS blue */ + ctx->drw.setPen(&ctx->drw, ADRAW_COL_BLUE); + + /* Image map output */ + ismapRect(ismap, + entUrl, + x - (width / 2), y - ctx->drw.textHeight(&ctx->drw), + x + (width / 2), y); + } + + /* Set to the explicit colours if directed */ + if(entColour != NULL) + { + ctx->drw.setPen(&ctx->drw, ADrawGetColour(entColour)); + } + + if(entBgColour != NULL) + { + ctx->drw.setBgPen(&ctx->drw, ADrawGetColour(entBgColour)); + } + + /* Render text and restore pen */ + ctx->drw.textC (&ctx->drw, x, y, lineLabel); + ctx->drw.setPen(&ctx->drw, ADRAW_COL_BLACK); + ctx->drw.setBgPen(&ctx->drw, ADRAW_COL_WHITE); + + /* Render the Id of the title, if specified and for first line only */ + if(entId && l == 0) + { + unsigned int idwidth; + int idx, idy; + + idy = y - ctx->drw.textHeight(&ctx->drw); + idx = x + (width / 2); + + ctx->drw.setFontSize(&ctx->drw, ADRAW_FONT_TINY); + + idwidth = ctx->drw.textWidth(&ctx->drw, entId); + idy += (ctx->drw.textHeight(&ctx->drw) + 1) / 2; + + if(entIdUrl) + { + ctx->drw.setPen(&ctx->drw, ADRAW_COL_BLUE); + ctx->drw.textR (&ctx->drw, idx, idy, entId); + ctx->drw.setPen(&ctx->drw, ADRAW_COL_BLACK); + + /* Image map output */ + ismapRect(ismap, + entIdUrl, + idx, idy - ctx->drw.textHeight(&ctx->drw), + idx + idwidth, idy); + } + else + { + ctx->drw.textR(&ctx->drw, idx, idy, entId); + } + + ctx->drw.setFontSize(&ctx->drw, ADRAW_FONT_SMALL); + } + } + } +} + +/** Draw vertical lines stemming from entities. + * This function will draw a single segment of the vertical line that + * drops from an entity. + * + * \param m The \a Msc for which the lines are drawn + * \param ymin Top of the row. + * \param ymax Bottom of the row. + * \param dotted If #TRUE, produce a dotted line, otherwise solid. + * \param colourRefs Colour references for each entity. + */ +static void entityLines(Context *ctx, + Msc m, + const unsigned int ymin, + const unsigned int ymax, + Boolean dotted, + const ADrawColour *colourRefs) +{ + unsigned int t; + + for (t = 0; t < MscGetNumEntities(m); t++) + { + unsigned int x = (ctx->opts.entitySpacing / 2) + (ctx->opts.entitySpacing * t); + + ctx->drw.setPen(&ctx->drw, colourRefs[t]); + + if(dotted) + { + ctx->drw.dottedLine(&ctx->drw, x, ymin, x, ymax); + } + else + { + ctx->drw.line(&ctx->drw, x, ymin, x, ymax); + } + } + + ctx->drw.setPen(&ctx->drw, ADRAW_COL_BLACK); + +} + +/** Draw an arrow pointing to the right. + * \param x The x co-ordinate for the end point for the arrow head. + * \param y The y co-ordinate for the end point for the arrow head. + * \param type The arc type, which controls the format of the arrow head. + */ +static void arrowR(Context *ctx, + unsigned int x, + unsigned int y, + MscArcType type) +{ + switch(type) + { + case MSC_ARC_SIGNAL: /* Unfilled half */ + ctx->drw.line(&ctx->drw, + x, y, + x - ctx->opts.arrowWidth, y + ctx->opts.arrowHeight); + break; + + case MSC_ARC_DOUBLE: + case MSC_ARC_METHOD: /* Filled */ + case MSC_ARC_RETVAL: /* Filled, dotted arc (not rendered here) */ + ctx->drw.filledTriangle(&ctx->drw, + x, y, + x - ctx->opts.arrowWidth, y + ctx->opts.arrowHeight, + x - ctx->opts.arrowWidth, y - ctx->opts.arrowHeight); + break; + + case MSC_ARC_CALLBACK: /* Non-filled */ + ctx->drw.line(&ctx->drw, + x, y, + x - ctx->opts.arrowWidth, y + ctx->opts.arrowHeight); + ctx->drw.line(&ctx->drw, + x - ctx->opts.arrowWidth, y - ctx->opts.arrowHeight, + x, y); + break; + + default: + assert(0); + break; + } +} + + +/** Draw an arrow pointing to the left. + * \param x The x co-ordinate for the end point for the arrow head. + * \param y The y co-ordinate for the end point for the arrow head. + * \param type The arc type, which controls the format of the arrow head. + */ +static void arrowL(Context *ctx, + unsigned int x, + unsigned int y, + MscArcType type) +{ + switch(type) + { + case MSC_ARC_SIGNAL: /* Unfilled half */ + ctx->drw.line(&ctx->drw, + x, y, + x + ctx->opts.arrowWidth, y + ctx->opts.arrowHeight); + break; + + case MSC_ARC_DOUBLE: + case MSC_ARC_METHOD: /* Filled */ + case MSC_ARC_RETVAL: /* Filled, dotted arc (not rendered here) */ + ctx->drw.filledTriangle(&ctx->drw, + x, y, + x + ctx->opts.arrowWidth, y + ctx->opts.arrowHeight, + x + ctx->opts.arrowWidth, y - ctx->opts.arrowHeight); + break; + + case MSC_ARC_CALLBACK: /* Non-filled */ + ctx->drw.line(&ctx->drw, + x, y, + x + ctx->opts.arrowWidth, y + ctx->opts.arrowHeight); + ctx->drw.line(&ctx->drw, + x, y, + x + ctx->opts.arrowWidth, y - ctx->opts.arrowHeight); + break; + + default: + assert(0); + break; + } +} + +/** Draw vertical lines and boxes stemming from entities. + * \param ymin Top of the row. + * \param ymax Bottom of the row. + * \param boxStart Column in which the box starts. + * \param boxEnd Column in which the box ends. + * \param boxType The type of box to draw, MSC_ARC_BOX, MSC_ARC_RBOX etc. + * \param lineColour Colour of the lines to use for rendering the box. + * \param bgColour Background colour for rendering the box. + */ +static void arcBox(Context *ctx, + unsigned int ymin, + unsigned int ymax, + unsigned int boxStart, + unsigned int boxEnd, + MscArcType boxType, + const char *lineColour, + const char *bgColour) +{ + unsigned int t; + + /* Ensure the start is less than or equal to the end */ + if(boxStart > boxEnd) + { + t = boxEnd; + boxEnd = boxStart; + boxStart = t; + } + + /* Now draw the box */ + unsigned int x1 = (ctx->opts.entitySpacing * boxStart) + ctx->opts.boxSpacing; + unsigned int x2 = ctx->opts.entitySpacing * (boxEnd + 1) - ctx->opts.boxSpacing; + unsigned int ymid = (ymin + ymax) / 2; + + /* Set colour for the background area */ + if(bgColour != NULL) + { + ctx->drw.setPen(&ctx->drw, ADrawGetColour(bgColour)); + } + else + { + ctx->drw.setPen(&ctx->drw, ADRAW_COL_WHITE); + } + + /* Draw the background to overwrite the entity lines */ + switch(boxType) + { + case MSC_ARC_BOX: + ctx->drw.filledRectangle(&ctx->drw, x1, ymin, x2, ymax); + break; + + case MSC_ARC_RBOX: + ctx->drw.filledRectangle(&ctx->drw, x1 + ctx->opts.rboxArc, ymin, x2 - ctx->opts.rboxArc, ymax); + ctx->drw.filledRectangle(&ctx->drw, x1, ymin + ctx->opts.rboxArc, x2, ymax - ctx->opts.rboxArc); + ctx->drw.filledCircle(&ctx->drw, x1 + ctx->opts.rboxArc, ymin + ctx->opts.rboxArc, ctx->opts.rboxArc); + ctx->drw.filledCircle(&ctx->drw, x2 - ctx->opts.rboxArc, ymin + ctx->opts.rboxArc, ctx->opts.rboxArc); + ctx->drw.filledCircle(&ctx->drw, x1 + ctx->opts.rboxArc, ymax - ctx->opts.rboxArc, ctx->opts.rboxArc); + ctx->drw.filledCircle(&ctx->drw, x2 - ctx->opts.rboxArc, ymax - ctx->opts.rboxArc, ctx->opts.rboxArc); + break; + + case MSC_ARC_NOTE: + ctx->drw.filledRectangle(&ctx->drw, x1, ymin, x2 - ctx->opts.noteCorner, ymax); + ctx->drw.filledRectangle(&ctx->drw, x1, ymin + ctx->opts.noteCorner, x2, ymax); + ctx->drw.filledTriangle(&ctx->drw, x2 - ctx->opts.noteCorner, ymin, + x2, ymin + ctx->opts.noteCorner, + x2 - ctx->opts.noteCorner, ymin + ctx->opts.noteCorner); + break; + + case MSC_ARC_ABOX: + ctx->drw.filledRectangle(&ctx->drw, x1 + ctx->opts.aboxSlope, ymin, x2 - ctx->opts.aboxSlope, ymax); + ctx->drw.filledTriangle(&ctx->drw, x1 + ctx->opts.aboxSlope, ymin, + x1 + ctx->opts.aboxSlope, ymax, + x1, ymid); + ctx->drw.filledTriangle(&ctx->drw, x2 - ctx->opts.aboxSlope, ymin, + x2 - ctx->opts.aboxSlope, ymax, + x2, ymid); + break; + + default: + assert(0); + } + + /* Setup the colour for rendering the boxes */ + if(lineColour) + { + ctx->drw.setPen(&ctx->drw, ADrawGetColour(lineColour)); + } + else + { + ctx->drw.setPen(&ctx->drw, ADRAW_COL_BLACK); + } + + /* Draw the outline */ + switch(boxType) + { + case MSC_ARC_BOX: + ctx->drw.line(&ctx->drw, x1, ymin, x2, ymin); + ctx->drw.line(&ctx->drw, x1, ymax, x2, ymax); + ctx->drw.line(&ctx->drw, x1, ymin, x1, ymax); + ctx->drw.line(&ctx->drw, x2, ymin, x2, ymax); + break; + + case MSC_ARC_NOTE: + ctx->drw.line(&ctx->drw, x1, ymin, x2 - ctx->opts.noteCorner, ymin); + ctx->drw.line(&ctx->drw, x1, ymax, x2, ymax); + ctx->drw.line(&ctx->drw, x1, ymin, x1, ymax); + ctx->drw.line(&ctx->drw, x2, ymin + ctx->opts.noteCorner, x2, ymax); + ctx->drw.line(&ctx->drw, x2 - ctx->opts.noteCorner, ymin, + x2, ymin + ctx->opts.noteCorner); + ctx->drw.line(&ctx->drw, x2 - ctx->opts.noteCorner, ymin, + x2 - ctx->opts.noteCorner, ymin + ctx->opts.noteCorner); + ctx->drw.line(&ctx->drw, x2, ymin + ctx->opts.noteCorner, + x2 - ctx->opts.noteCorner, ymin + ctx->opts.noteCorner); + break; + + case MSC_ARC_RBOX: + ctx->drw.line(&ctx->drw, x1 + ctx->opts.rboxArc, ymin, x2 - ctx->opts.rboxArc, ymin); + ctx->drw.line(&ctx->drw, x1 + ctx->opts.rboxArc, ymax, x2 - ctx->opts.rboxArc, ymax); + ctx->drw.line(&ctx->drw, x1, ymin + ctx->opts.rboxArc, x1, ymax - ctx->opts.rboxArc); + ctx->drw.line(&ctx->drw, x2, ymin + ctx->opts.rboxArc, x2, ymax - ctx->opts.rboxArc); + + ctx->drw.arc(&ctx->drw, x1 + ctx->opts.rboxArc, + ymin + ctx->opts.rboxArc, ctx->opts.rboxArc * 2, ctx->opts.rboxArc * 2, + 180, 270); + ctx->drw.arc(&ctx->drw, x2 - ctx->opts.rboxArc, + ymin + ctx->opts.rboxArc, ctx->opts.rboxArc * 2, ctx->opts.rboxArc * 2, + 270, 0); + ctx->drw.arc(&ctx->drw, x2 - ctx->opts.rboxArc, + ymax - ctx->opts.rboxArc, ctx->opts.rboxArc * 2, ctx->opts.rboxArc * 2, + 0, 90); + ctx->drw.arc(&ctx->drw, x1 + ctx->opts.rboxArc, + ymax - ctx->opts.rboxArc, ctx->opts.rboxArc * 2, ctx->opts.rboxArc * 2, + 90, 180); + break; + + case MSC_ARC_ABOX: + ctx->drw.line(&ctx->drw, x1 + ctx->opts.aboxSlope, ymin, x2 - ctx->opts.aboxSlope, ymin); + ctx->drw.line(&ctx->drw, x1 + ctx->opts.aboxSlope, ymax, x2 - ctx->opts.aboxSlope, ymax); + ctx->drw.line(&ctx->drw, x1 + ctx->opts.aboxSlope, ymin, x1, ymid); + ctx->drw.line(&ctx->drw, x1, ymid, x1 + ctx->opts.aboxSlope, ymax); + ctx->drw.line(&ctx->drw, x2 - ctx->opts.aboxSlope, ymin, x2, ymid); + ctx->drw.line(&ctx->drw, x2, ymid, x2 - ctx->opts.aboxSlope, ymax); + break; + + default: + assert(0); + } + + /* Restore the pen colour if needed */ + if(lineColour) + { + ctx->drw.setPen(&ctx->drw, ADRAW_COL_BLACK); + } +} + + +/** Render text on an arc. + * Draw the text on some arc. + * \param m The Msc for which the text is being rendered. + * \param ismap If not \a NULL, write an ismap description here. + * \param outwidth Width of the output image. + * \param ymid Co-ordinate of the row on which the text should be aligned. + * \param startCol The column at which the arc being labelled starts. + * \param endCol The column at which the arc being labelled ends. + * \param arcLabelLineCount Count of lines of text in arcLabelLines. + * \param arcLabelLines Array of lines of text from 0 to arcLabelLineCount - 1. + * \param arcUrl The URL for rendering the label as a hyperlink. This + * maybe \a NULL if not required. + * \param arcId The text identifier for the arc. + * \param arcIdUrl The URL for rendering the test identifier as a hyperlink. + * This maybe \a NULL if not required. + * \param arcTextColour Colour for the arc text, or NULL to use default. + * \param arcTextColour Colour for the arc text backgroun, or NULL to use default. + * \param arcType The type of arc, used to control output semantics. + */ +static void arcText(Context *ctx, + Msc m, + FILE *ismap, + unsigned int outwidth, + unsigned int ymid, + int ygradient, + unsigned int startCol, + unsigned int endCol, + const unsigned int arcLabelLineCount, + char **arcLabelLines, + const char *arcUrl, + const char *arcId, + const char *arcIdUrl, + const char *arcTextColour, + const char *arcTextBgColour, + const MscArcType arcType) +{ + unsigned int l; + unsigned int y; + + /* A single line of normal text is above the midline */ + if(arcLabelLineCount == 1 && !isBoxArc(arcType) && + arcType != MSC_ARC_DISCO && arcType != MSC_ARC_DIVIDER && + arcType != MSC_ARC_SPACE) + { + y = ymid + (ygradient / 2) - ctx->drw.textHeight(&ctx->drw); + } + else /* Text is vertically centered on the midline */ + { + int yoff = ygradient - (ctx->drw.textHeight(&ctx->drw) * arcLabelLineCount); + y = ymid + (yoff / 2); + } + + for (l = 0; l < arcLabelLineCount; l++) + { + const char *lineLabel = arcLabelLines[l]; + unsigned int width = ctx->drw.textWidth(&ctx->drw, lineLabel); + int x = ((startCol + endCol + 1) * ctx->opts.entitySpacing) / 2; + + y += ctx->drw.textHeight(&ctx->drw); + + if(startCol != endCol || isBoxArc(arcType)) + { + /* Produce central aligned text */ + x -= width / 2; + } + else if(startCol < (MscGetNumEntities(m) / 2)) + { + /* Form text to the right */ + x += ctx->opts.textHGapPre; + } + else + { + /* Form text to the left */ + x -= width + ctx->opts.textHGapPost; + } + + /* Clip against edges of image */ + if(x + width > outwidth) + { + x = outwidth - width; + } + + if(x < 0) + { + x = 0; + } + + /* Check if a URL is associated */ + if(arcUrl) + { + /* Default to blue */ + ctx->drw.setPen(&ctx->drw, ADRAW_COL_BLUE); + + /* Image map output */ + ismapRect(ismap, + arcUrl, + x, y - ctx->drw.textHeight(&ctx->drw), + x + width, y); + } + + + /* Set to the explicit colours if directed */ + if(arcTextColour != NULL) + { + ctx->drw.setPen(&ctx->drw, ADrawGetColour(arcTextColour)); + } + + if(arcTextBgColour != NULL) + { + ctx->drw.setBgPen(&ctx->drw, ADrawGetColour(arcTextBgColour)); + } + + /* Render text and restore pen */ + ctx->drw.textR (&ctx->drw, x, y, lineLabel); + ctx->drw.setPen(&ctx->drw, ADRAW_COL_BLACK); + ctx->drw.setBgPen(&ctx->drw, ADRAW_COL_WHITE); + + /* Render the Id of the arc, if specified and for the first line*/ + if(arcId && l == 0) + { + unsigned int idwidth; + int idx, idy; + + idy = y - ctx->drw.textHeight(&ctx->drw); + idx = x + width; + + ctx->drw.setFontSize(&ctx->drw, ADRAW_FONT_TINY); + + idwidth = ctx->drw.textWidth(&ctx->drw, arcId); + idy += (ctx->drw.textHeight(&ctx->drw) + 1) / 2; + + if(arcIdUrl) + { + ctx->drw.setPen(&ctx->drw, ADRAW_COL_BLUE); + + /* Image map output */ + ismapRect(ismap, + arcIdUrl, + idx, idy - ctx->drw.textHeight(&ctx->drw), + idx + idwidth, idy); + } + + /* Render text and restore pen and font */ + ctx->drw.textR (&ctx->drw, idx, idy, arcId); + ctx->drw.setPen(&ctx->drw, ADRAW_COL_BLACK); + ctx->drw.setFontSize(&ctx->drw, ADRAW_FONT_SMALL); + } + } +} + + +/** Render the line and arrow head for some arc. + * This will draw the arc line and arrow head between two columns, + * noting that if the start and end column are the same, an arc is + * rendered. + * \param m The Msc for which the text is being rendered. + * \param ymin Top of row. + * \param ymax Bottom of row. + * \param ygradient The gradient of the arc which alters the y position a + * the ending column. + * \param startCol Starting column for the arc. + * \param endCol Column at which the arc terminates. + * \param hasArrows If true, draw arc arrows, otherwise omit them. + * \param hasBiArrows If true, has arrows in both directions. + * \param arcType The type of the arc, which dictates its rendered style. + */ +static void arcLine(Context *ctx, + Msc m, + unsigned int y, + unsigned int ygradient, + unsigned int startCol, + unsigned int endCol, + const char *arcLineCol, + Boolean hasArrows, + const int hasBiArrows, + const MscArcType arcType) +{ + const unsigned int sx = (startCol * ctx->opts.entitySpacing) + + (ctx->opts.entitySpacing / 2); + const unsigned int dx = (endCol * ctx->opts.entitySpacing) + + (ctx->opts.entitySpacing / 2); + + /* Check if an explicit line colour is requested */ + if(arcLineCol != NULL) + { + ctx->drw.setPen(&ctx->drw, ADrawGetColour(arcLineCol)); + } + + if(startCol != endCol) + { + /* Draw the line */ + if(arcType == MSC_ARC_RETVAL) + { + ctx->drw.dottedLine(&ctx->drw, sx, y, dx, y + ygradient); + } + else if(arcType == MSC_ARC_DOUBLE) + { + ctx->drw.line(&ctx->drw, sx, y - 1, dx, y - 1 + ygradient); + ctx->drw.line(&ctx->drw, sx, y + 1, dx, y + 1 + ygradient); + } + else if(arcType == MSC_ARC_LOSS) + { + signed int span = dx - sx; + unsigned int mx = sx + (span / 4) * 3; + + ctx->drw.line(&ctx->drw, sx, y, mx, y + ygradient); + hasArrows = 0; + + ctx->drw.line(&ctx->drw, mx - 4, y + ygradient - 4, mx + 4, y + ygradient + 4); + ctx->drw.line(&ctx->drw, mx + 4, y + ygradient - 4, mx - 4, y + ygradient + 4); + } + else + { + ctx->drw.line(&ctx->drw, sx, y, dx, y + ygradient); + } + + /* Now the arrow heads */ + if(hasArrows) + { + if(startCol < endCol) + { + arrowR(ctx, dx, y + ygradient, arcType); + } + else + { + arrowL(ctx, dx, y + ygradient, arcType); + } + + if(hasBiArrows) + { + if(startCol < endCol) + { + arrowL(ctx, sx, y + ygradient, arcType); + } + else + { + arrowR(ctx, sx, y + ygradient, arcType); + } + } + } + } + else if(startCol < (MscGetNumEntities(m) / 2)) + { + /* Arc looping to the left */ + if(arcType == MSC_ARC_RETVAL) + { + ctx->drw.dottedArc(&ctx->drw, + sx, y, + ctx->opts.entitySpacing, + ctx->opts.loopArcHeight, + 90, + 270); + } + else if(arcType == MSC_ARC_DOUBLE) + { + ctx->drw.arc(&ctx->drw, + sx, y - 1, + ctx->opts.entitySpacing, + ctx->opts.loopArcHeight, + 90, + 270); + ctx->drw.arc(&ctx->drw, + sx, y + 1, + ctx->opts.entitySpacing, + ctx->opts.loopArcHeight, + 90, + 270); + } + else if(arcType == MSC_ARC_LOSS) + { + unsigned int px, py; + + ctx->drw.arc(&ctx->drw, + sx, y - 1, + ctx->opts.entitySpacing - 8, + ctx->opts.loopArcHeight, + 180 - 45, + 270); + + hasArrows = FALSE; + + /* Get co-ordinates of the arc end-point */ + ADrawComputeArcPoint(sx, y - 1, ctx->opts.entitySpacing - 8, + ctx->opts.loopArcHeight, 180 - 45, + &px, &py); + + /* Draw a cross */ + ctx->drw.line(&ctx->drw, px - 4, py - 4, px + 4, py + 4); + ctx->drw.line(&ctx->drw, px + 4, py - 4, px - 4, py + 4); + } + else + { + ctx->drw.arc(&ctx->drw, + sx, y, + ctx->opts.entitySpacing - 4, + ctx->opts.loopArcHeight, + 90, + 270); + } + + if(hasArrows) + { + arrowR(ctx, dx, y + (ctx->opts.loopArcHeight / 2), arcType); + } + } + else + { + /* Arc looping to right */ + if(arcType == MSC_ARC_RETVAL) + { + ctx->drw.dottedArc(&ctx->drw, + sx, y, + ctx->opts.entitySpacing, + ctx->opts.loopArcHeight, + 270, + 90); + } + else if(arcType == MSC_ARC_DOUBLE) + { + ctx->drw.arc(&ctx->drw, + sx, y - 1, + ctx->opts.entitySpacing, + ctx->opts.loopArcHeight, + 270, + 90); + ctx->drw.arc(&ctx->drw, + sx, y + 1, + ctx->opts.entitySpacing, + ctx->opts.loopArcHeight, + 270, + 90); + } + else if(arcType == MSC_ARC_LOSS) + { + unsigned int px, py; + + ctx->drw.arc(&ctx->drw, + sx, y - 1, + ctx->opts.entitySpacing - 8, + ctx->opts.loopArcHeight, + 270, + 45); + + hasArrows = FALSE; + + /* Get co-ordinates of the arc end-point */ + ADrawComputeArcPoint(sx, y - 1, ctx->opts.entitySpacing - 8, + ctx->opts.loopArcHeight, 45, + &px, &py); + + /* Draw a cross */ + ctx->drw.line(&ctx->drw, px - 4, py - 4, px + 4, py + 4); + ctx->drw.line(&ctx->drw, px + 4, py - 4, px - 4, py + 4); + } + else + { + ctx->drw.arc(&ctx->drw, + sx, y, + ctx->opts.entitySpacing, + ctx->opts.loopArcHeight, + 270, + 90); + } + + if(hasArrows) + { + arrowL(ctx, dx, y + (ctx->opts.loopArcHeight / 2), arcType); + } + } + + /* Restore pen if needed */ + if(arcLineCol != NULL) + { + ctx->drw.setPen(&ctx->drw, ADRAW_COL_BLACK); + } +} + + + +/* Perform post-parsing validation of the MSC. + * This checks the passed MSC for various rules which can't easily be tested + * at parse time. + */ +static Boolean checkMsc(Msc m) +{ + /* Check all arc entites are known */ + MscResetArcIterator(m); + do + { + const MscArcType arcType = MscGetCurrentArcType(m); + + if (arcType != MSC_ARC_PARALLEL && arcType != MSC_ARC_DISCO && + arcType != MSC_ARC_DIVIDER && arcType != MSC_ARC_SPACE) + { + const char *src = MscGetCurrentArcSource(m); + const char *dst = MscGetCurrentArcDest(m); + const int startCol = MscGetEntityIndex(m, src); + const int endCol = MscGetEntityIndex(m, dst); + + /* Check the start column is valid */ + if (startCol == -1) + { + fprintf(stderr, "Error detected at line %u: Unknown source entity '%s'.\n", + MscGetCurrentArcInputLine(m), src); + return FALSE; + } + + if (endCol == -1 && !isBroadcastArc(dst)) + { + fprintf(stderr, "Error detected at line %u: Unknown destination entity '%s'.\n", + MscGetCurrentArcInputLine(m), dst); + return FALSE; + } + } + } + while (MscNextArc(m)); + + return TRUE; +} + + +int mscgen_generate(const char *inputFile, + const char *outputFile, + mscgen_format_t format + ) +{ + //printf("mscgen_generate(in=%s,out=%s,format=%d)\n",inputFile,outputFile,format); + ADrawOutputType outType; + ADrawColour *entColourRef = NULL; + const char *outImage = outputFile; + Msc m; + float f; + unsigned int w, h, row, col; + RowInfo *rowInfo = NULL; + Boolean addLines; + FILE *ismap = NULL; +#if defined(_WIN32) && !defined(__CYGWIN__) + const char *nullFile = "nul"; +#else + const char *nullFile = "/dev/null"; +#endif + Context ctx; + ctx.opts = gDefaultOpts; + + switch (format) + { + case mscgen_format_png: + outType = ADRAW_FMT_PNG; + break; + case mscgen_format_eps: + outType = ADRAW_FMT_EPS; + break; + case mscgen_format_svg: + outType = ADRAW_FMT_SVG; + break; + case mscgen_format_pngmap: + outType = ADRAW_FMT_PNG; + outImage = nullFile; + break; + case mscgen_format_svgmap: + outType = ADRAW_FMT_SVG; + outImage = nullFile; + break; + } + /* open file */ + FILE *in = fopen(inputFile, "r"); + if (!in) + { + fprintf(stderr, "Failed to open input file '%s'\n", inputFile); + return MSCGEN_FILE_ERROR; + } + /* parse file */ + m = MscParse(in); + fclose(in); + if (!m || !checkMsc(m)) + { + fprintf(stderr, "Input format error for '%s'\n", inputFile); + return MSCGEN_INPUT_FORMAT_ERROR; + } + + /* Check if an ismap file should also be generated */ + if (format==mscgen_format_pngmap || format==mscgen_format_svgmap) + { + ismap = fopen(outputFile, "w"); + if (!ismap) + { + fprintf(stderr, "Failed to open output file '%s': %s\n", outputFile, strerror(errno)); + MscFree(m); + return MSCGEN_FILE_ERROR; + } + } + + /* Open the drawing context with dummy dimensions */ + if (!ADrawOpen(10, 10, nullFile, "", outType, &ctx.drw)) + { + if (ismap) + { + fclose(ismap); + } + MscFree(m); + fprintf(stderr, "Failed to open temporary drawing context\n"); + return MSCGEN_OUTPUT_CONTEXT_ERROR; + } + + /* Now compute ideal canvas size, which may use text metrics */ + if (MscGetOptAsFloat(m, MSC_OPT_WIDTH, &f)) + { + ctx.opts.idealCanvasWidth = (unsigned int)f; + } + else if (MscGetOptAsFloat(m, MSC_OPT_HSCALE, &f)) + { + ctx.opts.idealCanvasWidth *= (unsigned int)f; + } + + /* Set the arc gradient if needed */ + if (MscGetOptAsFloat(m, MSC_OPT_ARCGRADIENT, &f)) + { + ctx.opts.arcGradient = (int)f; + ctx.opts.arcSpacing += ctx.opts.arcGradient; + } + + /* Check if word wrapping on arcs other than boxes should be used */ + MscGetOptAsBoolean(m, MSC_OPT_WORDWRAPARCS, &ctx.opts.wordWrapArcLabels); + + /* Work out the entitySpacing */ + if (ctx.opts.idealCanvasWidth / MscGetNumEntities(m) > ctx.opts.entitySpacing) + { + ctx.opts.entitySpacing = ctx.opts.idealCanvasWidth / MscGetNumEntities(m); + } + + /* Work out the entityHeadGap */ + MscResetEntityIterator(m); + for (col = 0; col < MscGetNumEntities(m); col++) + { + unsigned int lines = countLines(MscGetCurrentEntAttrib(m, MSC_ATTR_LABEL)); + unsigned int gap; + + /* Get the required gap */ + gap = lines * ctx.drw.textHeight(&ctx.drw); + if (gap > ctx.opts.entityHeadGap) + { + ctx.opts.entityHeadGap = gap; + } + + MscNextEntity(m); + } + + //printf("opts: idealCanvasWidth=%d entitySpacing=%d entityHeadGap=%d " + // "arcSpacing=%d arcGradient=%d boxSpacing=%d boxInternalBorder=%d " + // "rboxArc=%d noteCorner=%d aboxSlope=%d wordWrapArcLabels=%d arrowWidth=%d " + // "arrowHeight=%d loopArcHeight=%d textHGapPre=%d textHGapPost=%d\n", + // ctx.opts.idealCanvasWidth,ctx.opts.entitySpacing,ctx.opts.entityHeadGap, + // ctx.opts.arcSpacing,ctx.opts.arcGradient,ctx.opts.boxSpacing,ctx.opts.boxInternalBorder, + // ctx.opts.rboxArc,ctx.opts.noteCorner,ctx.opts.aboxSlope,ctx.opts.wordWrapArcLabels,ctx.opts.arrowWidth, + // ctx.opts.arrowHeight,ctx.opts.loopArcHeight,ctx.opts.textHGapPre,ctx.opts.textHGapPost); + + /* Work out the width and height of the canvas */ + rowInfo = computeCanvasSize(&ctx, m, &w , &h); + + /* Close the temporary output file */ + ctx.drw.close(&ctx.drw); + + //printf("opening canvas %d x %d for %s type=%d\n",w,h,outImage,outType); + + /* Open the output */ + if (!ADrawOpen(w, h, outImage, "", outType, &ctx.drw)) + { + free(rowInfo); + if (ismap) + { + fclose(ismap); + } + MscFree(m); + return MSCGEN_OUTPUT_CONTEXT_ERROR; + } + + /* Allocate storage for entity heading colours */ + entColourRef = malloc_s(MscGetNumEntities(m) * sizeof(ADrawColour)); + + /* Draw the entity headings */ + MscResetEntityIterator(m); + for (col = 0; col < MscGetNumEntities(m); col++) + { + unsigned int x = (ctx.opts.entitySpacing / 2) + (ctx.opts.entitySpacing * col); + const char *line; + + /* Titles */ + entityText(&ctx, ismap, + x, + ctx.opts.entityHeadGap - (ctx.drw.textHeight(&ctx.drw) / 2), + MscGetCurrentEntAttrib(m, MSC_ATTR_LABEL), + MscGetCurrentEntAttrib(m, MSC_ATTR_URL), + MscGetCurrentEntAttrib(m, MSC_ATTR_ID), + MscGetCurrentEntAttrib(m, MSC_ATTR_IDURL), + MscGetCurrentEntAttrib(m, MSC_ATTR_TEXT_COLOUR), + MscGetCurrentEntAttrib(m, MSC_ATTR_TEXT_BGCOLOUR)); + + /* Get the colours */ + line = MscGetCurrentEntAttrib(m, MSC_ATTR_LINE_COLOUR); + if (line != NULL) + { + entColourRef[col] = ADrawGetColour(line); + } + else + { + entColourRef[col] = ADRAW_COL_BLACK; + } + + MscNextEntity(m); + } + + /* Draw the arcs */ + addLines = TRUE; + row = 0; + + MscResetArcIterator(m); + do + { + const MscArcType arcType = MscGetCurrentArcType(m); + const char *arcUrl = MscGetCurrentArcAttrib(m, MSC_ATTR_URL); + const char *arcId = MscGetCurrentArcAttrib(m, MSC_ATTR_ID); + const char *arcIdUrl = MscGetCurrentArcAttrib(m, MSC_ATTR_IDURL); + const char *arcTextColour = MscGetCurrentArcAttrib(m, MSC_ATTR_TEXT_COLOUR); + const char *arcTextBgColour = MscGetCurrentArcAttrib(m, MSC_ATTR_TEXT_BGCOLOUR); + const char *arcLineColour = MscGetCurrentArcAttrib(m, MSC_ATTR_LINE_COLOUR); + const int arcGradient = isBoxArc(arcType) ? 0 : getArcGradient(&ctx, m, rowInfo, row); + const int arcHasArrows = MscGetCurrentArcAttrib(m, MSC_ATTR_NO_ARROWS) == NULL; + const int arcHasBiArrows = MscGetCurrentArcAttrib(m, MSC_ATTR_BI_ARROWS) != NULL; + char **arcLabelLines = NULL; + unsigned int arcLabelLineCount = 0; + int startCol = -1, endCol = -1; + + if (arcType == MSC_ARC_PARALLEL) + { + addLines = FALSE; + + /* Rewind the row */ + assert(row > 0); + row--; + } + else + { + const unsigned int ymin = rowInfo[row].ymin; + const unsigned int ymid = rowInfo[row].arcliney; + const unsigned int ymax = rowInfo[row].ymax; + +#if 0 + /* For debug, mark the row spacing */ + ctx.drw.line(&ctx.drw, 0, ymin, 10, ymin); + ctx.drw.line(&ctx.drw, 0, ymid, 5, ymid); + ctx.drw.line(&ctx.drw, 0, ymax, 10, ymax); +#endif + /* Get the entity indices */ + if (arcType != MSC_ARC_DISCO && arcType != MSC_ARC_DIVIDER && arcType != MSC_ARC_SPACE) + { + startCol = MscGetEntityIndex(m, MscGetCurrentArcSource(m)); + endCol = MscGetEntityIndex(m, MscGetCurrentArcDest(m)); + + /* Check that the start column is known and the end column is + * known, or that it's a broadcast arc + */ + assert(startCol != -1); + assert(endCol != -1 || isBroadcastArc(MscGetCurrentArcDest(m))); + + /* Check for entity colouring if not set explicity on the arc */ + if (arcTextColour == NULL) + { + arcTextColour = MscGetEntAttrib(m, startCol, MSC_ATTR_ARC_TEXT_COLOUR); + } + + if (arcTextBgColour == NULL) + { + arcTextBgColour = MscGetEntAttrib(m, startCol, MSC_ATTR_ARC_TEXT_BGCOLOUR); + } + + if (arcLineColour == NULL) + { + arcLineColour = MscGetEntAttrib(m, startCol, MSC_ATTR_ARC_LINE_COLOUR); + } + + } + else + { + /* Discontinuity or parallel arc spans whole chart */ + startCol = 0; + endCol = MscGetNumEntities(m) - 1; + } + + /* Work out how the label fits the gap between entities */ + arcLabelLineCount = computeLabelLines(&ctx, m, arcType, &arcLabelLines, + MscGetCurrentArcAttrib(m, MSC_ATTR_LABEL), + startCol, endCol); + + /* Check if this is a broadcast message */ + if (isBroadcastArc(MscGetCurrentArcDest(m))) + { + unsigned int t; + + /* Add in the entity lines */ + if (addLines) + { + entityLines(&ctx, m, ymin, ymax + ctx.opts.arcSpacing, FALSE, entColourRef); + } + + /* Draw arcs to each entity */ + for (t = 0; t < MscGetNumEntities(m); t++) + { + if ((signed)t != startCol) + { + arcLine(&ctx, m, ymid, arcGradient, startCol, + t, arcLineColour, arcHasArrows, + arcHasBiArrows, arcType); + } + } + + /* Fix up the start/end columns to span chart */ + startCol = 0; + endCol = MscGetNumEntities(m) - 1; + } + else + { + /* Check if it is a box, discontinuity arc etc... */ + if (isBoxArc(arcType)) + { + if (addLines) + { + entityLines(&ctx, m, ymin, ymax + ctx.opts.arcSpacing, FALSE, entColourRef); + } + arcBox(&ctx, ymin, ymax, startCol, endCol, arcType, arcLineColour, arcTextBgColour); + } + else if (arcType == MSC_ARC_DISCO) + { + if (addLines) + { + entityLines(&ctx, m, ymin, ymax + ctx.opts.arcSpacing, TRUE /* dotted */, entColourRef); + } + } + else if (arcType == MSC_ARC_DIVIDER || arcType == MSC_ARC_SPACE) + { + if (addLines) + { + entityLines(&ctx, m, ymin, ymax + ctx.opts.arcSpacing, FALSE, entColourRef); + } + + /* Dividers also have a horizontal line at the middle */ + if (arcType == MSC_ARC_DIVIDER) + { + const unsigned int margin = ctx.opts.entitySpacing / 4; + + if (arcLineColour != NULL) + { + ctx.drw.setPen(&ctx.drw, ADrawGetColour(arcLineColour)); + } + + /* Draw line through middle of text */ + ctx.drw.dottedLine(&ctx.drw, + margin, ymid, + (MscGetNumEntities(m) * ctx.opts.entitySpacing) - margin, ymid); + + if (arcLineColour != NULL) + { + ctx.drw.setPen(&ctx.drw, ADRAW_COL_BLACK); + } + } + } + else + { + if (addLines) + { + entityLines(&ctx, m, ymin, ymax + ctx.opts.arcSpacing, FALSE, entColourRef); + } + arcLine(&ctx, m, ymid, arcGradient, startCol, endCol, arcLineColour, + arcHasArrows, arcHasBiArrows, arcType); + } + } + + /* All may have text */ + if (arcLabelLineCount > 0) + { + arcText(&ctx, m, ismap, w, ymid, arcGradient, + startCol, endCol, + arcLabelLineCount, arcLabelLines, + arcUrl, arcId, arcIdUrl, + arcTextColour, arcTextBgColour, arcType); + } + + freeLabelLines(arcLabelLineCount, arcLabelLines); + + /* Advance the row */ + row++; + addLines = TRUE; + } + } while (MscNextArc(m)); + + /* Skip arcs may require the entity lines to be extended */ + entityLines(&ctx, m, + rowInfo[(MscGetNumArcs(m) - MscGetNumParallelArcs(m)) - 1].ymax, + h, FALSE, entColourRef); + + if (ismap) + { + fclose(ismap); + } + + free(entColourRef); + free(rowInfo); + MscFree(m); + /* Close the context */ + ctx.drw.close(&ctx.drw); + + return MSCGEN_OK; +} + + +const char *mscgen_error2str(int code) +{ + switch (code) + { + case MSCGEN_OK: return "OK"; + case MSCGEN_FILE_ERROR: return "FILE ERROR"; + case MSCGEN_INPUT_FORMAT_ERROR: return "INPUT FORMAT ERROR"; + case MSCGEN_OUTPUT_CONTEXT_ERROR: return "OUTPUT CONTEXT ERROR"; + default: return "UNKNOWN_ERROR"; + } +} + diff --git a/libmscgen/mscgen_api.h b/libmscgen/mscgen_api.h new file mode 100644 index 0000000..3d294a1 --- /dev/null +++ b/libmscgen/mscgen_api.h @@ -0,0 +1,41 @@ +#ifndef MSCGEN_API_H +#define MSCGEN_API_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MSCGEN_OK ( 0) +#define MSCGEN_FILE_ERROR (-1) +#define MSCGEN_INPUT_FORMAT_ERROR (-2) +#define MSCGEN_OUTPUT_CONTEXT_ERROR (-3) + +/** The supported image formats */ +typedef enum +{ + mscgen_format_png, /**< PNG bitmap image file */ + mscgen_format_eps, /**< Encapsulated PostScript file */ + mscgen_format_svg, /**< Scalable Vector Graphics file */ + mscgen_format_pngmap, /**< Image map for a bitmap file */ + mscgen_format_svgmap /**< Image map for a SVG file */ +} mscgen_format_t; + +/** generate an image file for a given .msc file. + * @param inputFile the name of the MSC file to process. + * @param outputFile the name of the image file to generate. + * @param fomat the format of the image file to generate. + * @return 0 on success, a non zero error code on failure. + */ +int mscgen_generate(const char *inputFile, + const char *outputFile, + mscgen_format_t format + ); + +/** Translates the error code returned by mscgen_generate into a string */ +const char *mscgen_error2str(int code); + +#ifdef __cplusplus +} +#endif + +#endif // MSCGEN_API_H diff --git a/libmscgen/mscgen_bool.h b/libmscgen/mscgen_bool.h new file mode 100644 index 0000000..e982d80 --- /dev/null +++ b/libmscgen/mscgen_bool.h @@ -0,0 +1,36 @@ +/*************************************************************************** + * + * $Id: bool.h 115 2010-08-19 09:58:45Z Michael.McTernan $ + * + * Boolean type for msclib. + * Copyright (C) 2009 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + ***************************************************************************/ + +#ifndef MSCGEN_BOOL_H +#define MSCGEN_BOOL_H + +typedef enum +{ + FALSE = 0, + TRUE +} +Boolean; + + +#endif /* MSCGEN_BOOL_H */ + +/* END OF FILE */ diff --git a/libmscgen/mscgen_config.h b/libmscgen/mscgen_config.h new file mode 100644 index 0000000..194b965 --- /dev/null +++ b/libmscgen/mscgen_config.h @@ -0,0 +1,55 @@ +#ifndef MSCGEN_CONFIG_H +#define MSCGEN_CONFIG_H + +#if defined(_WIN32) && !defined(__CYGWIN__) +#define M_PI 3.14159265358979323846264338327950288 +#define strcasecmp _stricmp +#define strdup _strdup +#define fileno _fileno +#define YY_NO_UNISTD_H 1 +#else +#define HAVE_UNISTD_H 1 +#endif + +/* Define to 1 if you have the <limits.h> header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the <unistd.h> header file. */ + +/* Name of package */ +#define PACKAGE "mscgen" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "Michael.McTernan.2001@cs.bris.ac.uk" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "mscgen" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "mscgen 0.20" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "mscgen" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "0.20" + +/* If set, remove PNG output support thereby removing libgd dependence. */ +//#define REMOVE_PNG_OUTPUT /**/ + +/* Define to 1 if you have the ANSI C header files. */ +//#define STDC_HEADERS 1 + +/* Use FreeType for rendering text in PNGs. */ +/* #undef USE_FREETYPE */ + +/* Version number of package */ +#define VERSION "0.20" + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +#define YYTEXT_POINTER 1 +#endif /* MSCGEN_CONFIG_H */ diff --git a/libmscgen/mscgen_gd_out.c b/libmscgen/mscgen_gd_out.c new file mode 100644 index 0000000..263431e --- /dev/null +++ b/libmscgen/mscgen_gd_out.c @@ -0,0 +1,606 @@ +/*************************************************************************** + * + * $Id: gd_out.c 186 2011-03-01 21:18:19Z Michael.McTernan $ + * + * This file is part of mscgen, a message sequence chart renderer. + * Copyright (C) 2010 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + **************************************************************************/ + +#include "mscgen_config.h" +#ifndef REMOVE_PNG_OUTPUT +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#ifdef HAVE_LIMITS_H +#include <limits.h> +#endif +#include "gd.h" +#ifndef USE_FREETYPE +#include "gdfontt.h" /* Tiny font */ +#include "gdfonts.h" /* Small font */ +#endif +#include "mscgen_adraw_int.h" +#include "mscgen_safe.h" + +/*************************************************************************** + * Manifest Constants + ***************************************************************************/ + +#define MAX_COLOURS 128 + +/*************************************************************************** + * Local types + ***************************************************************************/ + +typedef struct GdoContextTag +{ + gdImagePtr img; +#ifdef USE_FREETYPE + double fontPoints; + const char *fontName; +#else + gdFontPtr font; +#endif + + /** Array of colours and GD references. */ + struct + { + int ref; + ADrawColour col; + } + colour[MAX_COLOURS]; + + /** Number of valid references in \a colourRef[]. */ + int colourCount; + + /** The current pen for GD. */ + int pen; + + /** Background colour for rendering text. */ + int bgpen; + + FILE *outFile; +} +GdoContext; + +/*************************************************************************** + * Helper functions + ***************************************************************************/ + +/** Swap a pair of values inplace. + */ +static void swap(unsigned int *a, unsigned int *b) +{ + unsigned int x; + + x = *a; + *a = *b; + *b = x; +} + + +/** Get the context pointer from an ADraw structure. + */ +static GdoContext *getGdoCtx(struct ADrawTag *ctx) +{ + return (GdoContext *)ctx->internal; +} + + +/** Get the GD image pointer from an ADraw structure. + */ +static gdImagePtr getGdoImg(struct ADrawTag *ctx) +{ + return getGdoCtx(ctx)->img; +} + +/** Get the current GD pen index from an ADraw structure. + */ +static int getGdoPen(struct ADrawTag *ctx) +{ + return getGdoCtx(ctx)->pen; +} + + +/** Given a colour value, convert to a gd colour reference. + * This searches the current pallette of colours for the passed colour and + * returns an existing reference if possible. Otherwise a new colour reference + * is allocated and returned. + */ +static int getColourRef(GdoContext *context, ADrawColour col) +{ + int t; + + /* Check if the colour is already allocated */ + for(t = 0; t < context->colourCount; t++) + { + if(context->colour[t].col == col) + { + return context->colour[t].ref; + } + } + + /* Allocate a new colour if there is space */ + if(t < MAX_COLOURS) + { + /* Store the colour and allocate a reference */ + context->colour[t].col = col; + context->colour[t].ref = gdImageColorAllocate(context->img, + (col & 0xff0000) >> 16, + (col & 0x00ff00) >> 8, + (col & 0x0000ff) >> 0); + context->colourCount++; + + /* Return the new colour reference */ + return context->colour[t].ref; + } + else + { + /* Cannot allocate more colours, so return black by default */ + return getColourRef(context, ADRAW_COL_BLACK); + } +} + + +/** Set the dashed style. + */ +static void setStyle(struct ADrawTag *ctx) +{ + GdoContext *context = getGdoCtx(ctx); + int style[4]; + + /* Create dash pattern */ + style[0] = style[1] = context->pen; + style[2] = style[3] = getColourRef(context, ADRAW_COL_WHITE); + + gdImageSetStyle(context->img, style, 4); +} + +/*************************************************************************** + * API Functions + ***************************************************************************/ + +unsigned int gdoTextWidth(struct ADrawTag *ctx, + const char *string) +{ +#ifndef USE_FREETYPE + const unsigned int l = strlen(string); + + /* Remove 1 pixel since there is usually an uneven gap at + * the right of the last character for the fixed width + * font. + */ + return l == 0 ? 0 : (getGdoCtx(ctx)->font->w * l) - 1; +#else + GdoContext *context = getGdoCtx(ctx); + int rect[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + const char *r; + + r = gdImageStringFT(NULL, + rect, + context->pen, + (char *)context->fontName, + context->fontPoints, + 0, + 0, 0, + (char *)string); + if(r) + { + fprintf(stderr, "Error: gdoTextWidth: %s (GDFONTPATH=%s)\n", r, mscgen_getenv_s("GDFONTPATH")); + exit(EXIT_FAILURE); + } + + /* Remove 1 pixel since there is usually an uneven gap at + * the right of the last character for the fixed width + * font. + */ + return rect[2] - 1; +#endif +} + + +int gdoTextHeight(struct ADrawTag *ctx) +{ +#ifndef USE_FREETYPE + return getGdoCtx(ctx)->font->h; +#else + GdoContext *context = getGdoCtx(ctx); + int rect[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + const char *r; + + r = gdImageStringFT(NULL, + rect, + context->pen, + (char *)context->fontName, + context->fontPoints, + 0, + 0, 0, + "gHELLOWt"); + if(r) + { + fprintf(stderr, "Error: gdoTextHeight: %s (GDFONTPATH=%s)\n", r, mscgen_getenv_s("GDFONTPATH")); + exit(EXIT_FAILURE); + } + + return (-rect[5]) + 1; +#endif +} + + +void gdoLine(struct ADrawTag *ctx, + unsigned int x1, + unsigned int y1, + unsigned int x2, + unsigned int y2) +{ + /* Range check since gdImageLine() takes signed values */ + if(x1 <= INT_MAX && y1 <= INT_MAX && x2 <= INT_MAX && y2 <= INT_MAX) + { + /* Anti-aliasing fails if drawing 'backwards' for some octants */ + if(x1 > x2 && abs((int)x1 - (int)x2) > abs((int)y1 - (int)y2)) + { + swap(&x1, &x2); + swap(&y1, &y2); + } + + gdImageSetAntiAliased(getGdoImg(ctx), getGdoPen(ctx)); + gdImageLine(getGdoImg(ctx), + x1, y1, x2, y2, gdAntiAliased); + } +} + + +void gdoDottedLine(struct ADrawTag *ctx, + unsigned int x1, + unsigned int y1, + unsigned int x2, + unsigned int y2) +{ + setStyle(ctx); + + /* Range check since gdImageLine() takes signed values */ + if(x1 <= INT_MAX && y1 <= INT_MAX && x2 <= INT_MAX && y2 <= INT_MAX) + { + gdImageLine(getGdoImg(ctx), x1, y1, x2, y2, gdStyled); + } +} + + +void gdoTextR(struct ADrawTag *ctx, + unsigned int x, + unsigned int y, + const char *string) +{ + GdoContext *context = getGdoCtx(ctx); +#ifdef USE_FREETYPE + int rect[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + const char *r; +#endif + int textWidth; + + textWidth = gdoTextWidth(ctx, string); + + /* Range check since gdImageFilledRectangle() takes signed values */ + if(x + textWidth <= INT_MAX && y <= INT_MAX) + { + gdImageFilledRectangle(getGdoImg(ctx), + x, + y - (gdoTextHeight(ctx) - 2), + x + textWidth, + y - 2, + context->bgpen); + +#ifdef USE_FREETYPE + r = gdImageStringFT(getGdoImg(ctx), + rect, + context->pen, + (char *)context->fontName, + context->fontPoints, + 0, + x, y - 2, + (char *)string); + + if(r) + { + fprintf(stderr, "Error: gdoTextR: %s (GDFONTPATH=%s)\n", r, mscgen_getenv_s("GDFONTPATH")); + exit(EXIT_FAILURE); + } +#else + gdImageString(getGdoImg(ctx), + getGdoCtx(ctx)->font, + x, + y - gdoTextHeight(ctx), + (unsigned char *)string, + getGdoPen(ctx)); +#endif + } + +} + + +void gdoTextL(struct ADrawTag *ctx, + unsigned int x, + unsigned int y, + const char *string) +{ + x -= gdoTextWidth(ctx, string); + + /* Range check since gdImageFilledRectangle() takes signed values */ + if(x <= INT_MAX && y <= INT_MAX) + { + gdoTextR(ctx, x, y, string); + } +} + +void gdoTextC(struct ADrawTag *ctx, + unsigned int x, + unsigned int y, + const char *string) +{ + gdoTextR(ctx, x - (gdoTextWidth(ctx, string) / 2), y, string); +} + +void gdoFilledRectangle(struct ADrawTag *ctx, + unsigned int x1, + unsigned int y1, + unsigned int x2, + unsigned int y2) +{ + gdPoint p[4]; + + /* Range check since gdPoint contains signed values */ + if(x1 <= INT_MAX && y1 <= INT_MAX && x2 <= INT_MAX && y2 <= INT_MAX) + { + p[0].x = x1; p[0].y = y1; + p[1].x = x2; p[1].y = y1; + p[2].x = x2; p[2].y = y2; + p[3].x = x1; p[3].y = y2; + + + gdImageFilledPolygon(getGdoImg(ctx), p, 4, getGdoPen(ctx)); + } +} + +void gdoFilledTriangle(struct ADrawTag *ctx, + unsigned int x1, + unsigned int y1, + unsigned int x2, + unsigned int y2, + unsigned int x3, + unsigned int y3) +{ + gdPoint p[3]; + + /* Range check since gdPoint contains signed values */ + if(x1 <= INT_MAX && y1 <= INT_MAX && + x2 <= INT_MAX && y2 <= INT_MAX && + x3 <= INT_MAX && y3 <= INT_MAX) + { + p[0].x = x1; p[0].y = y1; + p[1].x = x2; p[1].y = y2; + p[2].x = x3; p[2].y = y3; + + gdImageSetAntiAliased(getGdoImg(ctx), getGdoPen(ctx)); + gdImageFilledPolygon(getGdoImg(ctx), p, 3, gdAntiAliased); + } +} + + +void gdoFilledCircle(struct ADrawTag *ctx, + unsigned int x, + unsigned int y, + unsigned int r) +{ + gdImageSetAntiAliased(getGdoImg(ctx), getGdoPen(ctx)); + gdImageFilledEllipse(getGdoImg(ctx), x, y, r * 2, r * 2, gdAntiAliased); +} + + +void gdoArc(struct ADrawTag *ctx, + unsigned int cx, + unsigned int cy, + unsigned int w, + unsigned int h, + unsigned int s, + unsigned int e) +{ + + /* Range check since gdImageArc takes signed values */ + if(cx <= INT_MAX && cy <= INT_MAX) + { + gdImageArc(getGdoImg(ctx), cx, cy, w, h, s, e, getGdoPen(ctx)); + } +} + + +void gdoDottedArc(struct ADrawTag *ctx, + unsigned int cx, + unsigned int cy, + unsigned int w, + unsigned int h, + unsigned int s, + unsigned int e) +{ + /* Range check since gdImageArc takes signed values */ + if(cx <= INT_MAX && cy <= INT_MAX) + { + setStyle(ctx); + gdImageArc(getGdoImg(ctx), cx, cy, w, h, s, e, gdStyled); + } +} + + +void gdoSetPen(struct ADrawTag *ctx, + ADrawColour col) +{ + GdoContext *context = getGdoCtx(ctx);; + + context->pen = getColourRef(context, col); +} + + +void gdoSetBgPen(struct ADrawTag *ctx, + ADrawColour col) +{ + GdoContext *context = getGdoCtx(ctx);; + + context->bgpen = getColourRef(context, col); +} + + +void gdoSetFontSize(struct ADrawTag *ctx, + ADrawFontSize size) +{ + switch(size) + { +#ifdef USE_FREETYPE + case ADRAW_FONT_TINY: + getGdoCtx(ctx)->fontPoints = 9.0; + break; + + case ADRAW_FONT_SMALL: + getGdoCtx(ctx)->fontPoints = 11.0; + break; +#else + case ADRAW_FONT_TINY: + getGdoCtx(ctx)->font = gdFontGetTiny(); + break; + + case ADRAW_FONT_SMALL: + getGdoCtx(ctx)->font = gdFontGetSmall(); + break; +#endif + default: + assert(0); + } +} + + +Boolean gdoClose(struct ADrawTag *ctx) +{ + GdoContext *context = getGdoCtx(ctx); + + /* Output the image to the disk file in PNG format. */ + gdImagePng(getGdoImg(ctx), context->outFile); + if(context->outFile != stdout) + { + fclose(context->outFile); + } + + /* Destroy the image in memory */ + gdImageDestroy(context->img); + + /* Free and destroy context */ + free(context); + ctx->internal = NULL; + + return TRUE; +} + + + +Boolean GdoInit(unsigned int w, + unsigned int h, + const char *file, + const char *fontName UNUSED, + struct ADrawTag *outContext) +{ + GdoContext *context; + + /* Range check the size */ + if(w > INT_MAX || h > INT_MAX) + { + fprintf(stderr, "Warning: The output image size larger than can be supported for png; output\n" + " will be clipped.\n"); + } + + /* Clip image size to limits */ + if(w > INT_MAX) w = INT_MAX; + if(h > INT_MAX) h = INT_MAX; + + /* Create context */ + context = outContext->internal = zalloc_s(sizeof(GdoContext)); + if(context == NULL) + { + return FALSE; + } + + /* Open the output file */ + if(strcmp(file, "-") == 0) + { + context->outFile = stdout; + } + else + { + context->outFile = fopen(file, "wb"); + if(!context->outFile) + { + fprintf(stderr, "GdoInit: Failed to open output file '%s': %s\n", file, strerror(errno)); + return FALSE; + } + } + +#ifdef USE_FREETYPE + /* Request that we use font config strings and store font name */ + gdFTUseFontConfig(1); + context->fontName = fontName; + + assert(fontName != NULL); +#endif + + /* Allocate the image */ + context->img = gdImageCreateTrueColor(w, h); + + /* Allocate first colour and clear background */ + gdImageFilledRectangle(context->img, + 0, 0, + w, h, + getColourRef(context, ADRAW_COL_WHITE)); + + /* Set pen colour to black and background to white */ + context->pen = getColourRef(context, ADRAW_COL_BLACK); + context->bgpen = getColourRef(context, ADRAW_COL_WHITE); + + /* Get the default font size */ + gdoSetFontSize(outContext, ADRAW_FONT_SMALL); + + /* Now fill in the function pointers */ + outContext->line = gdoLine; + outContext->dottedLine = gdoDottedLine; + outContext->textL = gdoTextL; + outContext->textC = gdoTextC; + outContext->textR = gdoTextR; + outContext->textWidth = gdoTextWidth; + outContext->textHeight = gdoTextHeight; + outContext->filledRectangle = gdoFilledRectangle; + outContext->filledTriangle = gdoFilledTriangle; + outContext->filledCircle = gdoFilledCircle; + outContext->arc = gdoArc; + outContext->dottedArc = gdoDottedArc; + outContext->setPen = gdoSetPen; + outContext->setBgPen = gdoSetBgPen; + outContext->setFontSize = gdoSetFontSize; + outContext->close = gdoClose; + + return TRUE; +} + +#endif /* REMOVE_PNG_OUTPUT */ + +/* END OF FILE */ diff --git a/libmscgen/mscgen_language.h b/libmscgen/mscgen_language.h new file mode 100644 index 0000000..4f401a6 --- /dev/null +++ b/libmscgen/mscgen_language.h @@ -0,0 +1,186 @@ + +/* A Bison parser, made by GNU Bison 2.4.1. */ + +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + TOK_STRING = 258, + TOK_QSTRING = 259, + TOK_EQUAL = 260, + TOK_COMMA = 261, + TOK_SEMICOLON = 262, + TOK_OCBRACKET = 263, + TOK_CCBRACKET = 264, + TOK_OSBRACKET = 265, + TOK_CSBRACKET = 266, + TOK_MSC = 267, + TOK_ATTR_LABEL = 268, + TOK_ATTR_URL = 269, + TOK_ATTR_ID = 270, + TOK_ATTR_IDURL = 271, + TOK_ATTR_LINE_COLOUR = 272, + TOK_ATTR_TEXT_COLOUR = 273, + TOK_ATTR_TEXT_BGCOLOUR = 274, + TOK_ATTR_ARC_LINE_COLOUR = 275, + TOK_ATTR_ARC_TEXT_COLOUR = 276, + TOK_ATTR_ARC_TEXT_BGCOLOUR = 277, + TOK_REL_LOSS_TO = 278, + TOK_REL_LOSS_FROM = 279, + TOK_REL_SIG_BI = 280, + TOK_REL_SIG_TO = 281, + TOK_REL_SIG_FROM = 282, + TOK_REL_METHOD_BI = 283, + TOK_REL_METHOD_TO = 284, + TOK_REL_METHOD_FROM = 285, + TOK_REL_RETVAL_BI = 286, + TOK_REL_RETVAL_TO = 287, + TOK_REL_RETVAL_FROM = 288, + TOK_REL_DOUBLE_BI = 289, + TOK_REL_DOUBLE_TO = 290, + TOK_REL_DOUBLE_FROM = 291, + TOK_REL_CALLBACK_BI = 292, + TOK_REL_CALLBACK_TO = 293, + TOK_REL_CALLBACK_FROM = 294, + TOK_REL_BOX = 295, + TOK_REL_ABOX = 296, + TOK_REL_RBOX = 297, + TOK_REL_NOTE = 298, + TOK_SPECIAL_ARC = 299, + TOK_OPT_HSCALE = 300, + TOK_OPT_WIDTH = 301, + TOK_OPT_ARCGRADIENT = 302, + TOK_OPT_WORDWRAPARCS = 303, + TOK_ASTERISK = 304, + TOK_UNKNOWN = 305, + TOK_REL_SIG = 306, + TOK_REL_METHOD = 307, + TOK_REL_RETVAL = 308, + TOK_REL_DOUBLE = 309, + TOK_ATTR_ARC_SKIP = 310 + }; +#endif +/* Tokens. */ +#define TOK_STRING 258 +#define TOK_QSTRING 259 +#define TOK_EQUAL 260 +#define TOK_COMMA 261 +#define TOK_SEMICOLON 262 +#define TOK_OCBRACKET 263 +#define TOK_CCBRACKET 264 +#define TOK_OSBRACKET 265 +#define TOK_CSBRACKET 266 +#define TOK_MSC 267 +#define TOK_ATTR_LABEL 268 +#define TOK_ATTR_URL 269 +#define TOK_ATTR_ID 270 +#define TOK_ATTR_IDURL 271 +#define TOK_ATTR_LINE_COLOUR 272 +#define TOK_ATTR_TEXT_COLOUR 273 +#define TOK_ATTR_TEXT_BGCOLOUR 274 +#define TOK_ATTR_ARC_LINE_COLOUR 275 +#define TOK_ATTR_ARC_TEXT_COLOUR 276 +#define TOK_ATTR_ARC_TEXT_BGCOLOUR 277 +#define TOK_REL_LOSS_TO 278 +#define TOK_REL_LOSS_FROM 279 +#define TOK_REL_SIG_BI 280 +#define TOK_REL_SIG_TO 281 +#define TOK_REL_SIG_FROM 282 +#define TOK_REL_METHOD_BI 283 +#define TOK_REL_METHOD_TO 284 +#define TOK_REL_METHOD_FROM 285 +#define TOK_REL_RETVAL_BI 286 +#define TOK_REL_RETVAL_TO 287 +#define TOK_REL_RETVAL_FROM 288 +#define TOK_REL_DOUBLE_BI 289 +#define TOK_REL_DOUBLE_TO 290 +#define TOK_REL_DOUBLE_FROM 291 +#define TOK_REL_CALLBACK_BI 292 +#define TOK_REL_CALLBACK_TO 293 +#define TOK_REL_CALLBACK_FROM 294 +#define TOK_REL_BOX 295 +#define TOK_REL_ABOX 296 +#define TOK_REL_RBOX 297 +#define TOK_REL_NOTE 298 +#define TOK_SPECIAL_ARC 299 +#define TOK_OPT_HSCALE 300 +#define TOK_OPT_WIDTH 301 +#define TOK_OPT_ARCGRADIENT 302 +#define TOK_OPT_WORDWRAPARCS 303 +#define TOK_ASTERISK 304 +#define TOK_UNKNOWN 305 +#define TOK_REL_SIG 306 +#define TOK_REL_METHOD 307 +#define TOK_REL_RETVAL 308 +#define TOK_REL_DOUBLE 309 +#define TOK_ATTR_ARC_SKIP 310 + + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + +/* Line 1676 of yacc.c */ +#line 248 "language.y" + + char *string; + Msc msc; + MscOpt opt; + MscOptType optType; + MscArc arc; + MscArcList arclist; + MscArcType arctype; + MscEntity entity; + MscEntityList entitylist; + MscAttrib attrib; + MscAttribType attribType; + + + +/* Line 1676 of yacc.c */ +#line 178 "language.h" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + +extern YYSTYPE yylval; + + diff --git a/libmscgen/mscgen_language.y b/libmscgen/mscgen_language.y new file mode 100644 index 0000000..0c0ab50 --- /dev/null +++ b/libmscgen/mscgen_language.y @@ -0,0 +1,430 @@ +%{ +/*************************************************************************** + * + * $Id: language.y 175 2011-02-06 21:07:43Z Michael.McTernan $ + * + * Grammar and parser for the mscgen language. + * Copyright (C) 2009 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk + * + * This file is part of msclib. + * + * Msc is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * Msclib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Foobar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + ***************************************************************************/ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include "mscgen_lexer.h" +#include "mscgen_safe.h" +#include "mscgen_msc.h" + +/* Lexer prototypes to prevent compiler warnings */ +int yylex(void); +int yylex_destroy(void); + +/* Use verbose error reporting such that the expected token names are dumped */ +#define YYERROR_VERBOSE + +/* Name of parameter that is passed to yyparse() */ +#define YYPARSE_PARAM yyparse_result + +#define YYMALLOC malloc_s + +/* yyerror + * Error handling function. The TOK_XXX names are substituted for more + * understandable values that make more sense to the user. + */ +void yyerror(void *unused, const char *str) +{ + static const char *tokNames[] = { "TOK_OCBRACKET", "TOK_CCBRACKET", + "TOK_OSBRACKET", "TOK_CSBRACKET", + "TOK_REL_DOUBLE_TO", "TOK_REL_DOUBLE_FROM", + "TOK_REL_SIG_TO", "TOK_REL_SIG_FROM", + "TOK_REL_METHOD_TO", "TOK_REL_METHOD_FROM", + "TOK_REL_RETVAL_TO", "TOK_REL_RETVAL_FROM", + "TOK_REL_CALLBACK_TO", "TOK_REL_CALLBACK_FROM", + "TOK_REL_SIG", "TOK_REL_METHOD", + "TOK_REL_RETVAL", "TOK_REL_DOUBLE", + "TOK_EQUAL", "TOK_COMMA", + "TOK_SEMICOLON", "TOK_MSC", + "TOK_ATTR_LABEL", "TOK_ATTR_URL", + "TOK_ATTR_IDURL", "TOK_ATTR_ID", + "TOK_ATTR_LINE_COLOUR", "TOK_ATTR_TEXT_COLOUR", + "TOK_SPECIAL_ARC", "TOK_UNKNOWN", + "TOK_STRING", "TOK_QSTRING", + "TOK_OPT_HSCALE", "TOK_ASTERISK", + "TOK_OPT_WIDTH", "TOK_ARC_BOX", + "TOK_ARC_ABOX", "TOK_ARC_RBOX", + "TOK_ATTR_TEXT_BGCOLOUR", "TOK_ATTR_ARC_TEXT_BGCOLOUR", + "TOK_REL_LOSS_TO", "TOK_REL_LOSS_FROM", + "TOK_OPT_ARCGRADIENT", "TOK_ATTR_ARC_SKIP", + "TOK_OPT_WORDWRAPARCS", "TOK_REL_NOTE" }; + + static const char *tokRepl[] = { "'{'", "'}'", + "'['", "']'", + "':>'", "'<:'", + "'->'", "'<-'", + "'=>'", "'<='", + "'>>'", "'<<'", + "'=>>'", "'<<='", + "'--'", "'=='", + "'..'", "'::'", + "'='", "','", + "';'", "'msc'", + "'label'", "'url'", + "'idurl'", "'id'", + "'linecolour'", "'textcolour'", + "'...', '---'", "characters", + "'string'", "'quoted string'", + "'hscale'", "'*'", + "'width'", "'box'", + "'abox'", "'rbox'", + "'textbgcolour'", "'arctextbgcolor'", + "'-x'", "'x-'", + "'arcgradient'", "'arcskip'", + "'wordwraparcs'", "'note'" }; + + static const int tokArrayLen = sizeof(tokNames) / sizeof(char *); + + char *s, *line; + int t; + + /* Print standard message part */ + fprintf(stderr, "Error detected at line %lu: ", lex_getlinenum()); + + /* Search for TOK */ + s = (char *)strstr(str, "TOK_"); + while(s != NULL) + { + int found = 0; + + /* Print out message until start of the token is found */ + while(str < s) + { + fprintf(stderr, "%c", *str); + str++; + } + + /* Look for the token name */ + for(t = 0; t < tokArrayLen && !found; t++) + { + if(strncmp(tokNames[t], str, strlen(tokNames[t])) == 0) + { + /* Dump the replacement string */ + fprintf(stderr, "%s", tokRepl[t]); + + /* Skip the token name */ + str += strlen(tokNames[t]); + + /* Exit the loop */ + found = 1; + } + } + + /* Check if a replacement was found */ + if(!found) + { + /* Dump the next char and skip it so that TOK doesn't match again */ + fprintf(stderr, "%c", *str); + str++; + } + + s = (char *)strstr(str, "TOK_"); + } + + fprintf(stderr, "%s.\n", str); + + line = lex_getline(); + if(line != NULL) + { + fprintf(stderr, "> %s\n", line); + + /* If the input line contains a 'lost arc', print a helpful note since + * without whitespace, this can confuse the lexer. + */ + if(strstr(line, "x-") != NULL) + { + fprintf(stderr, "\nNote: This input line contains 'x-' which has special meaning as a \n" + " 'lost message' arc, but may not have been recognised as such if it\n" + " is preceded by other letters or numbers. Please use double-quoted\n" + " strings for tokens before 'x-', or insert a preceding whitespace if\n" + " this is what you intend.\n"); + } + } + else + { + fprintf(stderr, ".\n"); + } +} + +int yywrap() +{ + return 1; +} + + +char *removeEscapes(char *in) +{ + const uint16_t l = strlen(in); + char *r = (char *)malloc_s(l + 1); + uint16_t t, u; + + for(t = u = 0; t < l; t++) + { + r[u] = in[t]; + if(in[t] != '\\' || in[t + 1] != '\"') + { + u++; + } + } + + r[u] = '\0'; + + free(in); + + return r; +} + +extern FILE *yyin; +extern int yyparse (void *YYPARSE_PARAM); + + +Msc MscParse(FILE *in) +{ + Msc m; + + yyin = in; + + /* Parse, and check that no errors are found */ + if(yyparse((void *)&m) != 0) + { + m = NULL; + } + + lex_destroy(); + yylex_destroy(); + + return m; +} + + +%} + +%parse-param {void *YYPARSE_PARAM} + +%token TOK_STRING TOK_QSTRING TOK_EQUAL TOK_COMMA TOK_SEMICOLON TOK_OCBRACKET TOK_CCBRACKET + TOK_OSBRACKET TOK_CSBRACKET TOK_MSC + TOK_ATTR_LABEL TOK_ATTR_URL TOK_ATTR_ID TOK_ATTR_IDURL + TOK_ATTR_LINE_COLOUR TOK_ATTR_TEXT_COLOUR TOK_ATTR_TEXT_BGCOLOUR + TOK_ATTR_ARC_LINE_COLOUR TOK_ATTR_ARC_TEXT_COLOUR TOK_ATTR_ARC_TEXT_BGCOLOUR + TOK_REL_LOSS_TO TOK_REL_LOSS_FROM + TOK_REL_SIG_BI TOK_REL_SIG_TO TOK_REL_SIG_FROM + TOK_REL_METHOD_BI TOK_REL_METHOD_TO TOK_REL_METHOD_FROM + TOK_REL_RETVAL_BI TOK_REL_RETVAL_TO TOK_REL_RETVAL_FROM + TOK_REL_DOUBLE_BI TOK_REL_DOUBLE_TO TOK_REL_DOUBLE_FROM + TOK_REL_CALLBACK_BI TOK_REL_CALLBACK_TO TOK_REL_CALLBACK_FROM + TOK_REL_BOX TOK_REL_ABOX + TOK_REL_RBOX TOK_REL_NOTE + TOK_SPECIAL_ARC TOK_OPT_HSCALE + TOK_OPT_WIDTH TOK_OPT_ARCGRADIENT + TOK_OPT_WORDWRAPARCS + TOK_ASTERISK TOK_UNKNOWN + TOK_REL_SIG TOK_REL_METHOD TOK_REL_RETVAL TOK_REL_DOUBLE + TOK_ATTR_ARC_SKIP + +%union +{ + char *string; + Msc msc; + MscOpt opt; + MscOptType optType; + MscArc arc; + MscArcList arclist; + MscArcType arctype; + MscEntity entity; + MscEntityList entitylist; + MscAttrib attrib; + MscAttribType attribType; +}; + +%type <msc> msc +%type <opt> optlist opt +%type <optType> optval TOK_OPT_HSCALE TOK_OPT_WIDTH TOK_OPT_ARCGRADIENT TOK_OPT_WORDWRAPARCS +%type <arc> arc arcrel +%type <arclist> arclist +%type <entity> entity +%type <entitylist> entitylist +%type <arctype> relation_box relation_line relation_bi relation_to relation_from + TOK_REL_SIG_BI TOK_REL_METHOD_BI TOK_REL_RETVAL_BI TOK_REL_CALLBACK_BI + TOK_REL_SIG_TO TOK_REL_METHOD_TO TOK_REL_RETVAL_TO TOK_REL_CALLBACK_TO TOK_REL_DOUBLE_BI + TOK_REL_SIG_FROM TOK_REL_METHOD_FROM TOK_REL_RETVAL_FROM TOK_REL_CALLBACK_FROM + TOK_REL_DOUBLE_TO TOK_REL_DOUBLE_FROM + TOK_REL_LOSS_TO TOK_REL_LOSS_FROM + TOK_SPECIAL_ARC TOK_REL_BOX TOK_REL_ABOX TOK_REL_RBOX TOK_REL_NOTE + TOK_REL_SIG TOK_REL_METHOD TOK_REL_RETVAL TOK_REL_DOUBLE +%type <attrib> attrlist attr +%type <attribType> attrval + TOK_ATTR_LABEL TOK_ATTR_URL TOK_ATTR_ID TOK_ATTR_IDURL + TOK_ATTR_LINE_COLOUR TOK_ATTR_TEXT_COLOUR TOK_ATTR_TEXT_BGCOLOUR + TOK_ATTR_ARC_LINE_COLOUR TOK_ATTR_ARC_TEXT_COLOUR TOK_ATTR_ARC_TEXT_BGCOLOUR + TOK_ATTR_ARC_SKIP +%type <string> string TOK_STRING TOK_QSTRING + + +%% +msc: TOK_MSC TOK_OCBRACKET optlist TOK_SEMICOLON entitylist TOK_SEMICOLON arclist TOK_SEMICOLON TOK_CCBRACKET +{ + $$ = MscAlloc($3, $5, $7); + *(Msc *)yyparse_result = $$; + +} + | TOK_MSC TOK_OCBRACKET entitylist TOK_SEMICOLON arclist TOK_SEMICOLON TOK_CCBRACKET +{ + $$ = MscAlloc(NULL, $3, $5); + *(Msc *)yyparse_result = $$; + +}; + +optlist: opt + | optlist TOK_COMMA opt +{ + $$ = MscLinkOpt($1, $3); +}; + +opt: optval TOK_EQUAL string +{ + $$ = MscAllocOpt($1, $3); +}; + +optval: TOK_OPT_HSCALE | TOK_OPT_WIDTH | TOK_OPT_ARCGRADIENT | TOK_OPT_WORDWRAPARCS; + +entitylist: entity +{ + $$ = MscLinkEntity(NULL, $1); /* Create new list */ +} + | entitylist TOK_COMMA entity +{ + $$ = MscLinkEntity($1, $3); /* Add to existing list */ +}; + + + +entity: string +{ + $$ = MscAllocEntity($1); +} + | entity TOK_OSBRACKET attrlist TOK_CSBRACKET +{ + MscEntityLinkAttrib($1, $3); +} +; + +arclist: arc +{ + $$ = MscLinkArc(NULL, $1); /* Create new list */ +} + | arclist TOK_SEMICOLON arc +{ + $$ = MscLinkArc($1, $3); /* Add to existing list */ +} + | arclist TOK_COMMA arc +{ + /* Add a special 'parallel' arc */ + $$ = MscLinkArc(MscLinkArc($1, MscAllocArc(NULL, NULL, MSC_ARC_PARALLEL, lex_getlinenum())), $3); +}; +; + + + +arc: arcrel TOK_OSBRACKET attrlist TOK_CSBRACKET +{ + MscArcLinkAttrib($1, $3); +} + | arcrel; + +arcrel: TOK_SPECIAL_ARC +{ + $$ = MscAllocArc(NULL, NULL, $1, lex_getlinenum()); +} + | string relation_box string +{ + $$ = MscAllocArc($1, $3, $2, lex_getlinenum()); +} + | string relation_bi string +{ + MscArc arc = MscAllocArc($1, $3, $2, lex_getlinenum()); + MscArcLinkAttrib(arc, MscAllocAttrib(MSC_ATTR_BI_ARROWS, strdup_s("true"))); + $$ = arc; +} + | string relation_to string +{ + $$ = MscAllocArc($1, $3, $2, lex_getlinenum()); +} + | string relation_line string +{ + MscArc arc = MscAllocArc($1, $3, $2, lex_getlinenum()); + MscArcLinkAttrib(arc, MscAllocAttrib(MSC_ATTR_NO_ARROWS, strdup_s("true"))); + $$ = arc; +} + | string relation_from string +{ + $$ = MscAllocArc($3, $1, $2, lex_getlinenum()); +} + | string relation_to TOK_ASTERISK +{ + $$ = MscAllocArc($1, strdup_s("*"), $2, lex_getlinenum()); +} + | TOK_ASTERISK relation_from string +{ + $$ = MscAllocArc($3, strdup_s("*"), $2, lex_getlinenum()); +}; + +relation_box: TOK_REL_BOX | TOK_REL_ABOX | TOK_REL_RBOX | TOK_REL_NOTE; +relation_line: TOK_REL_SIG | TOK_REL_METHOD | TOK_REL_RETVAL | TOK_REL_DOUBLE; +relation_bi: TOK_REL_SIG_BI | TOK_REL_METHOD_BI | TOK_REL_RETVAL_BI | TOK_REL_CALLBACK_BI | TOK_REL_DOUBLE_BI; +relation_to: TOK_REL_SIG_TO | TOK_REL_METHOD_TO | TOK_REL_RETVAL_TO | TOK_REL_CALLBACK_TO | TOK_REL_DOUBLE_TO | TOK_REL_LOSS_TO; +relation_from: TOK_REL_SIG_FROM | TOK_REL_METHOD_FROM | TOK_REL_RETVAL_FROM | TOK_REL_CALLBACK_FROM | TOK_REL_DOUBLE_FROM | TOK_REL_LOSS_FROM; + +attrlist: attr + | attrlist TOK_COMMA attr +{ + $$ = MscLinkAttrib($1, $3); +}; + +attr: attrval TOK_EQUAL string +{ + $$ = MscAllocAttrib($1, $3); +}; + +attrval: TOK_ATTR_LABEL | TOK_ATTR_URL | TOK_ATTR_ID | TOK_ATTR_IDURL | + TOK_ATTR_LINE_COLOUR | TOK_ATTR_TEXT_COLOUR | TOK_ATTR_TEXT_BGCOLOUR | + TOK_ATTR_ARC_LINE_COLOUR | TOK_ATTR_ARC_TEXT_COLOUR | TOK_ATTR_ARC_TEXT_BGCOLOUR | + TOK_ATTR_ARC_SKIP; + + +string: TOK_QSTRING +{ + $$ = removeEscapes($1); +} + | TOK_STRING +{ + $$ = $1; +}; +%% + + +/* END OF FILE */ diff --git a/libmscgen/mscgen_lexer.h b/libmscgen/mscgen_lexer.h new file mode 100644 index 0000000..0cbb21f --- /dev/null +++ b/libmscgen/mscgen_lexer.h @@ -0,0 +1,62 @@ +/*************************************************************************** + * + * $Id: lexer.h 152 2010-10-10 14:17:37Z Michael.McTernan $ + * + * Extra lexer/scanner API functions. + * Copyright (C) 2010 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + ***************************************************************************/ + +#ifndef MSCGEN_LEXER_H +#define MSCGEN_LEXER_H + +/***************************************************************************** + * Header Files + *****************************************************************************/ + +#include "mscgen_bool.h" + +/***************************************************************************** + * Preprocessor Macros & Constants + *****************************************************************************/ + +/***************************************************************************** + * Typedefs + *****************************************************************************/ + +/***************************************************************************** + * Global Variable Declarations + *****************************************************************************/ + +/***************************************************************************** + * Global Function Declarations + *****************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif +Boolean lex_getutf8(void); +#ifdef __cplusplus +} +#endif + +unsigned long lex_getlinenum(void); +char *lex_getline(void); +void lex_destroy(void); + +#endif /* MSCGEN_LEXER_H */ + +/* END OF FILE */ diff --git a/libmscgen/mscgen_lexer.l b/libmscgen/mscgen_lexer.l new file mode 100644 index 0000000..29d6aea --- /dev/null +++ b/libmscgen/mscgen_lexer.l @@ -0,0 +1,236 @@ +%{ +/*************************************************************************** + * + * $Id: lexer.l 184 2011-02-28 21:38:28Z Michael.McTernan $ + * + * Mscgen language lexer definition. + * Copyright (C) 2009 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk + * + * This file is part of msclib. + * + * Msc is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * Msclib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with msclib; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + ***************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include "mscgen_config.h" +#include "mscgen_msc.h" +#include "mscgen_bool.h" +#include "mscgen_safe.h" +#include "mscgen_lexer.h" +#include "mscgen_language.h" /* Token definitions from Yacc/Bison */ +/* Counter for error reporting */ +static unsigned long lex_linenum = 1; +static char *lex_line = NULL; +static Boolean lex_utf8 = FALSE; + +/* Local function prototypes */ +static void newline(const char *text, unsigned int n); +static char *trimQstring(char *s); + +%} + +/* Not used, so prevent compiler warning */ +%option never-interactive +%option noinput +%option noyywrap + +%x IN_COMMENT BODY +%% + +<INITIAL>{ +\xef\xbb\xbf lex_utf8 = TRUE; BEGIN(BODY); +(\r\n).* newline(yytext, 2); BEGIN(BODY); +(\r|\n).* newline(yytext, 1); BEGIN(BODY); +. unput(yytext[0]); BEGIN(BODY); +} + +<IN_COMMENT>{ +"*/" BEGIN(BODY); +[^*\n]+ +"*" +(\r\n).* newline(yytext, 2); +(\r|\n).* newline(yytext, 1); +} + +<BODY>{ + +"/*" BEGIN(IN_COMMENT); + +(\r\n).* newline(yytext, 2); +(\r|\n).* newline(yytext, 1); + +#.*$ /* Ignore lines after '#' */ +\/\/.*$ /* Ignore lines after '//' */ + +msc return TOK_MSC; +HSCALE|hscale yylval.optType = MSC_OPT_HSCALE; return TOK_OPT_HSCALE; +WIDTH|width yylval.optType = MSC_OPT_WIDTH; return TOK_OPT_WIDTH; +ARCGRADIENT|arcgradient yylval.optType = MSC_OPT_ARCGRADIENT; return TOK_OPT_ARCGRADIENT; +WORDWRAPARCS|wordwraparcs yylval.optType = MSC_OPT_WORDWRAPARCS; return TOK_OPT_WORDWRAPARCS; +URL|url yylval.attribType = MSC_ATTR_URL; return TOK_ATTR_URL; +LABEL|label yylval.attribType = MSC_ATTR_LABEL; return TOK_ATTR_LABEL; +IDURL|idurl yylval.attribType = MSC_ATTR_IDURL; return TOK_ATTR_IDURL; +ID|id yylval.attribType = MSC_ATTR_ID; return TOK_ATTR_ID; +LINECOLO(U?)R|linecolo(u?)r yylval.attribType = MSC_ATTR_LINE_COLOUR; return TOK_ATTR_LINE_COLOUR; +TEXTCOLO(U?)R|textcolo(u?)r yylval.attribType = MSC_ATTR_TEXT_COLOUR; return TOK_ATTR_TEXT_COLOUR; +TEXTBGCOLO(U?)R|textbgcolo(u?)r yylval.attribType = MSC_ATTR_TEXT_BGCOLOUR; return TOK_ATTR_TEXT_BGCOLOUR; +ARCLINECOLO(U?)R|arclinecolo(u?)r yylval.attribType = MSC_ATTR_ARC_LINE_COLOUR; return TOK_ATTR_ARC_LINE_COLOUR; +ARCTEXTCOLO(U?)R|arctextcolo(u?)r yylval.attribType = MSC_ATTR_ARC_TEXT_COLOUR; return TOK_ATTR_ARC_TEXT_COLOUR; +ARCTEXTBGCOLO(U?)R|arctextbgcolo(u?)r yylval.attribType = MSC_ATTR_ARC_TEXT_BGCOLOUR; return TOK_ATTR_ARC_TEXT_BGCOLOUR; +ARCSKIP|arcskip yylval.attribType = MSC_ATTR_ARC_SKIP; return TOK_ATTR_ARC_SKIP; +\.\.\. yylval.arctype = MSC_ARC_DISCO; return TOK_SPECIAL_ARC; /* ... */ +--- yylval.arctype = MSC_ARC_DIVIDER; return TOK_SPECIAL_ARC; /* --- */ +\|\|\| yylval.arctype = MSC_ARC_SPACE; return TOK_SPECIAL_ARC; /* ||| */ +\<-\> yylval.arctype = MSC_ARC_SIGNAL; return TOK_REL_SIG_BI; /* <-> */ +-\> yylval.arctype = MSC_ARC_SIGNAL; return TOK_REL_SIG_TO; /* -> */ +\<- yylval.arctype = MSC_ARC_SIGNAL; return TOK_REL_SIG_FROM; /* <- */ +-- yylval.arctype = MSC_ARC_SIGNAL; return TOK_REL_SIG; /* -- */ +-[Xx] yylval.arctype = MSC_ARC_LOSS; return TOK_REL_LOSS_TO; /* -x */ +[Xx]- yylval.arctype = MSC_ARC_LOSS; return TOK_REL_LOSS_FROM; /* x- */ +\<=\> yylval.arctype = MSC_ARC_METHOD; return TOK_REL_METHOD_BI; /* <=> */ +=\> yylval.arctype = MSC_ARC_METHOD; return TOK_REL_METHOD_TO; /* => */ +\<= yylval.arctype = MSC_ARC_METHOD; return TOK_REL_METHOD_FROM; /* <= */ +== yylval.arctype = MSC_ARC_METHOD; return TOK_REL_METHOD; /* == */ +\<\<\>\> yylval.arctype = MSC_ARC_RETVAL; return TOK_REL_RETVAL_BI; /* <<>> */ +\>\> yylval.arctype = MSC_ARC_RETVAL; return TOK_REL_RETVAL_TO; /* >> */ +\<\< yylval.arctype = MSC_ARC_RETVAL; return TOK_REL_RETVAL_FROM; /* << */ +\.\. yylval.arctype = MSC_ARC_RETVAL; return TOK_REL_RETVAL; /* .. */ +\<:\> yylval.arctype = MSC_ARC_DOUBLE; return TOK_REL_DOUBLE_BI; /* <:> */ +:\> yylval.arctype = MSC_ARC_DOUBLE; return TOK_REL_DOUBLE_TO; /* :> */ +\<: yylval.arctype = MSC_ARC_DOUBLE; return TOK_REL_DOUBLE_FROM; /* <: */ +:: yylval.arctype = MSC_ARC_DOUBLE; return TOK_REL_DOUBLE; /* :: */ +\<\<=\>\> yylval.arctype = MSC_ARC_CALLBACK; return TOK_REL_CALLBACK_BI; /* <<=>> */ +=\>\> yylval.arctype = MSC_ARC_CALLBACK; return TOK_REL_CALLBACK_TO; /* =>> */ +\<\<= yylval.arctype = MSC_ARC_CALLBACK; return TOK_REL_CALLBACK_FROM; /* <<= */ +BOX|box yylval.arctype = MSC_ARC_BOX; return TOK_REL_BOX; /* box */ +ABOX|abox yylval.arctype = MSC_ARC_ABOX; return TOK_REL_ABOX; /* abox */ +RBOX|rbox yylval.arctype = MSC_ARC_RBOX; return TOK_REL_RBOX; /* rbox */ +NOTE|note yylval.arctype = MSC_ARC_NOTE; return TOK_REL_NOTE; /* note */ +[A-Za-z0-9_]+ yylval.string = strdup_s(yytext); return TOK_STRING; +\"(\\\"|[^\"])*\" yylval.string = trimQstring(strdup_s(yytext)); return TOK_QSTRING; += return TOK_EQUAL; +, return TOK_COMMA; +\; return TOK_SEMICOLON; +\{ return TOK_OCBRACKET; +\} return TOK_CCBRACKET; +\[ return TOK_OSBRACKET; +\] return TOK_CSBRACKET; +\* return TOK_ASTERISK; +[ \t]+ /* ignore whitespace */; + +} + + +<*>.|\n|\r return TOK_UNKNOWN; + +%% + +/* Handle a new line of input. + * This counts the line number and duplicates the string incase we need + * it for error reporting. The line is then returned back for parsing + * without the newline characters prefixed. + */ +static void newline(const char *text, unsigned int n) +{ + lex_linenum++; + if(lex_line != NULL) + { + free(lex_line); + } + + lex_line = strdup(text + n); + yyless(n); +} + + +/* Trim a multi-line quoted string. + * This allows the parsed input quoted strings to span multiple lines of + * input but be condensed to only a single line of output e.g. + * a->b [label="line 1 + * line 1 too"]; + * Will parse to a string such as"line1\n line1 too". This function + * will collapse the \n and whitespace into a single space. + */ +static char *trimQstring(char *const s) +{ + int i = 0, o = 0, skipmode = 0; + + /* Strip leading " */ + if(s[i] == '\"') + { + i++; + } + + /* Copy body, compacting whitespace after newline sequences */ + while(s[i] != '\0') + { + if(s[i] == '\r' || s[i] == '\n' || s[i] == '\f') + { + skipmode = 1; + } + else if(!skipmode || !isspace(s[i])) + { + if(skipmode) + { + s[o] = ' '; + o++; + } + + skipmode = 0; + s[o] = s[i]; + o++; + } + + i++; + } + + /* Null terminate */ + s[o] = '\0'; + + /* Remove trailing " */ + if(o >= 1 && s[o - 1] == '\"') + s[o-1] = '\0'; + + return s; +} + +unsigned long lex_getlinenum(void) +{ + return lex_linenum; +} + +char *lex_getline(void) +{ + return lex_line; +} + +void lex_destroy(void) +{ + if(lex_line != NULL) + { + free(lex_line); + lex_line = NULL; + } +} + +Boolean lex_getutf8(void) +{ + return lex_utf8; +} + +/* END OF FILE */ diff --git a/libmscgen/mscgen_msc.c b/libmscgen/mscgen_msc.c new file mode 100644 index 0000000..0a17395 --- /dev/null +++ b/libmscgen/mscgen_msc.c @@ -0,0 +1,804 @@ +/*************************************************************************** + * + * $Id: msc.c 175 2011-02-06 21:07:43Z Michael.McTernan $ + * + * The message sequence parser ADT. + * Copyright (C) 2009 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + ***************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <string.h> +#include <stdlib.h> +#include "mscgen_config.h" +#include "mscgen_safe.h" +#include "mscgen_msc.h" + +/*************************************************************************** + * Structures + ***************************************************************************/ + +struct MscEntityTag +{ + char *label; + struct MscAttribTag *attr; + struct MscEntityTag *next; +}; + +struct MscEntityListTag +{ + unsigned int elements; + struct MscEntityTag *head, *tail; +}; + +struct MscArcTag +{ + char *src, *dst; + MscArcType type; + unsigned int inputLine; + struct MscAttribTag *attr; + struct MscArcTag *next; +}; + +struct MscArcListTag +{ + unsigned int elements; + unsigned int parElements; + struct MscArcTag *head, *tail; +}; + + +struct MscAttribTag +{ + MscAttribType type; + char *value; + struct MscAttribTag *next; +}; + +struct MscOptTag +{ + MscOptType type; + char *value; + struct MscOptTag *next; +}; + +struct MscTag +{ + struct MscOptTag *optList; + struct MscEntityListTag *entityList; + struct MscArcListTag *arcList; + + struct MscArcTag *nextArc; + struct MscEntityTag *nextEntity; +}; + +/*************************************************************************** + * Local Functions + ***************************************************************************/ + +/** Find come attrbute in an attribute list. + * + * \param[in] attr Head of the linked list to search. + * \param[in] a The attribute type to find. + * \retval NULL If the attribute was not found or the passed list was NULL. + */ +static const char *findAttrib(const struct MscAttribTag *attr, MscAttribType a) +{ + while(attr != NULL && attr->type != a) + { + attr = attr->next; + } + + if(attr != NULL) + { + return attr->value; + } + else + { + return NULL; + } +} + + +/** Free the memory underlying a list of attributes. + */ +static void freeAttribList(struct MscAttribTag *attr) +{ + while(attr) + { + struct MscAttribTag *next = attr->next; + free(attr->value); + free(attr); + attr = next; + } +} + +/*************************************************************************** + * Option Functions + ***************************************************************************/ + +/* Allocate some option and set it's value. + */ +struct MscOptTag *MscAllocOpt(MscOptType type, + char *value) +{ + struct MscOptTag *a = malloc_s(sizeof(struct MscOptTag)); + + a->type = type; + a->value = value; + a->next = NULL; + + return a; +} + +/* Link one or two options together. + */ +struct MscOptTag *MscLinkOpt(struct MscOptTag *head, + struct MscOptTag *newHead) +{ + struct MscOptTag *tail = newHead; + + assert(newHead); + + /* Find the end of the list */ + while(tail->next) + { + tail = tail->next; + } + + tail->next = head; + return newHead; +} + +/* MscPrettyOptType + * Returns a string that is the human readable form of the option + * code passed to the function. + */ +const char *MscPrettyOptType(MscOptType t) +{ + switch(t) + { + case MSC_OPT_HSCALE: return "hscale"; + case MSC_OPT_WIDTH: return "width"; + case MSC_OPT_ARCGRADIENT: return "arcgradient"; + default: + return "unknown"; + } +} + +struct MscOptTag *MscFindOpt(struct MscOptTag *list, + MscOptType type) +{ + struct MscOptTag *elem = list; + + while(elem && elem->type != type) + { + elem = elem->next; + } + + if(elem && elem->type == type) + { + return elem; + } + + return NULL; +} + +void MscPrintOptList(struct MscOptTag *list) +{ + struct MscOptTag *elem = list; + + while(elem) + { + printf("%p: %s=%s\n", elem, MscPrettyOptType(elem->type), elem->value); + elem = elem->next; + } +} + +/*************************************************************************** + * Entity Functions + ***************************************************************************/ + +/* MscAllocEntity + * Allocate some entity and set it's name. + */ +struct MscEntityTag *MscAllocEntity(char *entityName) +{ + struct MscEntityTag *e = malloc_s(sizeof(struct MscEntityListTag)); + + e->label = entityName; + e->attr = NULL; + e->next = NULL; + + return e; +} + + +/* MscLinkEntity + * Link some entity onto a list, possibly producing a new head element. + */ +struct MscEntityListTag *MscLinkEntity(struct MscEntityListTag *list, + struct MscEntityTag *elem) +{ + /* Check if the list has been allocated or not */ + if(list == NULL) + { + list = zalloc_s(sizeof(struct MscEntityListTag)); + } + + /* Check for an empty list */ + if(list->head == NULL) + { + list->head = list->tail = elem; + } + else + { + /* Add to tail */ + list->tail->next = elem; + list->tail = elem; + } + + /* Increment count of elements */ + list->elements++; + + return list; +} + + +void MscPrintEntityList(struct MscEntityListTag *list) +{ + struct MscEntityTag *elem = list->head; + + while(elem) + { + printf("%p: %s\n", elem, elem->label); + MscPrintAttrib(elem->attr); + elem = elem->next; + } +} + +/*************************************************************************** + * Arc Functions + ***************************************************************************/ + +/* MscAllocArc + * Allocate an arc, filling in the src and dst entities. + */ +struct MscArcTag *MscAllocArc(char *srcEntity, + char *dstEntity, + MscArcType type, + unsigned int inputLine) +{ + struct MscArcTag *a = malloc_s(sizeof(struct MscArcTag)); + + /* A discontinuity arcs are not between entities */ + if(type == MSC_ARC_DISCO) + { + assert(srcEntity == NULL && dstEntity == NULL); + } + + a->inputLine = inputLine; + a->src = srcEntity; + a->dst = dstEntity; + a->type = type; + a->next = NULL; + a->attr = NULL; + + return a; +} + + +/* MscLinkArc + * Link some entity onto a list, possibly producing a new head element. + */ +struct MscArcListTag *MscLinkArc(struct MscArcListTag *list, + struct MscArcTag *elem) +{ + /* Check if the list has been allocated or not */ + if(list == NULL) + { + list = zalloc_s(sizeof(struct MscArcListTag)); + } + + /* Check for an empty list */ + if(list->head == NULL) + { + list->head = list->tail = elem; + } + else + { + /* Add to tail */ + list->tail->next = elem; + list->tail = elem; + } + + /* Increment count of elements */ + list->elements++; + if(elem->type == MSC_ARC_PARALLEL) + { + /* A parallel arc is a place holder, and indicates the next arc + * is on the same line. It also needs to account itself, so subtract + * two here. + */ + list->parElements += 2; + } + + return list; +} + + +/* MscPrintArcList + * Dump and arc list. + */ +void MscPrintArcList(struct MscArcListTag *list) +{ + struct MscArcTag *elem = list->head; + + while(elem) + { + printf("%p: '%s' -> '%s'\n", elem, elem->src, elem->dst); + MscPrintAttrib(elem->attr); + + elem = elem->next; + } +} + + +/*************************************************************************** + * Attribute functions + ***************************************************************************/ + +/* MscAllocAttrib + * Allocate some attribute. + */ +struct MscAttribTag *MscAllocAttrib(MscAttribType type, + char *value) +{ + struct MscAttribTag *a = malloc_s(sizeof(struct MscAttribTag)); + + a->type = type; + a->value = value; + a->next = NULL; + + return a; +} + + +/* MscLinkAttrib + * Link some attributes. The ordering of attributes is semi-important + * so the list is grown from the tail. + */ +struct MscAttribTag *MscLinkAttrib(struct MscAttribTag *head, + struct MscAttribTag *newHead) +{ + struct MscAttribTag *tail = newHead; + + assert(newHead); + + /* Find the end of the list */ + while(tail->next) + { + tail = tail->next; + } + + tail->next = head; + return newHead; +} + + +/* MscArcLinkAttrib + * Attach some attributes to some arc. + */ +void MscArcLinkAttrib(struct MscArcTag *arc, + struct MscAttribTag *att) +{ + if(arc->attr) + { + arc->attr = MscLinkAttrib(arc->attr, att); + } + else + { + arc->attr = att; + } +} + + +/* MscEntityLinkAttrib + * Attach some attributes to some entity. + */ +void MscEntityLinkAttrib(struct MscEntityTag *ent, + struct MscAttribTag *att) +{ + if(ent->attr) + { + ent->attr = MscLinkAttrib(ent->attr, att); + } + else + { + ent->attr = att; + } +} + + +/* MscPrintAttrib + * String a human readable version of the passed attribute list to stdout. + */ +void MscPrintAttrib(const struct MscAttribTag *att) +{ + while(att) + { + printf(" %s = %s\n", MscPrettyAttribType(att->type), att->value); + att = att->next; + } + +} + + +/* MscPrettyAttribType + * Returns a string that is the human readable form of the attribute + * code passed to the function. + */ +const char *MscPrettyAttribType(MscAttribType t) +{ + switch(t) + { + case MSC_ATTR_LABEL: return "label"; + case MSC_ATTR_URL: return "url"; + case MSC_ATTR_ID: return "id"; + case MSC_ATTR_IDURL: return "idurl"; + case MSC_ATTR_LINE_COLOUR: return "linecolour"; + case MSC_ATTR_TEXT_COLOUR: return "textcolour"; + case MSC_ATTR_TEXT_BGCOLOUR: return "textbgcolour"; + case MSC_ATTR_ARC_LINE_COLOUR: return "arclinecolour"; + case MSC_ATTR_ARC_TEXT_COLOUR: return "arctextcolour"; + case MSC_ATTR_ARC_TEXT_BGCOLOUR: return "arctextbgcolour"; + case MSC_ATTR_NO_ARROWS: return "noarrows"; + case MSC_ATTR_BI_ARROWS : return "biarrows"; + default: + return "<unknown>"; + } +} + + +/*************************************************************************** + * MSC Functions + ***************************************************************************/ + +struct MscTag *MscAlloc(struct MscOptTag *optList, + struct MscEntityListTag *entityList, + struct MscArcListTag *arcList) +{ + struct MscTag *m = malloc_s(sizeof(struct MscTag)); + + /* Copy the lists */ + m->optList = optList; + m->entityList = entityList; + m->arcList = arcList; + + /* Reset the iterators */ + MscResetEntityIterator(m); + MscResetArcIterator(m); + + return m; +} + +void MscFree(struct MscTag *m) +{ + struct MscOptTag *opt = m->optList; + struct MscEntityTag *entity = m->entityList->head; + struct MscArcTag *arc = m->arcList->head; + + while(opt) + { + struct MscOptTag *next = opt->next; + + free(opt->value); + free(opt); + + opt = next; + } + + while(entity) + { + struct MscEntityTag *next = entity->next; + + freeAttribList(entity->attr); + free(entity->label); + free(entity); + + entity = next; + } + + while(arc) + { + struct MscArcTag *next = arc->next; + + freeAttribList(arc->attr); + free(arc->dst); + free(arc->src); + free(arc); + + arc = next; + } + + free(m->entityList); + free(m->arcList); + free(m); +} + +void MscPrint(struct MscTag *m) +{ + printf("Option list (%d options)\n", MscGetNumOpts(m)); + MscPrintOptList(m->optList); + + printf("Entity list (%d entities, %d parallel)\n", + MscGetNumEntities(m), MscGetNumParallelArcs(m)); + MscPrintEntityList(m->entityList); + + printf("\nArc list (%d arcs)\n", MscGetNumArcs(m)); + MscPrintArcList(m->arcList); +} + +unsigned int MscGetNumEntities(struct MscTag *m) +{ + return m->entityList->elements; +} + +unsigned int MscGetNumArcs(Msc m) +{ + return m->arcList->elements; +} + +unsigned int MscGetNumParallelArcs(Msc m) +{ + return m->arcList->parElements; +} + +unsigned int MscGetNumOpts(Msc m) +{ + struct MscOptTag *elem = m->optList; + unsigned int count = 0; + + while(elem) + { + count++; + elem = elem->next; + } + + return count; +} + +int MscGetEntityIndex(struct MscTag *m, const char *label) +{ + struct MscEntityTag *entity = m->entityList->head; + int c = 0; + + assert(label); + + while(entity != NULL && strcmp(entity->label, label) != 0) + { + entity = entity->next; + c++; + } + + if(entity == NULL) + { + return -1; + } + else + { + return c; + } +} + +void MscResetEntityIterator(struct MscTag *m) +{ + m->nextEntity = m->entityList->head; +} + +Boolean MscNextEntity(struct MscTag *m) +{ + if(m->nextEntity->next != NULL) + { + m->nextEntity = m->nextEntity->next; + return TRUE; + } + else + { + return FALSE; + } +} + + +const char *MscGetCurrentEntAttrib(struct MscTag *m, MscAttribType a) +{ + const char *r; + + if(!m->nextEntity) + { + return NULL; + } + + r = findAttrib(m->nextEntity->attr, a); + + /* If the entity label was sought but not found, return entity name */ + if(r == NULL && a == MSC_ATTR_LABEL) + { + return m->nextEntity->label; + } + else + { + return r; + } +} + + +const char *MscGetEntAttrib(Msc m, unsigned int entIdx, MscAttribType a) +{ + struct MscEntityTag *entity; + const char *r; + + /* Find the entity */ + entity = m->entityList->head; + while(entIdx > 0 && entity != NULL) + { + entity = entity->next; + entIdx--; + } + + /* Search the attribute list if the entity was found */ + if(entity) + { + r = findAttrib(entity->attr, a); + + /* If the entity label was sought but not found, return entity name */ + if(r == NULL && a == MSC_ATTR_LABEL) + { + return m->nextEntity->label; + } + else + { + return r; + } + } + else + { + /* Entity was not found */ + return NULL; + } +} + + +void MscResetArcIterator(struct MscTag *m) +{ + m->nextArc = m->arcList->head; +} + +Boolean MscNextArc(struct MscTag *m) +{ + if(m->nextArc->next != NULL) + { + m->nextArc = m->nextArc->next; + return TRUE; + } + else + { + return FALSE; + } +} + +const char *MscGetCurrentArcSource(struct MscTag *m) +{ + return m->nextArc ? m->nextArc->src : NULL; +} + +const char *MscGetCurrentArcDest(struct MscTag *m) +{ + return m->nextArc ? m->nextArc->dst : NULL; +} + +MscArcType MscGetCurrentArcType(struct MscTag *m) +{ + return m->nextArc ? m->nextArc->type : MSC_INVALID_ARC_TYPE; +} + +const char *MscGetCurrentArcAttrib(struct MscTag *m, MscAttribType a) +{ + struct MscAttribTag *attr; + + if(!m->nextArc) + { + return NULL; + } + + attr = m->nextArc->attr; + + while(attr != NULL && attr->type != a) + { + attr = attr->next; + } + + if(attr != NULL) + { + return attr->value; + } + else + { + return NULL; + } + +} + +Boolean MscGetOptAsFloat(struct MscTag *m, MscOptType type, float *const f) +{ + struct MscOptTag *opt = MscFindOpt(m->optList, type); + + if(opt != NULL) + { + *f = (float)atof(opt->value); + return *f != 0.0f; + } + + return FALSE; +} + +unsigned int MscGetCurrentArcInputLine(struct MscTag *m) +{ + if(m->nextArc) + { + return m->nextArc->inputLine; + } + else + { + return 0; + } +} + +Boolean MscGetOptAsBoolean(struct MscTag *m, MscOptType type, Boolean *const b) +{ + struct MscOptTag *opt = MscFindOpt(m->optList, type); + + if(opt != NULL) + { + const char *v = opt->value; + + if(strcasecmp(v, "true") == 0 || strcasecmp(v, "yes") == 0 || + strcasecmp(v, "on") == 0 || strcasecmp(v, "1") == 0) + { + *b = TRUE; + return TRUE; + } + else if(strcasecmp(v, "false") == 0 || strcasecmp(v, "no") == 0 || + strcasecmp(v, "off") == 0 || strcasecmp(v, "0") == 0) + { + *b = FALSE; + return TRUE; + } + else + { + fprintf(stderr, "Warning: Unrecognised boolean option value '%s'. Valid values are 'true',\n" + " 'false', 'yes', 'no', 'on', 'off', '1' and '0'.\n", + v); + return FALSE; + } + } + + return FALSE; +} +/* END OF FILE */ + diff --git a/libmscgen/mscgen_msc.h b/libmscgen/mscgen_msc.h new file mode 100644 index 0000000..d7b2726 --- /dev/null +++ b/libmscgen/mscgen_msc.h @@ -0,0 +1,299 @@ +/*************************************************************************** + * + * $Id: msc.h 175 2011-02-06 21:07:43Z Michael.McTernan $ + * + * The message sequence parser API. + * Copyright (C) 2009 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + ***************************************************************************/ + +#ifndef MSCGEN_MSC_H +#define MSCGEN_MSC_H + +#include "mscgen_bool.h" + +/*************************************************************************** + * Types + ***************************************************************************/ + +/** Msc Options. + */ +typedef enum MscOptTypeTag +{ + MSC_OPT_HSCALE, + MSC_OPT_WIDTH, + MSC_OPT_ARCGRADIENT, + MSC_OPT_WORDWRAPARCS +} +MscOptType; + + +/** Arc attributes. + * An arc may have one or more attributes listed in square brackets after + * the declaration. This gives an enumerated type for each permissible + * attribute. + */ +typedef enum MscAttribTypeTag +{ + MSC_ATTR_LABEL, + MSC_ATTR_ID, + MSC_ATTR_URL, + MSC_ATTR_IDURL, + MSC_ATTR_LINE_COLOUR, + MSC_ATTR_TEXT_COLOUR, + MSC_ATTR_TEXT_BGCOLOUR, + MSC_ATTR_ARC_LINE_COLOUR, + MSC_ATTR_ARC_TEXT_COLOUR, + MSC_ATTR_ARC_TEXT_BGCOLOUR, + MSC_ATTR_NO_ARROWS, + MSC_ATTR_BI_ARROWS, + MSC_ATTR_ARC_SKIP +} +MscAttribType; + + +typedef enum +{ + MSC_ARC_METHOD, + MSC_ARC_RETVAL, + MSC_ARC_SIGNAL, + MSC_ARC_CALLBACK, + MSC_ARC_DOUBLE, + MSC_ARC_DISCO, /* ... Discontinuity in time line */ + MSC_ARC_DIVIDER, /* --- Divider */ + MSC_ARC_SPACE, /* ||| */ + MSC_ARC_PARALLEL, /* Comma instead of semicolon */ + MSC_ARC_BOX, + MSC_ARC_ABOX, + MSC_ARC_RBOX, + MSC_ARC_NOTE, + MSC_ARC_LOSS, /* -x or x- */ + + MSC_INVALID_ARC_TYPE +} +MscArcType; + + +/*************************************************************************** + * Abstract types + ***************************************************************************/ + +typedef struct MscTag *Msc; + +typedef struct MscOptTag *MscOpt; + +typedef struct MscEntityTag *MscEntity; + +typedef struct MscEntityListTag *MscEntityList; + +typedef struct MscArcTag *MscArc; + +typedef struct MscArcListTag *MscArcList; + +typedef struct MscAttribTag *MscAttrib; + + +/*************************************************************************** + * MSC Building Functions + ***************************************************************************/ + +/** Parse some input to build a message sequence chart. + * This will parse characters from \a in and build a message sequence chart + * ADT. + * \retval Msc The message sequence chart, which may equal \a NULL is a + * parse error occurred. + */ +#ifdef __cplusplus +extern "C" { +#endif +Msc MscParse(FILE *in); + +MscEntity MscAllocEntity(char *entityName); + +MscEntityList MscLinkEntity(MscEntityList list, MscEntity elem); + +void MscPrintEntityList(MscEntityList list); + +MscOpt MscAllocOpt(MscOptType type, + char *value); + +MscOpt MscLinkOpt(MscOpt head, + MscOpt newHead); + +MscArc MscAllocArc(char *srcEntity, + char *dstEntity, + MscArcType type, + unsigned int inputLine); + +MscArcList MscLinkArc (MscArcList list, + MscArc elem); + +void MscPrintArcList(struct MscArcListTag *list); + +MscAttrib MscAllocAttrib(MscAttribType type, + char *value); + +MscAttrib MscLinkAttrib(MscAttrib head, + MscAttrib newHead); + +void MscArcLinkAttrib(MscArc arc, + MscAttrib att); + +void MscEntityLinkAttrib(MscEntity ent, + MscAttrib att); + +void MscPrintAttrib(const struct MscAttribTag *att); + +const char *MscPrettyAttribType(MscAttribType t); + +Msc MscAlloc(MscOpt optList, + MscEntityList entityList, + MscArcList arcList); + +void MscFree(struct MscTag *m); + +/** Print the passed msc in textual form to stdout. + * This prints a human readable format of the parsed msc to stdout. This + * is primarily of use in debugging the parser. + */ +void MscPrint(Msc m); + +unsigned int MscGetNumEntities(Msc m); + +unsigned int MscGetNumArcs(Msc m); + +unsigned int MscGetNumParallelArcs(Msc m); + +unsigned int MscGetNumOpts(Msc m); + +/** Get an MSC option, returning the value as a float. + * + * \param[in] m The MSC to analyse. + * \param[in] type The option type to retrieve. + * \param[in,out] f Pointer to be filled with parsed value. + * \retval TRUE If the option was found and parsed successfully. + */ +Boolean MscGetOptAsFloat(struct MscTag *m, MscOptType type, float *const f); + +/** Get an MSC option, returning the value as a Boolean. + * + * \param[in] m The MSC to analyse. + * \param[in] type The option type to retrieve. + * \param[in,out] b Pointer to be filled with parsed value. + * \retval TRUE If the option was found and parsed successfully, + * otherwise FALSE in which case *b is unmodified. + * + */ +Boolean MscGetOptAsBoolean(struct MscTag *m, MscOptType type, Boolean *const b); + +/** Get the index of some entity. + * This returns the column index for the entity identified by the passed + * label. + * + * \param m The MSC to analyse. + * \param label The label to find. + * \retval -1 If the label was not found, otherwise the columnn index. + */ +int MscGetEntityIndex(struct MscTag *m, const char *label); + +/*************************************************************************** + * Entity processing functions + ***************************************************************************/ + +/** \defgroup EntityFuncs Entity handling functions + * @{ + */ + +/** Reset the entity interator. + * This moves the pointer to the current entity to the head of the list. + */ +void MscResetEntityIterator(Msc m); + +/** Move to the next entity in the MSC. + * \retval TRUE if there is another entity, otherwise FALSE if the end of the + * list has been reached. + */ +Boolean MscNextEntity(struct MscTag *m); + +/** Get the value of some attribute for the current entity. + * \retval The attribute string, or NULL if unset. + */ +const char *MscGetCurrentEntAttrib(Msc m, MscAttribType a); + +/** Get an attribute associated with some entity. + * \param[in] entIdx The index of the entity. + * \retval The attribute string, or NULL if unset. + */ +const char *MscGetEntAttrib(Msc m, unsigned int entIdx, MscAttribType a); + +/** @} */ + +/*************************************************************************** + * Arc processing functions + ***************************************************************************/ + +/** \defgroup ArcFuncs Arc handling functions + * @{ + */ + +/** Reset the arc interator. + * This moves the pointer to the current arc to the head of the list. + */ +void MscResetArcIterator (Msc m); + +/** Move to the next arc in the MSC. + * \retval TRUE if there is another arc, otherwise FALSE if the end of the + * list has been reached. + */ +Boolean MscNextArc(struct MscTag *m); + + +/** Get the name of the entity from which the current arc originates. + * \retvat The label for the entity from which the current arc starts. + * The returned string must not be modified. + */ +const char *MscGetCurrentArcSource(Msc m); + + +/** Get the name of the entity at which the current arc terminates. + * \retval The label for the entity at which the current arc stops. + * The returned string must not be modified. + */ +const char *MscGetCurrentArcDest(Msc m); + +/** Get the type for some arc. + * + */ +MscArcType MscGetCurrentArcType(struct MscTag *m); + +/** Get the value of some attribute for the current arc. + * \retval The attribute string, or NULL if unset. + */ +const char *MscGetCurrentArcAttrib(Msc m, MscAttribType a); + +/** Get the line of the input file at which the current arc was defined. + * \retval The line number of the input file. + */ +unsigned int MscGetCurrentArcInputLine(Msc m); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* MSCGEN_MSC_H */ + +/* END OF FILE */ diff --git a/libmscgen/mscgen_null_out.c b/libmscgen/mscgen_null_out.c new file mode 100644 index 0000000..4607c71 --- /dev/null +++ b/libmscgen/mscgen_null_out.c @@ -0,0 +1,170 @@ +/*************************************************************************** + * + * $Id: null_out.c 112 2010-08-18 12:59:54Z Michael.McTernan $ + * + * This file is part of mscgen, a message sequence chart renderer. + * Copyright (C) 2005 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + **************************************************************************/ + + +#include <stdio.h> +#include <assert.h> + +#include "mscgen_adraw_int.h" + +/*************************************************************************** + * API Functions + ***************************************************************************/ + +static unsigned int NullTextWidth(struct ADrawTag *ctx UNUSED, + const char *string UNUSED) +{ + return 0; +} + + +static int NullTextHeight(struct ADrawTag *ctx UNUSED) +{ + return 0; +} + + +static void NullLine(struct ADrawTag *ctx UNUSED, + unsigned int x1 UNUSED, + unsigned int y1 UNUSED, + unsigned int x2 UNUSED, + unsigned int y2 UNUSED) +{ +} + + +static void NullDottedLine(struct ADrawTag *ctx UNUSED, + unsigned int x1 UNUSED, + unsigned int y1 UNUSED, + unsigned int x2 UNUSED, + unsigned int y2 UNUSED) +{ +} + + +static void NullTextR(struct ADrawTag *ctx UNUSED, + unsigned int x UNUSED, + unsigned int y UNUSED, + const char *string UNUSED) +{ +} + + +static void NullTextL(struct ADrawTag *ctx UNUSED, + unsigned int x UNUSED, + unsigned int y UNUSED, + const char *string UNUSED) +{ +} + + +static void NullTextC(struct ADrawTag *ctx UNUSED, + unsigned int x UNUSED, + unsigned int y UNUSED, + const char *string UNUSED) +{ +} + + +static void NullFilledRectangle(struct ADrawTag *ctx UNUSED, + unsigned int x1 UNUSED, + unsigned int y1 UNUSED, + unsigned int x2 UNUSED, + unsigned int y2 UNUSED) +{ +} + + +static void NullFilledTriangle(struct ADrawTag *ctx UNUSED, + unsigned int x1 UNUSED, + unsigned int y1 UNUSED, + unsigned int x2 UNUSED, + unsigned int y2 UNUSED, + unsigned int x3 UNUSED, + unsigned int y3 UNUSED) +{ +} + + +static void NullArc(struct ADrawTag *ctx UNUSED, + unsigned int cx UNUSED, + unsigned int cy UNUSED, + unsigned int w UNUSED, + unsigned int h UNUSED, + unsigned int s UNUSED, + unsigned int e UNUSED) +{ +} + + +static void NullDottedArc(struct ADrawTag *ctx UNUSED, + unsigned int cx UNUSED, + unsigned int cy UNUSED, + unsigned int w UNUSED, + unsigned int h UNUSED, + unsigned int s UNUSED, + unsigned int e UNUSED) +{ +} + + +static void NullSetPen (struct ADrawTag *ctx UNUSED, + ADrawColour col UNUSED) +{ +} + + +static void NullSetFontSize(struct ADrawTag *ctx UNUSED, + ADrawFontSize size UNUSED) +{ +} + + +static Boolean NullClose(struct ADrawTag *ctx UNUSED) +{ + return TRUE; +} + + +Boolean NullInit(struct ADrawTag *outContext) +{ + /* Fill in the function pointers */ + outContext->line = NullLine; + outContext->dottedLine = NullDottedLine; + outContext->textL = NullTextL; + outContext->textC = NullTextC; + outContext->textR = NullTextR; + outContext->textWidth = NullTextWidth; + outContext->textHeight = NullTextHeight; + outContext->filledRectangle = NullFilledRectangle; + outContext->filledTriangle = NullFilledTriangle; + outContext->arc = NullArc; + outContext->dottedArc = NullDottedArc; + outContext->setPen = NullSetPen; + outContext->setBgPen = NullSetPen; + outContext->setFontSize = NullSetFontSize; + outContext->close = NullClose; + + return TRUE; +} + +/* END OF FILE */ diff --git a/libmscgen/mscgen_ps_out.c b/libmscgen/mscgen_ps_out.c new file mode 100644 index 0000000..32f9eae --- /dev/null +++ b/libmscgen/mscgen_ps_out.c @@ -0,0 +1,595 @@ +/*************************************************************************** + * + * $Id: ps_out.c 186 2011-03-01 21:18:19Z Michael.McTernan $ + * + * This file is part of mscgen, a message sequence chart renderer. + * Copyright (C) 2005 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + **************************************************************************/ + +#include "mscgen_config.h" +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <assert.h> +#include <string.h> +#include "mscgen_adraw_int.h" +#include "mscgen_utf8.h" +#include "mscgen_safe.h" + +/*************************************************************************** + * Manifest Constants + ***************************************************************************/ + +/** Overall scaling of the Postscript output. + */ +#define PS_OUT_SCALE 0.7f + +/*************************************************************************** + * Local types + ***************************************************************************/ + +typedef struct PsContextTag +{ + /** Output file. */ + FILE *of; + + /** Point size of the current font. */ + int fontPoints; + + /** Current pen colour. */ + ADrawColour penColour; + + /** Background colour for the pen. */ + ADrawColour penBgColour; +} +PsContext; + +typedef struct +{ + int capheight, xheight, ascender, descender; + int widths[256]; +} +PsCharMetric; + +/** Helvetica character widths. + * This gives the width of each character is 1/1000ths of a point. + * The values are taken from the Adobe Font Metric file for Hevletica. + */ +static const PsCharMetric PsHelvetica = +{ + 718, 523, 718, -207, + { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 278, 278, 355, 556, 556, 889, 667, 222, + 333, 333, 389, 584, 278, 333, 278, 278, + 556, 556, 556, 556, 556, 556, 556, 556, + 556, 556, 278, 278, 584, 584, 584, 556, + 1015, 667, 667, 722, 722, 667, 611, 778, + 722, 278, 500, 667, 556, 833, 722, 778, + 667, 778, 722, 667, 611, 722, 667, 944, + 667, 667, 611, 278, 278, 278, 469, 556, + 222, 556, 556, 500, 556, 556, 278, 556, + 556, 222, 222, 500, 222, 833, 556, 556, + 556, 556, 333, 500, 278, 556, 500, 722, + 500, 500, 500, 334, 260, 334, 584, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 333, 556, 556, 167, 556, 556, 556, + 556, 191, 333, 556, 333, 333, 500, 500, + -1, 556, 556, 556, 278, -1, 537, 350, + 222, 333, 333, 556, 1000, 1000, -1, 611, + -1, 333, 333, 333, 333, 333, 333, 333, + 333, -1, 333, 333, -1, 333, 333, 333, + 1000, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 1000, -1, 370, -1, -1, -1, -1, + 556, 778, 1000, 365, -1, -1, -1, -1, + -1, 889, -1, -1, -1, 278, -1, -1, + 222, 611, 944, 611, -1, -1, -1, -1 + } +}; + +/*************************************************************************** + * Helper functions + ***************************************************************************/ + + +/** Get the context pointer from an ADraw structure. + */ +static PsContext *getPsCtx(struct ADrawTag *ctx) +{ + return (PsContext *)ctx->internal; +} + +/** Get the context pointer from an ADraw structure. + */ +static FILE *getPsFile(struct ADrawTag *ctx) +{ + return getPsCtx(ctx)->of; +} + +/** Given a font metric measurement, return device dependent units. + * Font metric data is stored as 1/1000th of a point, and therefore + * needs to be multiplied by the font point size and divided by + * 1000 to give a value in device dependent units. + */ +static int getSpace(struct ADrawTag *ctx, long thousanths) +{ + return ((thousanths * getPsCtx(ctx)->fontPoints) + 500) / 1000; +} + +/** Write out a line of text, escaping special characters. + */ +static void writeEscaped(struct ADrawTag *ctx, const char *string) +{ + FILE *f = getPsFile(ctx); + + while(*string != '\0') + { + unsigned int code, bytes; + + switch(*string) + { + case '(': fprintf(f, "\\("); break; + case ')': fprintf(f, "\\)"); break; + default: + if(Utf8Decode(string, &code, &bytes)) + { + fprintf(f, "\\%o", code); + string += bytes - 1; + } + else + { + fputc(*string, f); + } + break; + } + + string++; + } +} + +static void setColour(struct ADrawTag *ctx, + ADrawColour col) +{ + float r, g, b; + + /* Extract RGB values */ + r = (float)((col & 0xff0000) >> 16); + g = (float)((col & 0x00ff00) >> 8); + b = (float)((col & 0x0000ff) >> 0); + + /* Normalise */ + r /= 255.0f; + g /= 255.0f; + b /= 255.0f; + + /* Generate output command */ + fprintf(getPsFile(ctx), "%f %f %f setrgbcolor\n", r ,g ,b); +} + +/*************************************************************************** + * API Functions + ***************************************************************************/ + +unsigned int PsTextWidth(struct ADrawTag *ctx, + const char *string) +{ + unsigned long width = 0; + + while(*string != '\0') + { + int i = *string & 0xff; + unsigned long w = PsHelvetica.widths[i]; + + /* Ignore undefined characters */ + width += w > 0 ? w : 0; + + string++; + } + + return getSpace(ctx, width); +} + + +int PsTextHeight(struct ADrawTag *ctx) +{ + return getSpace(ctx, PsHelvetica.ascender - PsHelvetica.descender); +} + + +void PsLine(struct ADrawTag *ctx, + unsigned int x1, + unsigned int y1, + unsigned int x2, + unsigned int y2) +{ + fprintf(getPsFile(ctx), + "newpath %d %d moveto %d %d lineto stroke\n", + x1, 0-y1, x2, 0-y2); + +} + + +void PsDottedLine(struct ADrawTag *ctx, + unsigned int x1, + unsigned int y1, + unsigned int x2, + unsigned int y2) +{ + fprintf(getPsFile(ctx), "[2] 0 setdash\n"); + PsLine(ctx, x1, y1, x2, y2); + fprintf(getPsFile(ctx), "[] 0 setdash\n"); +} + + +void PsFilledRectangle(struct ADrawTag *ctx, + unsigned int x1, + unsigned int y1, + unsigned int x2, + unsigned int y2) +{ + fprintf(getPsFile(ctx), + "newpath " + "%d %d moveto " + "%d %d lineto " + "%d %d lineto " + "%d %d lineto " + "closepath " + "fill\n", + x1, 0-y1, + x2, 0-y1, + x2, 0-y2, + x1, 0-y2); +} + + +void PsTextR(struct ADrawTag *ctx, + unsigned int x, + unsigned int y, + const char *string) +{ + PsContext *context = getPsCtx(ctx); + + /* Push the string and get its width */ + fprintf(getPsFile(ctx), "("); + writeEscaped(ctx, string); + fprintf(getPsFile(ctx), ") dup stringwidth\n"); + + /* Draw the background box */ + setColour(ctx, context->penBgColour); + fprintf(getPsFile(ctx), "pop " /* Ignore y-value */ + "dup " /* Duplicate string width */ + "newpath " + "%d %d moveto " /* Bottom left of the box */ + "0 rlineto " /* Move to bottom right of the box */ + "0 %d rlineto " /* To top right */ + "neg 0 rlineto " /* Back to bottom left */ + "closepath fill\n", /* Done */ + x, 0-y - getSpace(ctx, PsHelvetica.descender), + getSpace(ctx, PsHelvetica.ascender)); + + /* Restore pen and show the string */ + setColour(ctx, context->penColour); + fprintf(getPsFile(ctx), "%d %d moveto show\n", + x, 0-y - getSpace(ctx, PsHelvetica.descender)); +} + + +void PsTextL(struct ADrawTag *ctx, + unsigned int x, + unsigned int y, + const char *string) +{ + PsContext *context = getPsCtx(ctx); + + /* Draw the background box */ + setColour(ctx, context->penBgColour); + PsFilledRectangle(ctx, x, 0-y, x + 10, 0-y + 10); + setColour(ctx, context->penColour); + + fprintf(getPsFile(ctx), + "%d %d moveto " + "(", + x, 0-y - getSpace(ctx, PsHelvetica.descender)); + writeEscaped(ctx, string); + fprintf(getPsFile(ctx), + ") dup stringwidth " + "pop " /* Ignore y value */ + "neg " /* Invert x value */ + "0 " + "rmoveto " + "show\n"); +} + + +void PsTextC(struct ADrawTag *ctx, + unsigned int x, + unsigned int y, + const char *string) +{ + PsContext *context = getPsCtx(ctx); + + /* Push the string and get its width */ + fprintf(getPsFile(ctx), "("); + writeEscaped(ctx, string); + fprintf(getPsFile(ctx), ") dup stringwidth\n"); + + /* Draw the background box */ + setColour(ctx, context->penBgColour); + fprintf(getPsFile(ctx), "pop " /* Ignore y-value */ + "dup dup " /* Duplicate string width twice */ + "newpath " + "%d %d moveto " /* Starting point, centre bottom of box */ + "2 div neg 0 rmoveto " /* Move to bottom left */ + "0 rlineto " /* Move to bottom right of the box */ + "0 %d rlineto " /* To top right */ + "neg 0 rlineto " /* Back to bottom left */ + "closepath fill\n", /* Done */ + x, 0-y, + getSpace(ctx, PsHelvetica.ascender)); + + /* Restore pen and show the string */ + setColour(ctx, context->penColour); + fprintf(getPsFile(ctx), "%d %d moveto dup stringwidth pop 2 div neg 0 rmoveto show\n", + x, 0-y - getSpace(ctx, PsHelvetica.descender)); +} + + +void PsFilledTriangle(struct ADrawTag *ctx, + unsigned int x1, + unsigned int y1, + unsigned int x2, + unsigned int y2, + unsigned int x3, + unsigned int y3) +{ + fprintf(getPsFile(ctx), + "newpath " + "%d %d moveto " + "%d %d lineto " + "%d %d lineto " + "closepath " + "fill\n", + x1, 0-y1, + x2, 0-y2, + x3, 0-y3); +} + + +void PsFilledCircle(struct ADrawTag *ctx, + unsigned int x, + unsigned int y, + unsigned int r) +{ + fprintf(getPsFile(ctx), + "newpath " + "%d %d %d 0 360 arc " + "closepath " + "fill\n", + x, 0-y, r); +} + + +void PsArc(struct ADrawTag *ctx, + unsigned int cx, + unsigned int cy, + unsigned int w, + unsigned int h, + unsigned int s, + unsigned int e) +{ + fprintf(getPsFile(ctx), + "newpath " + "%d %d %d %d %d %d ellipse " + "stroke\n", + cx, 0-cy, w, h, s, e); +} + + +void PsDottedArc(struct ADrawTag *ctx, + unsigned int cx, + unsigned int cy, + unsigned int w, + unsigned int h, + unsigned int s, + unsigned int e) +{ + fprintf(getPsFile(ctx), "[2] 0 setdash\n"); + PsArc(ctx, cx, cy, w, h, s, e); + fprintf(getPsFile(ctx), "[] 0 setdash\n"); +} + + +void PsSetPen(struct ADrawTag *ctx, + ADrawColour col) +{ + PsContext *context = getPsCtx(ctx); + + assert(col != ADRAW_COL_INVALID); + + /* Check if the pen colour has changed */ + if(context->penColour != col) + { + setColour(ctx, col); + + /* Store the pen colour */ + context->penColour = col; + } +} + + +void PsSetBgPen(struct ADrawTag *ctx, + ADrawColour col) +{ + PsContext *context = getPsCtx(ctx); + + context->penBgColour = col; +} + + +void PsSetFontSize(struct ADrawTag *ctx, + ADrawFontSize size) +{ + PsContext *context = getPsCtx(ctx); + + switch(size) + { + case ADRAW_FONT_TINY: + getPsCtx(ctx)->fontPoints = 8; + break; + + case ADRAW_FONT_SMALL: + getPsCtx(ctx)->fontPoints = 12; + break; + + default: + assert(0); + } + + fprintf(context->of, "/Helvetica findfont\n"); + fprintf(context->of, "%d scalefont\n", getPsCtx(ctx)->fontPoints); + fprintf(context->of, "setfont\n"); +} + + +Boolean PsClose(struct ADrawTag *ctx) +{ + PsContext *context = getPsCtx(ctx); + + /* Close the output file */ + if(context->of != stdout) + { + fclose(context->of); + } + + /* Free and destroy context */ + free(context); + ctx->internal = NULL; + + return TRUE; +} + + + +Boolean PsInit(unsigned int w, + unsigned int h, + const char *file, + struct ADrawTag *outContext) +{ + PsContext *context; + + /* Create context */ + context = outContext->internal = malloc_s(sizeof(PsContext)); + if(context == NULL) + { + return FALSE; + } + + /* Open the output file */ + if(strcmp(file, "-") == 0) + { + context->of = stdout; + } + else + { + context->of = fopen(file, "wb"); + if(!context->of) + { + fprintf(stderr, "PsInit: Failed to open output file '%s': %s\n", file, strerror(errno)); + return FALSE; + } + } + + /* Write the header */ + fprintf(context->of, "%%!PS-Adobe-3.0 EPSF-2.0\n" + "%%%%BoundingBox: 0 0 %.0f %.0f\n", w * PS_OUT_SCALE, h * PS_OUT_SCALE); + fprintf(context->of, "%%%%Creator: mscgen %s\n", PACKAGE_VERSION); + fprintf(context->of, "%%%%EndComments\n"); + + /* Shrink everything by 70% */ + fprintf(context->of, "%f %f scale\n", PS_OUT_SCALE, PS_OUT_SCALE); + + /* Create clipping rectangle to constrain dimensions */ + fprintf(context->of, "0 0 moveto\n"); + fprintf(context->of, "0 %u lineto\n", h); + fprintf(context->of, "%u %u lineto\n", w, h); + fprintf(context->of, "%u 0 lineto\n", w); + fprintf(context->of, "closepath\n"); + fprintf(context->of, "clip\n"); + fprintf(context->of, "%%PageTrailer\n"); + fprintf(context->of, "%%Page: 1 1\n"); + + /* Set default font */ + fprintf(context->of, "/Helvetica findfont\n"); + fprintf(context->of, "10 scalefont\n"); + fprintf(context->of, "setfont\n"); + + /* Get the default font size */ + PsSetFontSize(outContext, ADRAW_FONT_SMALL); + + /* Translate up by the height, y-axis will be inverted */ + fprintf(context->of, "0 %d translate\n", h); + + /* Arc drawing function */ + fprintf(context->of, "/mtrx matrix def\n" + "/ellipse\n" + " { /endangle exch def\n" + " /startangle exch def\n" + " /ydia exch def\n" + " /xdia exch def\n" + " /y exch def\n" + " /x exch def\n" + " /savematrix mtrx currentmatrix def\n" + " x y translate\n" + " xdia 2 div ydia 2 div scale\n" + " 1 -1 scale\n" + " 0 0 1 startangle endangle arc\n" + " savematrix setmatrix\n" + "} def\n"); + + /* Set the current pen colours */ + context->penColour = ADRAW_COL_BLACK; + context->penBgColour = ADRAW_COL_WHITE; + + /* Now fill in the function pointers */ + outContext->line = PsLine; + outContext->dottedLine = PsDottedLine; + outContext->textL = PsTextL; + outContext->textC = PsTextC; + outContext->textR = PsTextR; + outContext->textWidth = PsTextWidth; + outContext->textHeight = PsTextHeight; + outContext->filledRectangle = PsFilledRectangle; + outContext->filledTriangle = PsFilledTriangle; + outContext->filledCircle = PsFilledCircle; + outContext->arc = PsArc; + outContext->dottedArc = PsDottedArc; + outContext->setPen = PsSetPen; + outContext->setBgPen = PsSetBgPen; + outContext->setFontSize = PsSetFontSize; + outContext->close = PsClose; + + return TRUE; +} + +/* END OF FILE */ diff --git a/libmscgen/mscgen_safe.c b/libmscgen/mscgen_safe.c new file mode 100644 index 0000000..c657110 --- /dev/null +++ b/libmscgen/mscgen_safe.c @@ -0,0 +1,119 @@ +/***************************************************************************
+ *
+ * $Id: safe.c 152 2010-10-10 14:17:37Z Michael.McTernan $
+ *
+ * This file is part of timgen, a timing diagram renderer.
+ * Copyright (C) 2010 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ **************************************************************************/
+
+#define FILE_NAME SAFE
+
+/*****************************************************************************
+ * Header Files
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "mscgen_config.h"
+#include "mscgen_safe.h"
+
+/*****************************************************************************
+ * Preprocessor Macros & Constants
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Typedefs
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Local Variable Definitions
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Global Variable Definitions
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Local Function Definitions
+ *****************************************************************************/
+
+static void checkNotNull(void *p, const char *message)
+{
+ if(!p)
+ {
+ fprintf(stderr, "Fatal error: %s\n", message);
+ exit(EXIT_FAILURE);
+ }
+}
+
+/*****************************************************************************
+ * Global Function Definitions
+ *****************************************************************************/
+
+void *realloc_s(void *ptr, size_t size)
+{
+ void *r = realloc(ptr, size);
+
+ checkNotNull(r, "realloc() failed");
+
+ return r;
+}
+
+void *malloc_s(size_t size)
+{
+ void *r = malloc(size);
+
+ checkNotNull(r, "malloc() failed");
+
+ return r;
+}
+
+void *zalloc_s(size_t size)
+{
+ void *r = malloc(size);
+
+ checkNotNull(r, "malloc() failed");
+ memset(r, 0, size);
+
+ return r;
+}
+
+char *strdup_s(const char *s)
+{
+ char *r = strdup(s);
+
+ checkNotNull(r, "strdup() failed");
+
+ return r;
+}
+
+const char *mscgen_getenv_s(const char *name)
+{
+ char *r = getenv(name);
+
+ if(r == NULL) r = "";
+
+ return r;
+}
+
+/*****************************************************************************
+ * Unit Test Support
+ *****************************************************************************/
+
+
+/* END OF FILE */
diff --git a/libmscgen/mscgen_safe.h b/libmscgen/mscgen_safe.h new file mode 100644 index 0000000..894c4c8 --- /dev/null +++ b/libmscgen/mscgen_safe.h @@ -0,0 +1,59 @@ +/***************************************************************************
+ *
+ * $Id: safe.h 152 2010-10-10 14:17:37Z Michael.McTernan $
+ *
+ * This file is part of mscgen, a message sequence chart renderer.
+ * Copyright (C) 2005 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ **************************************************************************/
+
+#ifndef MSCGEN_SAFE_H
+#define MSCGEN_SAFE_H
+
+/*****************************************************************************
+ * Header Files
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preprocessor Macros & Constants
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Typedefs
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Global Variable Declarations
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Global Function Declarations
+ *****************************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+void *realloc_s(void *ptr, size_t size);
+void *malloc_s(size_t size);
+void *zalloc_s(size_t size);
+char *strdup_s(const char *s);
+const char *mscgen_getenv_s(const char *name);
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* MSCGEN_SAFE_H */
diff --git a/libmscgen/mscgen_svg_out.c b/libmscgen/mscgen_svg_out.c new file mode 100644 index 0000000..73378be --- /dev/null +++ b/libmscgen/mscgen_svg_out.c @@ -0,0 +1,585 @@ +/*************************************************************************** + * + * $Id: svg_out.c 186 2011-03-01 21:18:19Z Michael.McTernan $ + * + * This file is part of mscgen, a message sequence chart renderer. + * Copyright (C) 2005 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + **************************************************************************/ + +#include "mscgen_config.h" +#include <math.h> +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <assert.h> +#include <string.h> +#include "mscgen_adraw_int.h" +#include "mscgen_safe.h" +#include "mscgen_utf8.h" + +/*************************************************************************** + * Local types + ***************************************************************************/ + +typedef struct SvgContextTag +{ + /** Output file. */ + FILE *of; + + /** Current pen colour name. */ + const char *penColName; + + /** Current background pen colour name. */ + const char *penBgColName; + + int fontPoints; +} +SvgContext; + +typedef struct +{ + int capheight, xheight, ascender, descender; + int widths[256]; +} +SvgCharMetric; + +/** Helvetica character widths. + * This gives the width of each character is 1/1000ths of a point. + * The values are taken from the Adobe Font Metric file for Hevletica. + */ +static const SvgCharMetric SvgHelvetica = +{ + 718, 523, 718, -207, + { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 278, 278, 355, 556, 556, 889, 667, 222, + 333, 333, 389, 584, 278, 333, 278, 278, + 556, 556, 556, 556, 556, 556, 556, 556, + 556, 556, 278, 278, 584, 584, 584, 556, + 1015, 667, 667, 722, 722, 667, 611, 778, + 722, 278, 500, 667, 556, 833, 722, 778, + 667, 778, 722, 667, 611, 722, 667, 944, + 667, 667, 611, 278, 278, 278, 469, 556, + 222, 556, 556, 500, 556, 556, 278, 556, + 556, 222, 222, 500, 222, 833, 556, 556, + 556, 556, 333, 500, 278, 556, 500, 722, + 500, 500, 500, 334, 260, 334, 584, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 333, 556, 556, 167, 556, 556, 556, + 556, 191, 333, 556, 333, 333, 500, 500, + -1, 556, 556, 556, 278, -1, 537, 350, + 222, 333, 333, 556, 1000, 1000, -1, 611, + -1, 333, 333, 333, 333, 333, 333, 333, + 333, -1, 333, 333, -1, 333, 333, 333, + 1000, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 1000, -1, 370, -1, -1, -1, -1, + 556, 778, 1000, 365, -1, -1, -1, -1, + -1, 889, -1, -1, -1, 278, -1, -1, + 222, 611, 944, 611, -1, -1, -1, -1 + } +}; + +/*************************************************************************** + * Helper functions + ***************************************************************************/ + + +/** Get the context pointer from an ADraw structure. + */ +static SvgContext *getSvgCtx(struct ADrawTag *ctx) +{ + return (SvgContext *)ctx->internal; +} + +/** Get the context pointer from an ADraw structure. + */ +static FILE *getSvgFile(struct ADrawTag *ctx) +{ + return getSvgCtx(ctx)->of; +} + +static const char *getSvgPen(struct ADrawTag *ctx) +{ + return getSvgCtx(ctx)->penColName; +} + +static const char *getSvgBgPen(struct ADrawTag *ctx) +{ + return getSvgCtx(ctx)->penBgColName; +} + +/** Given a font metric measurement, return device dependent units. + * Font metric data is stored as 1/1000th of a point, and therefore + * needs to be multiplied by the font point size and divided by + * 1000 to give a value in device dependent units. + */ +static int getSpace(struct ADrawTag *ctx, long thousanths) +{ + return ((thousanths * getSvgCtx(ctx)->fontPoints) + 500) / 1000; +} + + +/** Compute a point on an ellipse. + * This computes the point on an ellipse. + * + * \param[in] cx,cy Center of the ellipse. + * \param[in] w,h Ellipse width and height. + * \param[in] a Angle in degrees. + * \param[in,out] x,y Pointer to be populated with result co-ordinates. + */ +static void arcPoint(float cx, + float cy, + float w, + float h, + float a, + unsigned int *x, + unsigned int *y) +{ + float rad = (float)((a * M_PI) / 180.0f); + + /* Compute point, noting this is for SVG co-ordinate system */ + *x = (unsigned int)round(cx + ((w / 2.0f) * cos(rad))); + *y = (unsigned int)round(cy + ((h / 2.0f) * sin(rad))); +} + + +/** Write out a line of text, escaping special characters. + */ +static void writeEscaped(struct ADrawTag *ctx, const char *string) +{ + FILE *f = getSvgFile(ctx); + + while(*string != '\0') + { + unsigned int code, bytes; + + switch(*string) + { + case '<': fprintf(f, "<"); break; + case '>': fprintf(f, ">"); break; + case '"': fprintf(f, """); break; + case '&': fprintf(f, "&"); break; + default: + if(Utf8Decode(string, &code, &bytes)) + { + fprintf(f, "&#x%x;", code); + string += bytes - 1; + } + else + { + fputc(*string, f); + } + break; + + } + + string++; + } +} + + + +static void svgRect(struct ADrawTag *ctx, + const char *colour, + unsigned int x1, + unsigned int y1, + unsigned int x2, + unsigned int y2) +{ + fprintf(getSvgFile(ctx), + "<polygon fill=\"%s\" points=\"%u,%u %u,%u %u,%u %u,%u\"/>\n", + colour, + x1, y1, + x2, y1, + x2, y2, + x1, y2); +} + +static const char *svgColour(ADrawColour col) +{ + switch(col) + { + case ADRAW_COL_WHITE: + return "white"; + + case ADRAW_COL_BLACK: + return "black"; + + case ADRAW_COL_BLUE: + return "blue"; + + case ADRAW_COL_RED: + return "red"; + + case ADRAW_COL_GREEN: + return "green"; + + default: + return NULL; + } +} + + +/*************************************************************************** + * API Functions + ***************************************************************************/ + +unsigned int SvgTextWidth(struct ADrawTag *ctx, + const char *string) +{ + unsigned long width = 0; + + while(*string != '\0') + { + int i = *string & 0xff; + unsigned long w = SvgHelvetica.widths[i]; + + /* Ignore undefined characters */ + width += w > 0 ? w : 0; + + string++; + } + + return getSpace(ctx, width); +} + + +int SvgTextHeight(struct ADrawTag *ctx) +{ + return getSpace(ctx, SvgHelvetica.ascender - SvgHelvetica.descender); +} + + +void SvgLine(struct ADrawTag *ctx, + unsigned int x1, + unsigned int y1, + unsigned int x2, + unsigned int y2) +{ + fprintf(getSvgFile(ctx), + "<line x1=\"%u\" y1=\"%u\" x2=\"%u\" y2=\"%u\" stroke=\"%s\"/>\n", + x1, y1, x2, y2, getSvgPen(ctx)); + +} + + +void SvgDottedLine(struct ADrawTag *ctx, + unsigned int x1, + unsigned int y1, + unsigned int x2, + unsigned int y2) +{ + fprintf(getSvgFile(ctx), + "<line x1=\"%u\" y1=\"%u\" x2=\"%u\" y2=\"%u\" stroke=\"%s\" stroke-dasharray=\"2,2\"/>\n", + x1, y1, x2, y2, getSvgPen(ctx)); +} + + +void SvgTextR(struct ADrawTag *ctx, + unsigned int x, + unsigned int y, + const char *string) +{ + SvgContext *context = getSvgCtx(ctx); + + svgRect(ctx, getSvgBgPen(ctx), x - 2, y - SvgTextHeight(ctx) + 1, x + SvgTextWidth(ctx, string), y - 1); + + y += getSpace(ctx, SvgHelvetica.descender); + + fprintf(getSvgFile(ctx), + "<text x=\"%u\" y=\"%u\" textLength=\"%u\" font-family=\"Helvetica\" font-size=\"%u\" fill=\"%s\">\n", + x - 1, y, SvgTextWidth(ctx, string), context->fontPoints, context->penColName); + writeEscaped(ctx, string); + fprintf(getSvgFile(ctx), "\n</text>\n"); +} + + +void SvgTextL(struct ADrawTag *ctx, + unsigned int x, + unsigned int y, + const char *string) +{ + SvgContext *context = getSvgCtx(ctx); + + svgRect(ctx, getSvgBgPen(ctx), x - (SvgTextWidth(ctx, string) + 2), y - SvgTextHeight(ctx) + 1, x, y - 1); + + y += getSpace(ctx, SvgHelvetica.descender); + + fprintf(getSvgFile(ctx), + "<text x=\"%u\" y=\"%u\" textLength=\"%u\" font-family=\"Helvetica\" font-size=\"%u\" fill=\"%s\" text-anchor=\"end\">\n", + x, y, SvgTextWidth(ctx, string), context->fontPoints, context->penColName); + writeEscaped(ctx, string); + fprintf(getSvgFile(ctx), "\n</text>\n"); + + +} + + +void SvgTextC(struct ADrawTag *ctx, + unsigned int x, + unsigned int y, + const char *string) +{ + SvgContext *context = getSvgCtx(ctx); + unsigned int hw = SvgTextWidth(ctx, string) / 2; + + svgRect(ctx, getSvgBgPen(ctx), x - (hw + 2), y - SvgTextHeight(ctx) + 1, x + hw, y - 1); + + y += getSpace(ctx, SvgHelvetica.descender); + + fprintf(getSvgFile(ctx), + "<text x=\"%u\" y=\"%u\" textLength=\"%u\" font-family=\"Helvetica\" font-size=\"%u\" fill=\"%s\" text-anchor=\"middle\">\n\n", + x, y, SvgTextWidth(ctx, string), context->fontPoints, context->penColName); + writeEscaped(ctx, string); + fprintf(getSvgFile(ctx), "\n</text>\n"); +} + + +void SvgFilledTriangle(struct ADrawTag *ctx, + unsigned int x1, + unsigned int y1, + unsigned int x2, + unsigned int y2, + unsigned int x3, + unsigned int y3) +{ + + fprintf(getSvgFile(ctx), + "<polygon fill=\"%s\" points=\"%u,%u %u,%u %u,%u\"/>\n", + getSvgPen(ctx), + x1, y1, + x2, y2, + x3, y3); +} + + +void SvgFilledCircle(struct ADrawTag *ctx, + unsigned int x, + unsigned int y, + unsigned int r) +{ + fprintf(getSvgFile(ctx), + "<circle fill=\"%s\" cx=\"%u\" cy=\"%u\" r=\"%u\"/>\n", + getSvgPen(ctx), + x, y, r); +} + + +void SvgFilledRectangle(struct ADrawTag *ctx, + unsigned int x1, + unsigned int y1, + unsigned int x2, + unsigned int y2) +{ + svgRect(ctx, getSvgPen(ctx), x1, y1, x2, y2); +} + + +void SvgArc(struct ADrawTag *ctx, + unsigned int cx, + unsigned int cy, + unsigned int w, + unsigned int h, + unsigned int s, + unsigned int e) +{ + unsigned int sx, sy, ex, ey; + + /* Get start and end x,y */ + arcPoint((float)cx, (float)cy, (float)w, (float)h, (float)s, &sx, &sy); + arcPoint((float)cx, (float)cy, (float)w, (float)h, (float)e, &ex, &ey); + + fprintf(getSvgFile(ctx), + "<path d=\"M %u %u A%u,%u 0 0,1 %u,%u\" stroke=\"%s\" fill=\"none\"/>", + sx, sy, w / 2, h / 2, ex, ey, getSvgPen(ctx)); +} + + +void SvgDottedArc(struct ADrawTag *ctx, + unsigned int cx, + unsigned int cy, + unsigned int w, + unsigned int h, + unsigned int s, + unsigned int e) +{ + unsigned int sx, sy, ex, ey; + + /* Get start and end x,y */ + arcPoint((float)cx, (float)cy, (float)w, (float)h, (float)s, &sx, &sy); + arcPoint((float)cx, (float)cy, (float)w, (float)h, (float)e, &ex, &ey); + + + fprintf(getSvgFile(ctx), + "<path d=\"M %u %u A%u,%u 0 0,1 %u,%u\" stroke=\"%s\" fill=\"none\" stroke-dasharray=\"2,2\"/>", + sx, sy, w / 2, h / 2, ex, ey, getSvgPen(ctx)); +} + + +void SvgSetPen(struct ADrawTag *ctx, + ADrawColour col) +{ + static char colCmd[10]; + + getSvgCtx(ctx)->penColName = svgColour(col); + if(getSvgCtx(ctx)->penColName == NULL) + { + /* Print the RGB value into the local storage */ + sprintf(colCmd, "#%06X", col); + + /* Now set the colour name to the local store */ + getSvgCtx(ctx)->penColName = colCmd; + } +} + + +void SvgSetBgPen(struct ADrawTag *ctx, + ADrawColour col) +{ + static char colCmd[10]; + + getSvgCtx(ctx)->penBgColName = svgColour(col); + if(getSvgCtx(ctx)->penBgColName == NULL) + { + /* Print the RGB value into the local storage */ + sprintf(colCmd, "#%06X", col); + + /* Now set the colour name to the local store */ + getSvgCtx(ctx)->penBgColName = colCmd; + } +} + + +void SvgSetFontSize(struct ADrawTag *ctx, + ADrawFontSize size) +{ + SvgContext *context = getSvgCtx(ctx); + + switch(size) + { + case ADRAW_FONT_TINY: + context->fontPoints = 8; + break; + + case ADRAW_FONT_SMALL: + context->fontPoints = 12; + break; + + default: + assert(0); + } + +} + + +Boolean SvgClose(struct ADrawTag *ctx) +{ + SvgContext *context = getSvgCtx(ctx); + + /* Close the SVG */ + fprintf(context->of, "</svg>\n"); + + /* Close the output file */ + if(context->of != stdout) + { + fclose(context->of); + } + + /* Free and destroy context */ + free(context); + ctx->internal = NULL; + + return TRUE; +} + + + +Boolean SvgInit(unsigned int w, + unsigned int h, + const char *file, + struct ADrawTag *outContext) +{ + SvgContext *context; + + /* Create context */ + context = outContext->internal = malloc_s(sizeof(SvgContext)); + if(context == NULL) + { + return FALSE; + } + + /* Open the output file */ + if(strcmp(file, "-") == 0) + { + context->of = stdout; + } + else + { + context->of = fopen(file, "wb"); + if(!context->of) + { + fprintf(stderr, "SvgInit: Failed to open output file '%s': %s\n", file, strerror(errno)); + return FALSE; + } + } + + /* Set the initial pen state */ + SvgSetPen(outContext, ADRAW_COL_BLACK); + SvgSetBgPen(outContext, ADRAW_COL_WHITE); + + /* Default to small font */ + SvgSetFontSize(outContext, ADRAW_FONT_SMALL); + + fprintf(context->of, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n" + " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n"); + + fprintf(context->of, "<svg version=\"1.1\"\n" + " width=\"%upx\" height=\"%upx\"\n" + " viewBox=\"0 0 %u %u\"\n" + " xmlns=\"http://www.w3.org/2000/svg\" shape-rendering=\"crispEdges\"\n" + " stroke-width=\"1\" text-rendering=\"geometricPrecision\">\n", + w, h, w, h); + + /* Now fill in the function pointers */ + outContext->line = SvgLine; + outContext->dottedLine = SvgDottedLine; + outContext->textL = SvgTextL; + outContext->textC = SvgTextC; + outContext->textR = SvgTextR; + outContext->textWidth = SvgTextWidth; + outContext->textHeight = SvgTextHeight; + outContext->filledRectangle = SvgFilledRectangle; + outContext->filledTriangle = SvgFilledTriangle; + outContext->filledCircle = SvgFilledCircle; + outContext->arc = SvgArc; + outContext->dottedArc = SvgDottedArc; + outContext->setPen = SvgSetPen; + outContext->setBgPen = SvgSetBgPen; + outContext->setFontSize = SvgSetFontSize; + outContext->close = SvgClose; + + return TRUE; +} + +/* END OF FILE */ diff --git a/libmscgen/mscgen_usage.c b/libmscgen/mscgen_usage.c new file mode 100644 index 0000000..2126d44 --- /dev/null +++ b/libmscgen/mscgen_usage.c @@ -0,0 +1,111 @@ +/*************************************************************************** + * + * $Id: main.c 75 2009-07-26 14:45:59Z Michael.McTernan $ + * + * This file is part of mscgen, a message sequence chart renderer. + * Copyright (C) 2010 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + **************************************************************************/ + +/*************************************************************************** + * Include Files + ***************************************************************************/ + +#include "mscgen_config.h" +#include <stdio.h> +#include "mscgen_usage.h" + +/*************************************************************************** + * Types + ***************************************************************************/ + +/*************************************************************************** + * Local Variables. + ***************************************************************************/ + +/*************************************************************************** + * Functions + ***************************************************************************/ + +/** Print program usage and return. + */ +void Usage(void) +{ + printf( +"Usage: mscgen -T <type> [-o <file>] [-i] <infile>\n" +" mscgen -l\n" +"\n" +"Where:\n" +" -T <type> Specifies the output file type, which maybe one of 'png', 'eps',\n" +" 'svg' or 'ismap'\n" +" -i <infile> The file from which to read input. If omitted or specified as\n" +" '-', input will be read from stdin. The '-i' flag maybe\n" +" omitted if <infile> is specified as the last option on the\n" +" command line.\n" +" -o <file> Write output to the named file. This option must be specified if \n" +" input is taken from stdin, otherwise the output filename\n" +" defaults to <infile>.<type>. This may also be specified as '-'\n" +" to write output directly to stdout.\n" +#ifdef USE_FREETYPE +" -F <font> Use specified font for PNG output. This must be a font specifier\n" +" compatbile with fontconfig (see 'fc-list'), and overrides the\n" +" MSCGEN_FONT environment variable if also set.\n" +#endif +" -p Print parsed msc output (for parser debug).\n" +" -l Display program licence and exit.\n" +"\n" +"Mscgen version %s, Copyright (C) 2010 Michael C McTernan,\n" +" Michael.McTernan.2001@cs.bris.ac.uk\n" +"Mscgen comes with ABSOLUTELY NO WARRANTY. This is free software, and you are\n" +"welcome to redistribute it under certain conditions; type `mscgen -l' for\n" +"details.\n" +"\n" +"PNG rendering by libgd, www.libgd.org\n" +"\n", +PACKAGE_VERSION); +} + + +/** Print program licence and return. + */ +void Licence(void) +{ + printf( +"Mscgen, a message sequence chart renderer.\n" +"Copyright (C) 2010 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk\n" +"\n" +"TTPCom Ltd., hereby disclaims all copyright interest in the program `mscgen'\n" +"(which renders message sequence charts) written by Michael McTernan.\n" +"\n" +"Rob Meades of TTPCom Ltd, 1 August 2005\n" +"Rob Meades, director of Software\n" +"\n" +"This program is free software; you can redistribute it and/or modify\n" +"it under the terms of the GNU General Public License as published by\n" +"the Free Software Foundation; either version 2 of the License, or\n" +"(at your option) any later version.\n" +"\n" +"This program is distributed in the hope that it will be useful,\n" +"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +"GNU General Public License for more details.\n" +"\n" +"You should have received a copy of the GNU General Public License\n" +"along with this program; if not, write to the Free Software\n" +"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA\n"); +} + +/* END OF FILE */ diff --git a/libmscgen/mscgen_usage.h b/libmscgen/mscgen_usage.h new file mode 100644 index 0000000..0aab946 --- /dev/null +++ b/libmscgen/mscgen_usage.h @@ -0,0 +1,49 @@ +/***************************************************************************
+ *
+ * $Id: safe.h 59 2009-07-18 17:31:50Z Michael.McTernan $
+ *
+ * This file is part of mscgen, a message sequence chart renderer.
+ * Copyright (C) 2005 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ **************************************************************************/
+
+#ifndef MSCGEN_USAGE_H
+#define MSCGEN_USAGE_H
+
+/*****************************************************************************
+ * Header Files
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preprocessor Macros & Constants
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Typedefs
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Global Variable Declarations
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Global Function Declarations
+ *****************************************************************************/
+
+void Usage(void);
+void Licence(void);
+
+#endif /* MSCGEN_USAGE_H */
diff --git a/libmscgen/mscgen_utf8.c b/libmscgen/mscgen_utf8.c new file mode 100644 index 0000000..9614c47 --- /dev/null +++ b/libmscgen/mscgen_utf8.c @@ -0,0 +1,103 @@ +/***************************************************************************
+ *
+ * $Id: utf8.c 93 2009-08-24 20:57:31Z Michael.McTernan $
+ *
+ * UTF8 decode routine.
+ * Copyright (C) 2008 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ **************************************************************************/
+
+/**************************************************************************
+ * Includes
+ **************************************************************************/
+
+#include "mscgen_utf8.h"
+
+/**************************************************************************
+ * Manfest Constants
+ **************************************************************************/
+
+/**************************************************************************
+ * Macros
+ **************************************************************************/
+
+/**************************************************************************
+ * Types
+ **************************************************************************/
+
+/**************************************************************************
+ * Local Variables
+ **************************************************************************/
+
+/**************************************************************************
+ * Local Functions
+ **************************************************************************/
+
+/** Count leading ones from the MSB.
+ */
+static unsigned int clo(char c)
+{
+ unsigned int t = 0;
+
+ while((c & (0x80 >> t)) != 0 && t < 8)
+ {
+ t++;
+ }
+
+ return t;
+}
+
+/**************************************************************************
+ * Global Functions
+ **************************************************************************/
+
+Boolean Utf8Decode(const char *s, unsigned int *r, unsigned int *bytes)
+{
+ if((*s & 0x80) == 0)
+ {
+ return FALSE;
+ }
+ else
+ {
+ unsigned int t;
+
+ /* Set default return values */
+ *bytes = clo(*s);
+ *r = 0;
+
+ /* Loop through string, checking for null termination */
+ for(t = 0; t < *bytes && s[t] != '\0'; t++)
+ {
+ /* Shift up previous bits */
+ *r <<= 6;
+
+ /* Add the required bits */
+ if(t == 0)
+ {
+ *r |= s[t] & (0xff >> (*bytes + 1));
+ }
+ else
+ {
+ *r |= s[t] & 0x3f;
+ }
+ }
+
+ /* Success if no NULL was encoutered */
+ return t == *bytes;
+ }
+}
+
+/* END OF FILE */
diff --git a/libmscgen/mscgen_utf8.h b/libmscgen/mscgen_utf8.h new file mode 100644 index 0000000..a0ea954 --- /dev/null +++ b/libmscgen/mscgen_utf8.h @@ -0,0 +1,48 @@ +/***************************************************************************
+ *
+ * $Id: utf8.h 93 2009-08-24 20:57:31Z Michael.McTernan $
+ *
+ * UTF8 decode routine interface.
+ * Copyright (C) 2009 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef MSCGEN_UTF8_H
+#define MSCGEN_UTF8_H
+
+/**************************************************************************
+ * Includes
+ **************************************************************************/
+
+#include "mscgen_bool.h"
+
+/**************************************************************************
+ * Macros
+ **************************************************************************/
+
+/**************************************************************************
+ * Types
+ **************************************************************************/
+
+/**************************************************************************
+ * Prototypes
+ **************************************************************************/
+
+Boolean Utf8Decode(const char *s, unsigned int *r, unsigned int *bytes);
+
+#endif
+
+/* END OF FILE */
|