2019-09-11 11:14:42 +03:00
/* svg.c - Scalable Vector Graphics */
/*
libzint - the open source barcode library
2020-04-04 18:53:29 +03:00
Copyright ( C ) 2009 - 2020 Robin Stuart < rstuart114 @ gmail . com >
2019-09-11 11:14:42 +03:00
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions
are met :
1. Redistributions of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
2. Redistributions in binary form must reproduce the above copyright
notice , this list of conditions and the following disclaimer in the
documentation and / or other materials provided with the distribution .
3. Neither the name of the project nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS " AND
ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION )
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT
LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE .
*/
2019-11-27 19:16:14 +03:00
/* vim: set ts=4 sw=4 et : */
2019-09-11 11:14:42 +03:00
# include <locale.h>
# include <string.h>
# include <stdio.h>
# include <math.h>
# ifdef _MSC_VER
# include <malloc.h>
# endif
# include "common.h"
2019-12-18 21:33:18 +03:00
void pick_colour ( int colour , char colour_code [ ] ) {
switch ( colour ) {
case 0 : // White
strcpy ( colour_code , " ffffff " ) ;
break ;
case 1 : // Cyan
strcpy ( colour_code , " 00ffff " ) ;
break ;
case 2 : // Blue
strcpy ( colour_code , " 0000ff " ) ;
break ;
case 3 : // Magenta
strcpy ( colour_code , " ff00ff " ) ;
break ;
case 4 : // Red
strcpy ( colour_code , " ff0000 " ) ;
break ;
case 5 : // Yellow
strcpy ( colour_code , " ffff00 " ) ;
break ;
case 6 : // Green
strcpy ( colour_code , " 00ff00 " ) ;
break ;
default : // Black
strcpy ( colour_code , " 000000 " ) ;
break ;
}
}
2019-12-19 03:37:55 +03:00
static void make_html_friendly ( unsigned char * string , char * html_version ) {
2019-10-30 11:40:26 +03:00
/* Converts text to use HTML entity codes */
int i , html_pos ;
html_pos = 0 ;
html_version [ html_pos ] = ' \0 ' ;
2020-04-04 18:53:29 +03:00
for ( i = 0 ; i < ( int ) ustrlen ( string ) ; i + + ) {
2019-10-30 11:40:26 +03:00
switch ( string [ i ] ) {
case ' > ' :
strcat ( html_version , " > " ) ;
2019-10-16 20:42:22 +03:00
html_pos + = 4 ;
2019-10-30 11:40:26 +03:00
break ;
case ' < ' :
strcat ( html_version , " < " ) ;
2019-10-16 20:42:22 +03:00
html_pos + = 4 ;
2019-10-30 11:40:26 +03:00
break ;
case ' & ' :
strcat ( html_version , " & " ) ;
2019-10-16 20:42:22 +03:00
html_pos + = 5 ;
2019-10-30 11:40:26 +03:00
break ;
case ' " ' :
strcat ( html_version , " " " ) ;
html_pos + = 6 ;
break ;
2019-11-03 14:51:12 +03:00
case ' \' ' :
strcat ( html_version , " ' " ) ;
html_pos + = 6 ;
2019-10-30 11:40:26 +03:00
break ;
default :
2019-10-16 20:42:22 +03:00
html_version [ html_pos ] = string [ i ] ;
html_pos + + ;
html_version [ html_pos ] = ' \0 ' ;
break ;
}
2019-10-30 11:40:26 +03:00
}
2019-10-16 20:42:22 +03:00
}
2019-12-19 03:37:55 +03:00
INTERNAL int svg_plot ( struct zint_symbol * symbol ) {
2019-09-11 11:14:42 +03:00
FILE * fsvg ;
int error_number = 0 ;
const char * locale = NULL ;
float ax , ay , bx , by , cx , cy , dx , dy , ex , ey , fx , fy ;
float radius ;
2019-11-17 21:30:55 +03:00
int i ;
2019-10-30 11:40:26 +03:00
2019-09-11 11:14:42 +03:00
struct zint_vector_rect * rect ;
struct zint_vector_hexagon * hex ;
struct zint_vector_circle * circle ;
struct zint_vector_string * string ;
2019-10-30 11:40:26 +03:00
2019-12-18 21:33:18 +03:00
char colour_code [ 7 ] ;
2019-11-17 21:30:55 +03:00
# ifdef _MSC_VER
char * html_string ;
# endif
2019-10-30 11:40:26 +03:00
int html_len = strlen ( ( char * ) symbol - > text ) + 1 ;
2020-04-04 18:53:29 +03:00
for ( i = 0 ; i < ( int ) strlen ( ( char * ) symbol - > text ) ; i + + ) {
2019-10-30 11:40:26 +03:00
switch ( symbol - > text [ i ] ) {
case ' > ' :
case ' < ' :
case ' " ' :
case ' & ' :
2019-11-03 14:51:12 +03:00
case ' \' ' :
html_len + = 6 ;
2019-10-30 11:40:26 +03:00
break ;
}
}
2019-10-16 20:42:22 +03:00
# ifndef _MSC_VER
2019-10-30 11:40:26 +03:00
char html_string [ html_len ] ;
2019-10-16 20:42:22 +03:00
# else
2019-11-17 21:30:55 +03:00
html_string = ( char * ) _alloca ( html_len ) ;
2019-10-16 20:42:22 +03:00
# endif
2019-09-11 11:14:42 +03:00
/* Check for no created vector set */
/* E-Mail Christian Schmitz 2019-09-10: reason unknown Ticket #164*/
if ( symbol - > vector = = NULL ) {
return ZINT_ERROR_INVALID_DATA ;
}
if ( symbol - > output_options & BARCODE_STDOUT ) {
fsvg = stdout ;
} else {
fsvg = fopen ( symbol - > outfile , " w " ) ;
}
if ( fsvg = = NULL ) {
strcpy ( symbol - > errtxt , " 660: Could not open output file " ) ;
return ZINT_ERROR_FILE_ACCESS ;
}
locale = setlocale ( LC_ALL , " C " ) ;
/* Start writing the header */
fprintf ( fsvg , " <?xml version= \" 1.0 \" standalone= \" no \" ?> \n " ) ;
fprintf ( fsvg , " <!DOCTYPE svg PUBLIC \" -//W3C//DTD SVG 1.1//EN \" \n " ) ;
fprintf ( fsvg , " \" http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd \" > \n " ) ;
fprintf ( fsvg , " <svg width= \" %d \" height= \" %d \" version= \" 1.1 \" \n " , ( int ) ceil ( symbol - > vector - > width ) , ( int ) ceil ( symbol - > vector - > height ) ) ;
fprintf ( fsvg , " xmlns= \" http://www.w3.org/2000/svg \" > \n " ) ;
fprintf ( fsvg , " <desc>Zint Generated Symbol \n " ) ;
fprintf ( fsvg , " </desc> \n " ) ;
fprintf ( fsvg , " \n <g id= \" barcode \" fill= \" #%s \" > \n " , symbol - > fgcolour ) ;
fprintf ( fsvg , " <rect x= \" 0 \" y= \" 0 \" width= \" %d \" height= \" %d \" fill= \" #%s \" /> \n " , ( int ) ceil ( symbol - > vector - > width ) , ( int ) ceil ( symbol - > vector - > height ) , symbol - > bgcolour ) ;
rect = symbol - > vector - > rectangles ;
while ( rect ) {
2019-12-18 21:33:18 +03:00
if ( rect - > colour = = - 1 ) {
fprintf ( fsvg , " <rect x= \" %.2f \" y= \" %.2f \" width= \" %.2f \" height= \" %.2f \" /> \n " , rect - > x , rect - > y , rect - > width , rect - > height ) ;
} else {
pick_colour ( rect - > colour , colour_code ) ;
fprintf ( fsvg , " <rect x= \" %.2f \" y= \" %.2f \" width= \" %.2f \" height= \" %.2f \" fill= \" #%s \" /> \n " , rect - > x , rect - > y , rect - > width , rect - > height , colour_code ) ;
}
2019-09-11 11:14:42 +03:00
rect = rect - > next ;
}
2019-10-30 11:40:26 +03:00
2019-09-11 11:14:42 +03:00
hex = symbol - > vector - > hexagons ;
while ( hex ) {
radius = hex - > diameter / 2.0 ;
ay = hex - > y + ( 1.0 * radius ) ;
by = hex - > y + ( 0.5 * radius ) ;
cy = hex - > y - ( 0.5 * radius ) ;
dy = hex - > y - ( 1.0 * radius ) ;
ey = hex - > y - ( 0.5 * radius ) ;
fy = hex - > y + ( 0.5 * radius ) ;
ax = hex - > x ;
bx = hex - > x + ( 0.86 * radius ) ;
cx = hex - > x + ( 0.86 * radius ) ;
dx = hex - > x ;
ex = hex - > x - ( 0.86 * radius ) ;
fx = hex - > x - ( 0.86 * radius ) ;
fprintf ( fsvg , " <path d= \" M %.2f %.2f L %.2f %.2f L %.2f %.2f L %.2f %.2f L %.2f %.2f L %.2f %.2f Z \" /> \n " , ax , ay , bx , by , cx , cy , dx , dy , ex , ey , fx , fy ) ;
hex = hex - > next ;
}
2019-10-30 11:40:26 +03:00
2019-09-11 11:14:42 +03:00
circle = symbol - > vector - > circles ;
while ( circle ) {
if ( circle - > colour ) {
fprintf ( fsvg , " <circle cx= \" %.2f \" cy= \" %.2f \" r= \" %.2f \" fill= \" #%s \" /> \n " , circle - > x , circle - > y , circle - > diameter / 2.0 , symbol - > bgcolour ) ;
} else {
fprintf ( fsvg , " <circle cx= \" %.2f \" cy= \" %.2f \" r= \" %.2f \" fill= \" #%s \" /> \n " , circle - > x , circle - > y , circle - > diameter / 2.0 , symbol - > fgcolour ) ;
}
circle = circle - > next ;
}
2019-10-30 11:40:26 +03:00
2019-09-11 11:14:42 +03:00
string = symbol - > vector - > strings ;
while ( string ) {
fprintf ( fsvg , " <text x= \" %.2f \" y= \" %.2f \" text-anchor= \" middle \" \n " , string - > x , string - > y ) ;
fprintf ( fsvg , " font-family= \" Helvetica \" font-size= \" %.1f \" fill= \" #%s \" > \n " , string - > fsize , symbol - > fgcolour ) ;
2019-10-16 20:42:22 +03:00
make_html_friendly ( string - > text , html_string ) ;
fprintf ( fsvg , " %s \n " , html_string ) ;
2019-09-11 11:14:42 +03:00
fprintf ( fsvg , " </text> \n " ) ;
string = string - > next ;
}
fprintf ( fsvg , " </g> \n " ) ;
fprintf ( fsvg , " </svg> \n " ) ;
if ( symbol - > output_options & BARCODE_STDOUT ) {
fflush ( fsvg ) ;
} else {
fclose ( fsvg ) ;
}
if ( locale )
setlocale ( LC_ALL , locale ) ;
return error_number ;
}