2022-07-14 18:01:30 +03:00
/* vector.c - Creates vector image objects */
/*
2018-06-10 11:16:18 +03:00
libzint - the open source barcode library
2023-02-10 17:44:10 +03:00
Copyright ( C ) 2018 - 2023 Robin Stuart < rstuart114 @ gmail . com >
2018-06-10 11:16:18 +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 .
*/
2022-07-14 18:01:30 +03:00
/* SPDX-License-Identifier: BSD-3-Clause */
2018-06-10 11:16:18 +03:00
# include "common.h"
2020-05-21 20:22:28 +03:00
# include "output.h"
2021-05-15 14:23:46 +03:00
# include "zfiletypes.h"
2018-06-10 11:16:18 +03:00
2019-12-19 03:37:55 +03:00
INTERNAL int ps_plot ( struct zint_symbol * symbol ) ;
INTERNAL int svg_plot ( struct zint_symbol * symbol ) ;
2020-09-30 14:19:12 +03:00
INTERNAL int emf_plot ( struct zint_symbol * symbol , int rotate_angle ) ;
2018-06-10 11:16:18 +03:00
2023-06-12 03:25:55 +03:00
static int vector_add_rect ( struct zint_symbol * symbol , const float x , const float y , const float width ,
const float height , struct zint_vector_rect * * last_rect ) {
2018-06-10 11:16:18 +03:00
struct zint_vector_rect * rect ;
2021-06-10 13:15:39 +03:00
rect = ( struct zint_vector_rect * ) malloc ( sizeof ( struct zint_vector_rect ) ) ;
2021-09-20 16:56:27 +03:00
if ( ! rect ) {
strcpy ( symbol - > errtxt , " 691: Insufficient memory for vector rectangle " ) ;
2023-06-12 03:25:55 +03:00
return 0 ;
2021-09-20 16:56:27 +03:00
}
2018-06-10 11:16:18 +03:00
rect - > next = NULL ;
rect - > x = x ;
rect - > y = y ;
rect - > width = width ;
rect - > height = height ;
2022-07-14 18:01:30 +03:00
rect - > colour = - 1 ; /* Default colour */
2018-06-10 11:16:18 +03:00
if ( * last_rect )
( * last_rect ) - > next = rect ;
else
2022-07-14 18:01:30 +03:00
symbol - > vector - > rectangles = rect ; /* first rectangle */
2018-06-10 11:16:18 +03:00
* last_rect = rect ;
2023-06-12 03:25:55 +03:00
return 1 ;
2018-06-10 11:16:18 +03:00
}
2023-06-12 03:25:55 +03:00
static int vector_add_hexagon ( struct zint_symbol * symbol , const float x , const float y ,
const float diameter , struct zint_vector_hexagon * * last_hexagon ) {
2018-06-10 11:16:18 +03:00
struct zint_vector_hexagon * hexagon ;
2021-06-10 13:15:39 +03:00
hexagon = ( struct zint_vector_hexagon * ) malloc ( sizeof ( struct zint_vector_hexagon ) ) ;
2021-09-20 16:56:27 +03:00
if ( ! hexagon ) {
strcpy ( symbol - > errtxt , " 692: Insufficient memory for vector hexagon " ) ;
2023-06-12 03:25:55 +03:00
return 0 ;
2021-09-20 16:56:27 +03:00
}
2018-06-10 11:16:18 +03:00
hexagon - > next = NULL ;
hexagon - > x = x ;
hexagon - > y = y ;
2020-10-26 15:21:43 +03:00
hexagon - > diameter = diameter ;
2020-08-05 23:23:11 +03:00
hexagon - > rotation = 0 ;
2018-06-10 11:16:18 +03:00
if ( * last_hexagon )
( * last_hexagon ) - > next = hexagon ;
else
2022-07-14 18:01:30 +03:00
symbol - > vector - > hexagons = hexagon ; /* first hexagon */
2018-06-10 11:16:18 +03:00
* last_hexagon = hexagon ;
2023-06-12 03:25:55 +03:00
return 1 ;
2018-06-10 11:16:18 +03:00
}
2023-06-12 03:25:55 +03:00
static int vector_add_circle ( struct zint_symbol * symbol , const float x , const float y , const float diameter ,
const float width , const int colour , struct zint_vector_circle * * last_circle ) {
2018-06-10 11:16:18 +03:00
struct zint_vector_circle * circle ;
2021-06-10 13:15:39 +03:00
circle = ( struct zint_vector_circle * ) malloc ( sizeof ( struct zint_vector_circle ) ) ;
2021-09-20 16:56:27 +03:00
if ( ! circle ) {
strcpy ( symbol - > errtxt , " 693: Insufficient memory for vector circle " ) ;
2023-06-12 03:25:55 +03:00
return 0 ;
2021-09-20 16:56:27 +03:00
}
2018-06-10 11:16:18 +03:00
circle - > next = NULL ;
circle - > x = x ;
circle - > y = y ;
circle - > diameter = diameter ;
2021-08-22 15:59:01 +03:00
circle - > width = width ;
2018-06-10 11:16:18 +03:00
circle - > colour = colour ;
if ( * last_circle )
( * last_circle ) - > next = circle ;
else
2022-07-14 18:01:30 +03:00
symbol - > vector - > circles = circle ; /* first circle */
2018-06-10 11:16:18 +03:00
* last_circle = circle ;
2023-06-12 03:25:55 +03:00
return 1 ;
2018-06-10 11:16:18 +03:00
}
2023-06-12 03:25:55 +03:00
static int vector_add_string ( struct zint_symbol * symbol , const unsigned char * text , const int length ,
2021-09-20 16:56:27 +03:00
const float x , const float y , const float fsize , const float width , const int halign ,
struct zint_vector_string * * last_string ) {
2018-06-10 11:16:18 +03:00
struct zint_vector_string * string ;
2021-06-10 13:15:39 +03:00
string = ( struct zint_vector_string * ) malloc ( sizeof ( struct zint_vector_string ) ) ;
2021-09-20 16:56:27 +03:00
if ( ! string ) {
strcpy ( symbol - > errtxt , " 694: Insufficient memory for vector string " ) ;
return 0 ;
}
2018-06-10 11:16:18 +03:00
string - > next = NULL ;
string - > x = x ;
string - > y = y ;
string - > width = width ;
string - > fsize = fsize ;
2023-02-10 17:44:10 +03:00
string - > length = length = = - 1 ? ( int ) ustrlen ( text ) : length ;
2020-08-05 23:23:11 +03:00
string - > rotation = 0 ;
2020-09-30 14:19:12 +03:00
string - > halign = halign ;
2021-09-20 16:56:27 +03:00
string - > text = ( unsigned char * ) malloc ( string - > length + 1 ) ;
if ( ! string - > text ) {
free ( string ) ;
strcpy ( symbol - > errtxt , " 695: Insufficient memory for vector string text " ) ;
return 0 ;
}
2023-02-10 17:44:10 +03:00
memcpy ( string - > text , text , string - > length ) ;
string - > text [ string - > length ] = ' \0 ' ;
2018-06-10 11:16:18 +03:00
if ( * last_string )
( * last_string ) - > next = string ;
else
2022-07-14 18:01:30 +03:00
symbol - > vector - > strings = string ; /* First text portion */
2023-06-12 03:25:55 +03:00
2018-06-10 11:16:18 +03:00
* last_string = string ;
return 1 ;
}
2019-12-19 03:37:55 +03:00
INTERNAL void vector_free ( struct zint_symbol * symbol ) {
2018-06-10 11:16:18 +03:00
if ( symbol - > vector ! = NULL ) {
struct zint_vector_rect * rect ;
struct zint_vector_hexagon * hex ;
struct zint_vector_circle * circle ;
struct zint_vector_string * string ;
2022-07-14 18:01:30 +03:00
/* Free Rectangles */
2018-06-10 11:16:18 +03:00
rect = symbol - > vector - > rectangles ;
while ( rect ) {
struct zint_vector_rect * r = rect ;
rect = rect - > next ;
free ( r ) ;
}
2022-07-14 18:01:30 +03:00
/* Free Hexagons */
2018-06-10 11:16:18 +03:00
hex = symbol - > vector - > hexagons ;
while ( hex ) {
struct zint_vector_hexagon * h = hex ;
hex = hex - > next ;
free ( h ) ;
}
2022-07-14 18:01:30 +03:00
/* Free Circles */
2018-06-10 11:16:18 +03:00
circle = symbol - > vector - > circles ;
while ( circle ) {
struct zint_vector_circle * c = circle ;
circle = circle - > next ;
free ( c ) ;
}
2022-07-14 18:01:30 +03:00
/* Free Strings */
2018-06-10 11:16:18 +03:00
string = symbol - > vector - > strings ;
while ( string ) {
struct zint_vector_string * s = string ;
string = string - > next ;
free ( s - > text ) ;
free ( s ) ;
}
2022-07-14 18:01:30 +03:00
/* Free vector */
2018-06-10 11:16:18 +03:00
free ( symbol - > vector ) ;
symbol - > vector = NULL ;
}
}
2021-09-20 16:56:27 +03:00
static void vector_scale ( struct zint_symbol * symbol , const int file_type ) {
2018-06-10 11:16:18 +03:00
struct zint_vector_rect * rect ;
struct zint_vector_hexagon * hex ;
struct zint_vector_circle * circle ;
struct zint_vector_string * string ;
2020-08-09 22:20:16 +03:00
float scale = symbol - > scale * 2.0f ;
2018-06-10 11:16:18 +03:00
2022-07-14 18:01:30 +03:00
if ( scale < 0.2f ) { /* Minimum vector scale 0.1 */
2021-09-09 23:50:02 +03:00
scale = 0.2f ;
}
2020-04-01 22:01:02 +03:00
if ( ( file_type = = OUT_EMF_FILE ) & & ( symbol - > symbology = = BARCODE_MAXICODE ) ) {
2022-07-14 18:01:30 +03:00
/* Increase size to overcome limitations in EMF file format */
2020-04-01 22:01:02 +03:00
scale * = 20 ;
}
2021-09-27 01:55:16 +03:00
symbol - > vector - > width = stripf ( symbol - > vector - > width * scale ) ;
symbol - > vector - > height = stripf ( symbol - > vector - > height * scale ) ;
2018-06-10 11:16:18 +03:00
rect = symbol - > vector - > rectangles ;
while ( rect ) {
2021-09-27 01:55:16 +03:00
rect - > x = stripf ( rect - > x * scale ) ;
rect - > y = stripf ( rect - > y * scale ) ;
rect - > height = stripf ( rect - > height * scale ) ;
rect - > width = stripf ( rect - > width * scale ) ;
2018-06-10 11:16:18 +03:00
rect = rect - > next ;
}
hex = symbol - > vector - > hexagons ;
while ( hex ) {
2021-09-27 01:55:16 +03:00
hex - > x = stripf ( hex - > x * scale ) ;
hex - > y = stripf ( hex - > y * scale ) ;
hex - > diameter = stripf ( hex - > diameter * scale ) ;
2018-06-10 11:16:18 +03:00
hex = hex - > next ;
}
circle = symbol - > vector - > circles ;
while ( circle ) {
2021-09-27 01:55:16 +03:00
circle - > x = stripf ( circle - > x * scale ) ;
circle - > y = stripf ( circle - > y * scale ) ;
circle - > diameter = stripf ( circle - > diameter * scale ) ;
circle - > width = stripf ( circle - > width * scale ) ;
2018-06-10 11:16:18 +03:00
circle = circle - > next ;
}
string = symbol - > vector - > strings ;
while ( string ) {
2021-09-27 01:55:16 +03:00
string - > x = stripf ( string - > x * scale ) ;
string - > y = stripf ( string - > y * scale ) ;
string - > width = stripf ( string - > width * scale ) ;
string - > fsize = stripf ( string - > fsize * scale ) ;
2018-06-10 11:16:18 +03:00
string = string - > next ;
}
}
2021-09-20 16:56:27 +03:00
static void vector_rotate ( struct zint_symbol * symbol , const int rotate_angle ) {
2022-07-14 18:01:30 +03:00
/* Rotates the image */
2020-08-05 23:23:11 +03:00
struct zint_vector_rect * rect ;
struct zint_vector_hexagon * hex ;
struct zint_vector_circle * circle ;
struct zint_vector_string * string ;
2021-01-21 00:15:03 +03:00
float temp ;
2021-09-27 01:55:16 +03:00
2020-08-05 23:23:11 +03:00
if ( rotate_angle = = 0 ) {
2022-07-14 18:01:30 +03:00
/* No rotation needed */
2020-08-05 23:23:11 +03:00
return ;
}
2021-09-27 01:55:16 +03:00
2020-08-05 23:23:11 +03:00
rect = symbol - > vector - > rectangles ;
while ( rect ) {
if ( rotate_angle = = 90 ) {
temp = rect - > x ;
2021-09-27 01:55:16 +03:00
rect - > x = stripf ( symbol - > vector - > height - ( rect - > y + rect - > height ) ) ;
2020-08-05 23:23:11 +03:00
rect - > y = temp ;
temp = rect - > width ;
rect - > width = rect - > height ;
rect - > height = temp ;
2021-07-26 17:29:05 +03:00
} else if ( rotate_angle = = 180 ) {
2021-09-27 01:55:16 +03:00
rect - > x = stripf ( symbol - > vector - > width - ( rect - > x + rect - > width ) ) ;
rect - > y = stripf ( symbol - > vector - > height - ( rect - > y + rect - > height ) ) ;
2021-07-26 17:29:05 +03:00
} else if ( rotate_angle = = 270 ) {
2020-08-05 23:23:11 +03:00
temp = rect - > x ;
rect - > x = rect - > y ;
2021-09-27 01:55:16 +03:00
rect - > y = stripf ( symbol - > vector - > width - ( temp + rect - > width ) ) ;
2020-08-05 23:23:11 +03:00
temp = rect - > width ;
rect - > width = rect - > height ;
rect - > height = temp ;
}
rect = rect - > next ;
}
2021-09-27 01:55:16 +03:00
2020-08-05 23:23:11 +03:00
hex = symbol - > vector - > hexagons ;
while ( hex ) {
if ( rotate_angle = = 90 ) {
temp = hex - > x ;
2021-09-27 01:55:16 +03:00
hex - > x = stripf ( symbol - > vector - > height - hex - > y ) ;
2020-08-05 23:23:11 +03:00
hex - > y = temp ;
hex - > rotation = 90 ;
2021-07-26 17:29:05 +03:00
} else if ( rotate_angle = = 180 ) {
2021-09-27 01:55:16 +03:00
hex - > x = stripf ( symbol - > vector - > width - hex - > x ) ;
hex - > y = stripf ( symbol - > vector - > height - hex - > y ) ;
2020-08-05 23:23:11 +03:00
hex - > rotation = 180 ;
2021-07-26 17:29:05 +03:00
} else if ( rotate_angle = = 270 ) {
2020-08-05 23:23:11 +03:00
temp = hex - > x ;
hex - > x = hex - > y ;
2021-09-27 01:55:16 +03:00
hex - > y = stripf ( symbol - > vector - > width - temp ) ;
2020-08-05 23:23:11 +03:00
hex - > rotation = 270 ;
}
hex = hex - > next ;
}
2021-09-27 01:55:16 +03:00
2020-08-05 23:23:11 +03:00
circle = symbol - > vector - > circles ;
while ( circle ) {
if ( rotate_angle = = 90 ) {
temp = circle - > x ;
2021-09-27 01:55:16 +03:00
circle - > x = stripf ( symbol - > vector - > height - circle - > y ) ;
2020-08-05 23:23:11 +03:00
circle - > y = temp ;
2021-07-26 17:29:05 +03:00
} else if ( rotate_angle = = 180 ) {
2021-09-27 01:55:16 +03:00
circle - > x = stripf ( symbol - > vector - > width - circle - > x ) ;
circle - > y = stripf ( symbol - > vector - > height - circle - > y ) ;
2021-07-26 17:29:05 +03:00
} else if ( rotate_angle = = 270 ) {
2020-08-05 23:23:11 +03:00
temp = circle - > x ;
circle - > x = circle - > y ;
2021-09-27 01:55:16 +03:00
circle - > y = stripf ( symbol - > vector - > width - temp ) ;
2020-08-05 23:23:11 +03:00
}
circle = circle - > next ;
}
2021-09-27 01:55:16 +03:00
2020-08-05 23:23:11 +03:00
string = symbol - > vector - > strings ;
while ( string ) {
if ( rotate_angle = = 90 ) {
temp = string - > x ;
2021-09-27 01:55:16 +03:00
string - > x = stripf ( symbol - > vector - > height - string - > y ) ;
2020-08-05 23:23:11 +03:00
string - > y = temp ;
string - > rotation = 90 ;
2021-07-26 17:29:05 +03:00
} else if ( rotate_angle = = 180 ) {
2021-09-27 01:55:16 +03:00
string - > x = stripf ( symbol - > vector - > width - string - > x ) ;
string - > y = stripf ( symbol - > vector - > height - string - > y ) ;
2020-08-05 23:23:11 +03:00
string - > rotation = 180 ;
2021-07-26 17:29:05 +03:00
} else if ( rotate_angle = = 270 ) {
2020-08-05 23:23:11 +03:00
temp = string - > x ;
string - > x = string - > y ;
2021-09-27 01:55:16 +03:00
string - > y = stripf ( symbol - > vector - > width - temp ) ;
2020-08-05 23:23:11 +03:00
string - > rotation = 270 ;
}
string = string - > next ;
}
2021-09-27 01:55:16 +03:00
2020-08-05 23:23:11 +03:00
if ( ( rotate_angle = = 90 ) | | ( rotate_angle = = 270 ) ) {
temp = symbol - > vector - > height ;
symbol - > vector - > height = symbol - > vector - > width ;
symbol - > vector - > width = temp ;
}
}
2019-12-19 03:37:55 +03:00
static void vector_reduce_rectangles ( struct zint_symbol * symbol ) {
2022-07-14 18:01:30 +03:00
/* Looks for vertically aligned rectangles and merges them together */
2019-11-12 00:38:21 +03:00
struct zint_vector_rect * rect , * target , * prev ;
2018-06-10 11:16:18 +03:00
rect = symbol - > vector - > rectangles ;
while ( rect ) {
2019-11-12 00:38:21 +03:00
prev = rect ;
target = prev - > next ;
2019-12-18 21:33:18 +03:00
2018-06-10 11:16:18 +03:00
while ( target ) {
Add Structured Append support for AZTEC, CODEONE, DATAMATRIX, DOTCODE,
GRIDMATRIX, MAXICODE, MICROPDF417, PDF417, QRCODE, ULTRA
DOTCODE: use pre-calculated generator poly coeffs in Reed-Solomon for
performance improvement
PDF417/MICROPDF417: use common routine pdf417_initial()
GUI: code lines <= 118, shorthand widget_obj(),
shorten calling upcean_addon_gap(), upcean_guard_descent()
various backend: var name debug -> debug_print
2021-09-28 23:42:44 +03:00
if ( ( rect - > x = = target - > x ) & & ( rect - > width = = target - > width )
& & ( stripf ( rect - > y + rect - > height ) = = target - > y ) & & ( rect - > colour = = target - > colour ) ) {
2018-06-10 11:16:18 +03:00
rect - > height + = target - > height ;
2019-11-12 00:38:21 +03:00
prev - > next = target - > next ;
free ( target ) ;
2018-06-10 11:16:18 +03:00
} else {
2019-11-12 00:38:21 +03:00
prev = target ;
2018-06-10 11:16:18 +03:00
}
2019-11-12 00:38:21 +03:00
target = prev - > next ;
2018-06-10 11:16:18 +03:00
}
rect = rect - > next ;
}
}
2019-12-19 03:37:55 +03:00
INTERNAL int plot_vector ( struct zint_symbol * symbol , int rotate_angle , int file_type ) {
2018-06-10 11:16:18 +03:00
int error_number ;
2020-09-30 14:19:12 +03:00
int main_width ;
2021-09-20 16:56:27 +03:00
int comp_xoffset = 0 ;
2023-06-12 03:25:55 +03:00
int comp_roffset = 0 ;
2020-07-15 21:00:12 +03:00
unsigned char addon [ 6 ] ;
2023-11-19 22:39:54 +03:00
int addon_len = 0 ;
2020-11-01 21:32:55 +03:00
int addon_gap = 0 ;
2021-09-20 16:56:27 +03:00
float addon_text_yposn = 0.0f ;
2023-12-15 13:51:51 +03:00
float xoffset , yoffset , roffset , boffset , qz_right ;
2020-09-30 14:19:12 +03:00
float textoffset ;
2020-07-15 21:00:12 +03:00
int upceanflag = 0 ;
int addon_latch = 0 ;
2020-09-30 14:19:12 +03:00
int hide_text ;
2020-07-15 21:00:12 +03:00
int i , r ;
2021-10-21 01:05:30 +03:00
int block_width = 0 ;
2023-06-22 19:48:54 +03:00
int font_height ; /* Font pixel size (so whole integers) */
2021-09-20 16:56:27 +03:00
float text_gap ; /* Gap between barcode and text */
2021-09-22 02:04:15 +03:00
float guard_descent ;
2023-06-12 03:25:55 +03:00
const int upcean_guard_whitespace = ! ( symbol - > output_options & BARCODE_NO_QUIET_ZONES )
& & ( symbol - > output_options & EANUPC_GUARD_WHITESPACE ) ;
2022-08-08 00:43:49 +03:00
const int is_codablockf = symbol - > symbology = = BARCODE_CODABLOCKF | | symbol - > symbology = = BARCODE_HIBC_BLOCKF ;
2022-11-11 01:13:41 +03:00
const int no_extend = is_codablockf | | symbol - > symbology = = BARCODE_DPD ;
2021-06-19 15:11:23 +03:00
2021-11-07 03:21:02 +03:00
float large_bar_height ;
2023-11-19 22:39:54 +03:00
int xoffset_comp ;
2023-06-22 19:48:54 +03:00
const float descent = 1.32779717f ; /* Arimo value for normal text (font height 7) */
const float descent_small = 0.948426545f ; /* Arimo value for SMALL_TEXT (font height 5) */
2023-02-10 17:44:10 +03:00
/* For UPC/EAN only */
float addon_row_yposn ;
float addon_row_height ;
2023-06-22 19:48:54 +03:00
int upcae_outside_font_height = 0 ; /* UPC-A/E outside digits font size */
2023-12-15 13:51:51 +03:00
const float gws_left_fudge = 0.5f ; /* These make the guard whitespaces appear closer to the edge for SVG/qzint */
const float gws_right_fudge = 0.5f ; /* (undone by EMF/EPS) */
2023-02-10 17:44:10 +03:00
/* Note using "ascender" to mean height above digits as "ascent" usually measured from baseline */
2023-06-12 03:25:55 +03:00
const float digit_ascender_factor = 0.22f ; /* Assuming digit ascender height roughly 22% of font size */
2023-02-10 17:44:10 +03:00
float digit_ascender = 0.0f ; /* Avoid gcc -Wmaybe-uninitialized */
const float antialias_fudge_factor = 0.02f ;
float antialias_fudge = 0.0f ; /* Avoid gcc -Wmaybe-uninitialized */
int rect_count = 0 , last_row_start = 0 ; /* For UPC/EAN guard bars */
2020-09-30 14:19:12 +03:00
float dot_overspill = 0.0f ;
2021-06-23 17:00:49 +03:00
float dot_offset = 0.0f ;
2021-11-07 03:21:02 +03:00
float yposn ;
2020-07-15 21:00:12 +03:00
2018-06-10 11:16:18 +03:00
struct zint_vector * vector ;
2023-06-12 03:25:55 +03:00
struct zint_vector_rect * rect , * last_rect = NULL ;
struct zint_vector_hexagon * last_hexagon = NULL ;
2018-06-10 11:16:18 +03:00
struct zint_vector_string * last_string = NULL ;
2023-06-12 03:25:55 +03:00
struct zint_vector_circle * last_circle = NULL ;
2022-10-13 15:33:59 +03:00
struct zint_vector_rect * * first_row_rects
= ( struct zint_vector_rect * * ) z_alloca ( sizeof ( struct zint_vector_rect * ) * ( symbol - > rows + 1 ) ) ;
2022-08-08 00:43:49 +03:00
memset ( first_row_rects , 0 , sizeof ( struct zint_vector_rect * ) * ( symbol - > rows + 1 ) ) ;
2020-04-03 21:40:59 +03:00
2022-07-14 18:01:30 +03:00
/* Free any previous rendering structures */
2020-07-15 21:00:12 +03:00
vector_free ( symbol ) ;
2022-07-14 18:01:30 +03:00
/* Sanity check colours */
2021-10-21 01:05:30 +03:00
error_number = out_check_colour_options ( symbol ) ;
2020-05-21 20:22:28 +03:00
if ( error_number ! = 0 ) {
return error_number ;
2018-06-10 11:16:18 +03:00
}
2022-07-14 18:01:30 +03:00
/* Allocate memory */
2021-06-10 13:15:39 +03:00
vector = symbol - > vector = ( struct zint_vector * ) malloc ( sizeof ( struct zint_vector ) ) ;
2021-09-20 16:56:27 +03:00
if ( ! vector ) {
strcpy ( symbol - > errtxt , " 696: Insufficient memory for vector header " ) ;
return ZINT_ERROR_MEMORY ;
}
2018-06-10 11:16:18 +03:00
vector - > rectangles = NULL ;
vector - > hexagons = NULL ;
vector - > circles = NULL ;
vector - > strings = NULL ;
2021-11-07 03:21:02 +03:00
large_bar_height = out_large_bar_height ( symbol , 0 /*si (scale and round)*/ , NULL /*row_heights_si*/ ,
NULL /*symbol_height_si*/ ) ;
2019-12-18 21:33:18 +03:00
2020-07-15 21:00:12 +03:00
main_width = symbol - > width ;
2023-06-12 03:25:55 +03:00
if ( is_composite ( symbol - > symbology ) ) {
while ( ! module_is_set ( symbol , symbol - > rows - 1 , comp_xoffset ) ) {
comp_xoffset + + ;
}
}
2023-11-19 22:39:54 +03:00
if ( is_upcean ( symbol - > symbology ) ) {
upceanflag = out_process_upcean ( symbol , comp_xoffset , & main_width , addon , & addon_len , & addon_gap ) ;
2023-06-12 03:25:55 +03:00
} else if ( is_composite ( symbol - > symbology ) ) {
int x ;
for ( x = symbol - > width - 1 ; x & & ! module_is_set ( symbol , symbol - > rows - 1 , x ) ; comp_roffset + + , x - - ) ;
main_width - = comp_xoffset + comp_roffset ;
2018-06-10 11:16:18 +03:00
}
2021-09-24 15:21:24 +03:00
hide_text = ( ( ! symbol - > show_hrt ) | | ( ustrlen ( symbol - > text ) = = 0 ) ) ;
2023-12-15 13:51:51 +03:00
out_set_whitespace_offsets ( symbol , hide_text , comp_xoffset , & xoffset , & yoffset , & roffset , & boffset , & qz_right ,
2023-11-19 22:39:54 +03:00
0 /*scaler*/ , NULL , NULL , NULL , NULL , NULL ) ;
xoffset_comp = xoffset + comp_xoffset ;
if ( ( symbol - > symbology ! = BARCODE_MAXICODE ) & & ( symbol - > output_options & BARCODE_DOTTY_MODE ) ) {
if ( symbol - > dot_size < 1.0f ) {
dot_overspill = 0.0f ;
/* Offset (1 - dot_size) / 2 + dot_radius == (1 - dot_size + dot_size) / 2 == 1 / 2 */
dot_offset = 0.5f ;
} else { /* Allow for exceeding 1X */
dot_overspill = symbol - > dot_size - 1.0f + 0.1f ; /* Fudge for anti-aliasing */
dot_offset = symbol - > dot_size / 2.0f + 0.05f ; /* Fudge for anti-aliasing */
}
}
vector - > width = symbol - > width + dot_overspill + ( xoffset + roffset ) ;
2018-06-10 11:16:18 +03:00
2020-09-30 14:19:12 +03:00
/* Note font sizes scaled by 2 so really twice these values */
if ( upceanflag ) {
/* Note BOLD_TEXT ignored for UPCEAN by svg/emf/ps/qzint */
2023-06-22 19:48:54 +03:00
font_height = symbol - > output_options & SMALL_TEXT ? 7 : 10 ;
digit_ascender = font_height * digit_ascender_factor ;
antialias_fudge = font_height * antialias_fudge_factor ;
2023-06-12 03:25:55 +03:00
/* Although font size 7 (for normal) seems small it meets GS1 General Spec (GGS) Section 5.2.5:
" the size of the first and last digits should be reduced to a maximum width equivalent to four modules " */
2023-06-22 19:48:54 +03:00
upcae_outside_font_height = symbol - > output_options & SMALL_TEXT ? 6 : 7 ;
2023-06-12 03:25:55 +03:00
/* Note default now 1.0 (GGS 5.2.5 "Normally the minimum is one module") but was 0.5 (absolute minimum) */
2023-11-19 22:39:54 +03:00
text_gap = symbol - > text_gap - digit_ascender ;
2021-09-20 16:56:27 +03:00
/* Guard bar height (none for EAN-2 and EAN-5) */
2023-06-12 03:25:55 +03:00
guard_descent = upceanflag > = 6 ? symbol - > guard_descent : 0.0f ;
2020-09-30 14:19:12 +03:00
} else {
2023-06-22 19:48:54 +03:00
font_height = symbol - > output_options & SMALL_TEXT ? 5 : 7 ;
antialias_fudge = font_height * antialias_fudge_factor ;
2023-11-19 22:39:54 +03:00
text_gap = symbol - > text_gap ;
2021-09-22 02:04:15 +03:00
guard_descent = 0.0f ;
2020-09-30 14:19:12 +03:00
}
2020-07-15 21:00:12 +03:00
if ( hide_text ) {
2021-09-22 02:04:15 +03:00
textoffset = guard_descent ;
2018-06-10 11:16:18 +03:00
} else {
2023-11-19 22:39:54 +03:00
textoffset = font_height + stripf ( text_gap + antialias_fudge ) ;
2020-09-30 14:19:12 +03:00
if ( upceanflag ) {
2023-02-10 17:44:10 +03:00
if ( textoffset < guard_descent ) {
2021-09-22 02:04:15 +03:00
textoffset = guard_descent ;
}
2020-09-30 14:19:12 +03:00
}
2018-06-10 11:16:18 +03:00
}
2020-10-26 15:21:43 +03:00
vector - > height = symbol - > height + textoffset + dot_overspill + ( yoffset + boffset ) ;
2018-06-10 11:16:18 +03:00
2022-07-14 18:01:30 +03:00
/* Plot Maxicode symbols */
2020-10-26 15:21:43 +03:00
if ( symbol - > symbology = = BARCODE_MAXICODE ) {
2021-08-22 15:59:01 +03:00
float bull_x , bull_y , bull_d_incr , bull_width ;
2021-05-16 18:34:42 +03:00
const float two_div_sqrt3 = 1.1547f ; /* 2 / √3 */
const float sqrt3_div_two = 0.866f ; /* √3 / 2 == 1.5 / √3 */
/* `hex_diameter` is short diameter, X in ISO/IEC 16023:2000 Figure 8 (same as W) */
const float hex_diameter = 1.0f ;
const float hex_radius = hex_diameter / 2.0f ;
const float hex_ydiameter = two_div_sqrt3 * hex_diameter ; /* Long diameter, V in Figure 8 */
const float hex_yradius = hex_ydiameter / 2.0f ;
const float yposn_offset = sqrt3_div_two * hex_diameter ; /* Vertical distance between rows, Y in Figure 8 */
vector - > width = 30 * hex_diameter + ( xoffset + roffset ) ;
/* 32 rows drawn yposn_offset apart + final hexagon */
vector - > height = 32 * yposn_offset + hex_ydiameter + ( yoffset + boffset ) ;
2022-07-14 18:01:30 +03:00
/* Bullseye (ISO/IEC 16023:2000 4.2.1.1 and 4.11.4) */
2021-05-16 18:34:42 +03:00
bull_x = 14.5f * hex_diameter + xoffset ; /* 14W right from leftmost centre = 14.5X */
bull_y = vector - > height / 2.0f ; /* 16Y above bottom-most centre = halfway */
/* Total finder diameter is 9X, so diametric increment for 5 diameters d2 to d6 is (9X - d1) / 5 */
bull_d_incr = ( hex_diameter * 9 - hex_ydiameter ) / 5.0f ;
2021-08-22 15:59:01 +03:00
bull_width = bull_d_incr / 2.0f ;
2021-05-16 18:34:42 +03:00
2023-06-12 03:25:55 +03:00
if ( ! vector_add_circle ( symbol , bull_x , bull_y , hex_ydiameter + bull_d_incr * 5 - bull_width , bull_width , 0 ,
& last_circle ) ) return ZINT_ERROR_MEMORY ;
if ( ! vector_add_circle ( symbol , bull_x , bull_y , hex_ydiameter + bull_d_incr * 3 - bull_width , bull_width , 0 ,
& last_circle ) ) return ZINT_ERROR_MEMORY ;
if ( ! vector_add_circle ( symbol , bull_x , bull_y , hex_ydiameter + bull_d_incr - bull_width , bull_width , 0 ,
& last_circle ) ) return ZINT_ERROR_MEMORY ;
2020-10-26 15:21:43 +03:00
/* Hexagons */
for ( r = 0 ; r < symbol - > rows ; r + + ) {
2021-05-16 18:34:42 +03:00
const int odd_row = r & 1 ; /* Odd (reduced) row, even (full) row */
2021-10-21 01:05:30 +03:00
const float hex_yposn = r * yposn_offset + hex_yradius + yoffset ;
2021-05-16 18:34:42 +03:00
const float xposn_offset = ( odd_row ? hex_diameter : hex_radius ) + xoffset ;
for ( i = 0 ; i < symbol - > width - odd_row ; i + + ) {
2020-10-26 15:21:43 +03:00
if ( module_is_set ( symbol , r , i ) ) {
2021-10-21 01:05:30 +03:00
const float hex_xposn = i * hex_diameter + xposn_offset ;
2023-06-12 03:25:55 +03:00
if ( ! vector_add_hexagon ( symbol , hex_xposn , hex_yposn , hex_diameter , & last_hexagon ) )
return ZINT_ERROR_MEMORY ;
2020-10-26 15:21:43 +03:00
}
}
}
2022-07-14 18:01:30 +03:00
/* Dotty mode */
2020-10-26 15:21:43 +03:00
} else if ( symbol - > output_options & BARCODE_DOTTY_MODE ) {
for ( r = 0 ; r < symbol - > rows ; r + + ) {
for ( i = 0 ; i < symbol - > width ; i + + ) {
if ( module_is_set ( symbol , r , i ) ) {
2023-06-12 03:25:55 +03:00
if ( ! vector_add_circle ( symbol , i + dot_offset + xoffset , r + dot_offset + yoffset ,
symbol - > dot_size , 0 , 0 , & last_circle ) ) return ZINT_ERROR_MEMORY ;
2020-10-26 15:21:43 +03:00
}
}
}
2022-07-14 18:01:30 +03:00
/* Plot rectangles - most symbols created here */
2021-10-21 01:05:30 +03:00
} else if ( symbol - > symbology = = BARCODE_ULTRA ) {
yposn = yoffset ;
for ( r = 0 ; r < symbol - > rows ; r + + ) {
2021-11-07 03:21:02 +03:00
const float row_height = symbol - > row_height [ r ] ;
2021-10-21 01:05:30 +03:00
for ( i = 0 ; i < symbol - > width ; i + = block_width ) {
2021-11-07 03:21:02 +03:00
const int fill = module_colour_is_set ( symbol , r , i ) ;
2021-10-21 01:05:30 +03:00
for ( block_width = 1 ; ( i + block_width < symbol - > width )
& & module_colour_is_set ( symbol , r , i + block_width ) = = fill ; block_width + + ) ;
if ( fill ) {
/* a colour block */
2023-06-12 03:25:55 +03:00
if ( ! vector_add_rect ( symbol , i + xoffset , yposn , block_width , row_height , & last_rect ) )
return ZINT_ERROR_MEMORY ;
last_rect - > colour = module_colour_is_set ( symbol , r , i ) ;
2021-10-21 01:05:30 +03:00
}
}
yposn + = row_height ;
}
} else if ( upceanflag > = 6 ) { /* UPC-E, EAN-8, UPC-A, EAN-13 */
2021-09-20 16:56:27 +03:00
yposn = yoffset ;
2018-06-10 11:16:18 +03:00
for ( r = 0 ; r < symbol - > rows ; r + + ) {
2021-11-07 03:21:02 +03:00
const float row_height = symbol - > row_height [ r ] ? symbol - > row_height [ r ] : large_bar_height ;
2018-06-10 11:16:18 +03:00
last_row_start = rect_count ;
2021-10-21 01:05:30 +03:00
for ( i = 0 ; i < symbol - > width ; i + = block_width ) {
2021-11-07 03:21:02 +03:00
const int fill = module_is_set ( symbol , r , i ) ;
2021-10-21 01:05:30 +03:00
for ( block_width = 1 ; ( i + block_width < symbol - > width )
& & module_is_set ( symbol , r , i + block_width ) = = fill ; block_width + + ) ;
2018-06-10 11:16:18 +03:00
2021-10-21 01:05:30 +03:00
if ( ( r = = ( symbol - > rows - 1 ) ) & & ( i > main_width ) & & ( addon_latch = = 0 ) ) {
2023-06-22 19:48:54 +03:00
addon_text_yposn = yposn + font_height - digit_ascender ;
2021-10-21 01:05:30 +03:00
if ( addon_text_yposn < 0.0f ) {
addon_text_yposn = 0.0f ;
2020-09-30 14:19:12 +03:00
}
2023-06-22 19:48:54 +03:00
addon_row_yposn = yposn + font_height + text_gap + antialias_fudge ;
2023-02-10 17:44:10 +03:00
addon_row_height = row_height - ( addon_row_yposn - yposn ) ;
2021-10-21 01:05:30 +03:00
if ( upceanflag ! = 12 & & upceanflag ! = 6 ) { /* UPC-A/E add-ons don't descend */
addon_row_height + = guard_descent ;
}
if ( addon_row_height < 0.5f ) {
addon_row_height = 0.5f ;
2020-09-30 14:19:12 +03:00
}
2021-10-21 01:05:30 +03:00
addon_latch = 1 ;
}
if ( fill ) {
/* a bar */
if ( addon_latch ) {
2023-06-12 03:25:55 +03:00
if ( ! vector_add_rect ( symbol , i + xoffset , addon_row_yposn , block_width , addon_row_height ,
& last_rect ) ) return ZINT_ERROR_MEMORY ;
2021-10-21 01:05:30 +03:00
} else {
2023-06-12 03:25:55 +03:00
if ( ! vector_add_rect ( symbol , i + xoffset , yposn , block_width , row_height , & last_rect ) )
return ZINT_ERROR_MEMORY ;
2018-06-10 11:16:18 +03:00
}
2021-10-21 01:05:30 +03:00
rect_count + + ;
}
}
yposn + = row_height ;
}
} else {
yposn = yoffset ;
2023-06-12 03:25:55 +03:00
if ( upceanflag & & ! hide_text ) { /* EAN-2, EAN-5 (standalone add-ons) */
2023-06-22 19:48:54 +03:00
yposn + = font_height + text_gap + antialias_fudge ;
2023-06-12 03:25:55 +03:00
}
2021-10-21 01:05:30 +03:00
for ( r = 0 ; r < symbol - > rows ; r + + ) {
2021-11-07 03:21:02 +03:00
const float row_height = symbol - > row_height [ r ] ? symbol - > row_height [ r ] : large_bar_height ;
2018-06-10 11:16:18 +03:00
2021-10-21 01:05:30 +03:00
for ( i = 0 ; i < symbol - > width ; i + = block_width ) {
2021-11-07 03:21:02 +03:00
const int fill = module_is_set ( symbol , r , i ) ;
2021-10-21 01:05:30 +03:00
for ( block_width = 1 ; ( i + block_width < symbol - > width )
& & module_is_set ( symbol , r , i + block_width ) = = fill ; block_width + + ) ;
if ( fill ) {
/* a bar */
2023-06-12 03:25:55 +03:00
if ( ! vector_add_rect ( symbol , i + xoffset , yposn , block_width , row_height , & last_rect ) )
return ZINT_ERROR_MEMORY ;
2022-08-08 00:43:49 +03:00
if ( i = = 0 ) {
2023-06-12 03:25:55 +03:00
first_row_rects [ r ] = last_rect ;
2022-08-08 00:43:49 +03:00
}
2021-10-21 01:05:30 +03:00
}
2020-11-01 21:32:55 +03:00
}
2021-09-20 16:56:27 +03:00
yposn + = row_height ;
2018-06-10 11:16:18 +03:00
}
}
2021-10-21 01:05:30 +03:00
if ( guard_descent & & upceanflag > = 6 ) { /* UPC-E, EAN-8, UPC-A, EAN-13 */
2020-07-15 21:00:12 +03:00
/* Guard bar extension */
if ( upceanflag = = 6 ) { /* UPC-E */
i = 0 ;
for ( rect = symbol - > vector - > rectangles ; rect ! = NULL ; rect = rect - > next ) {
switch ( i - last_row_start ) {
case 0 :
case 1 :
case 14 :
case 15 :
case 16 :
2021-09-22 02:04:15 +03:00
rect - > height + = guard_descent ;
2020-07-15 21:00:12 +03:00
break ;
}
i + + ;
2018-06-10 11:16:18 +03:00
}
2020-07-15 21:00:12 +03:00
} else if ( upceanflag = = 8 ) { /* EAN-8 */
i = 0 ;
for ( rect = symbol - > vector - > rectangles ; rect ! = NULL ; rect = rect - > next ) {
switch ( i - last_row_start ) {
case 0 :
case 1 :
case 10 :
case 11 :
case 20 :
case 21 :
2021-09-22 02:04:15 +03:00
rect - > height + = guard_descent ;
2020-07-15 21:00:12 +03:00
break ;
}
i + + ;
2018-06-10 11:16:18 +03:00
}
2020-07-15 21:00:12 +03:00
} else if ( upceanflag = = 12 ) { /* UPC-A */
i = 0 ;
for ( rect = symbol - > vector - > rectangles ; rect ! = NULL ; rect = rect - > next ) {
switch ( i - last_row_start ) {
case 0 :
case 1 :
case 2 :
case 3 :
case 14 :
case 15 :
case 26 :
case 27 :
case 28 :
case 29 :
2021-09-22 02:04:15 +03:00
rect - > height + = guard_descent ;
2020-07-15 21:00:12 +03:00
break ;
}
i + + ;
2018-06-10 11:16:18 +03:00
}
2021-10-21 01:05:30 +03:00
} else { /* EAN-13 */
2020-07-15 21:00:12 +03:00
i = 0 ;
for ( rect = symbol - > vector - > rectangles ; rect ! = NULL ; rect = rect - > next ) {
switch ( i - last_row_start ) {
case 0 :
case 1 :
case 14 :
case 15 :
case 28 :
case 29 :
2021-09-22 02:04:15 +03:00
rect - > height + = guard_descent ;
2020-07-15 21:00:12 +03:00
break ;
}
i + + ;
2018-06-10 11:16:18 +03:00
}
}
}
2019-12-18 21:33:18 +03:00
2018-06-10 11:16:18 +03:00
/* Add the text */
2019-11-12 00:38:21 +03:00
2018-06-10 11:16:18 +03:00
if ( ! hide_text ) {
2023-06-12 03:25:55 +03:00
float textwidth ;
2021-09-20 16:56:27 +03:00
2021-10-21 01:05:30 +03:00
if ( upceanflag > = 6 ) { /* UPC-E, EAN-8, UPC-A, EAN-13 */
2023-06-12 03:25:55 +03:00
2023-11-19 22:39:54 +03:00
float text_yposn = yoffset + symbol - > height + font_height + text_gap - antialias_fudge ; /* Baseline */
2023-12-15 13:51:51 +03:00
if ( symbol - > border_width > 0 & & ( symbol - > output_options & ( BARCODE_BOX | BARCODE_BIND ) )
& & ! ( symbol - > output_options & BARCODE_BIND_TOP ) ) { /* Trumps BARCODE_BOX & BARCODE_BIND */
text_yposn + = symbol - > border_width ;
2023-11-19 22:39:54 +03:00
}
2020-07-15 21:00:12 +03:00
if ( upceanflag = = 6 ) { /* UPC-E */
2023-11-19 22:39:54 +03:00
float text_xposn = - ( 5.0f - 0.35f ) + xoffset_comp ;
2020-08-09 22:20:16 +03:00
textwidth = 6.2f ;
2023-11-19 22:39:54 +03:00
if ( ! vector_add_string ( symbol , symbol - > text , 1 , text_xposn , text_yposn , upcae_outside_font_height ,
2023-06-12 03:25:55 +03:00
textwidth , 2 /*right align*/ , & last_string ) ) return ZINT_ERROR_MEMORY ;
2023-11-19 22:39:54 +03:00
text_xposn = ( 24.0f + 0.5f ) + xoffset_comp ;
2020-08-09 22:20:16 +03:00
textwidth = 6.0f * 8.5f ;
2023-11-19 22:39:54 +03:00
if ( ! vector_add_string ( symbol , symbol - > text + 1 , 6 , text_xposn , text_yposn , font_height , textwidth ,
2023-06-12 03:25:55 +03:00
0 /*centre align*/ , & last_string ) ) return ZINT_ERROR_MEMORY ;
2023-11-19 22:39:54 +03:00
text_xposn = ( 51.0f - 0.35f ) + 3.0f + xoffset_comp ;
2020-08-09 22:20:16 +03:00
textwidth = 6.2f ;
2023-11-19 22:39:54 +03:00
if ( ! vector_add_string ( symbol , symbol - > text + 7 , 1 , text_xposn , text_yposn , upcae_outside_font_height ,
2023-06-12 03:25:55 +03:00
textwidth , 1 /*left align*/ , & last_string ) ) return ZINT_ERROR_MEMORY ;
2023-02-10 17:44:10 +03:00
if ( addon_len ) {
2023-11-19 22:39:54 +03:00
text_xposn = ( addon_len = = 2 ? 61.0f : 75.0f ) + xoffset_comp + addon_gap ;
2023-02-10 17:44:10 +03:00
textwidth = addon_len * 8.5f ;
2023-06-22 19:48:54 +03:00
if ( ! vector_add_string ( symbol , addon , addon_len , text_xposn , addon_text_yposn , font_height ,
2023-06-12 03:25:55 +03:00
textwidth , 0 /*centre align*/ , & last_string ) ) return ZINT_ERROR_MEMORY ;
if ( upcean_guard_whitespace ) {
2023-12-15 13:51:51 +03:00
text_xposn = symbol - > width + gws_right_fudge + qz_right + xoffset ;
2023-06-12 03:25:55 +03:00
textwidth = 8.5f ;
if ( ! vector_add_string ( symbol , ( const unsigned char * ) " > " , 1 , text_xposn , addon_text_yposn ,
2023-12-15 13:51:51 +03:00
font_height , textwidth , 2 /*right align*/ , & last_string ) ) return ZINT_ERROR_MEMORY ;
2023-06-12 03:25:55 +03:00
}
2020-07-15 21:00:12 +03:00
}
2018-06-10 11:16:18 +03:00
2020-07-15 21:00:12 +03:00
} else if ( upceanflag = = 8 ) { /* EAN-8 */
2023-11-19 22:39:54 +03:00
float text_xposn ;
2023-06-12 03:25:55 +03:00
if ( upcean_guard_whitespace ) {
2023-12-15 13:51:51 +03:00
text_xposn = - 7.0f - gws_left_fudge + xoffset_comp ;
2023-06-12 03:25:55 +03:00
textwidth = 8.5f ;
if ( ! vector_add_string ( symbol , ( const unsigned char * ) " < " , 1 , text_xposn , text_yposn ,
2023-12-15 13:51:51 +03:00
font_height , textwidth , 1 /*left align*/ , & last_string ) ) return ZINT_ERROR_MEMORY ;
2023-06-12 03:25:55 +03:00
}
2023-11-19 22:39:54 +03:00
text_xposn = ( 17.0f + 0.5f ) + xoffset_comp ;
2020-08-09 22:20:16 +03:00
textwidth = 4.0f * 8.5f ;
2023-11-19 22:39:54 +03:00
if ( ! vector_add_string ( symbol , symbol - > text , 4 , text_xposn , text_yposn , font_height , textwidth ,
2023-06-12 03:25:55 +03:00
0 /*centre align*/ , & last_string ) ) return ZINT_ERROR_MEMORY ;
2023-11-19 22:39:54 +03:00
text_xposn = ( 50.0f - 0.5f ) + xoffset_comp ;
if ( ! vector_add_string ( symbol , symbol - > text + 4 , 4 , text_xposn , text_yposn , font_height , textwidth ,
2023-06-12 03:25:55 +03:00
0 /*centre align*/ , & last_string ) ) return ZINT_ERROR_MEMORY ;
2023-02-10 17:44:10 +03:00
if ( addon_len ) {
2023-11-19 22:39:54 +03:00
text_xposn = ( addon_len = = 2 ? 77.0f : 91.0f ) + xoffset_comp + addon_gap ;
2023-02-10 17:44:10 +03:00
textwidth = addon_len * 8.5f ;
2023-06-22 19:48:54 +03:00
if ( ! vector_add_string ( symbol , addon , addon_len , text_xposn , addon_text_yposn , font_height ,
2023-06-12 03:25:55 +03:00
textwidth , 0 /*centre align*/ , & last_string ) ) return ZINT_ERROR_MEMORY ;
if ( upcean_guard_whitespace ) {
2023-12-15 13:51:51 +03:00
text_xposn = symbol - > width + gws_right_fudge + qz_right + xoffset ;
2023-06-12 03:25:55 +03:00
textwidth = 8.5f ;
if ( ! vector_add_string ( symbol , ( const unsigned char * ) " > " , 1 , text_xposn , addon_text_yposn ,
2023-12-15 13:51:51 +03:00
font_height , textwidth , 2 /*right align*/ , & last_string ) ) return ZINT_ERROR_MEMORY ;
2023-06-12 03:25:55 +03:00
}
} else if ( upcean_guard_whitespace ) {
2023-12-15 13:51:51 +03:00
text_xposn = symbol - > width + gws_right_fudge + qz_right + xoffset ;
2023-06-12 03:25:55 +03:00
textwidth = 8.5f ;
if ( ! vector_add_string ( symbol , ( const unsigned char * ) " > " , 1 , text_xposn , text_yposn ,
2023-12-15 13:51:51 +03:00
font_height , textwidth , 2 /*right align*/ , & last_string ) ) return ZINT_ERROR_MEMORY ;
2020-07-15 21:00:12 +03:00
}
2018-06-10 11:16:18 +03:00
2020-07-15 21:00:12 +03:00
} else if ( upceanflag = = 12 ) { /* UPC-A */
2023-11-19 22:39:54 +03:00
float text_xposn = - ( 5.0f - 0.35f ) + xoffset_comp ;
2020-08-09 22:20:16 +03:00
textwidth = 6.2f ;
2023-11-19 22:39:54 +03:00
if ( ! vector_add_string ( symbol , symbol - > text , 1 , text_xposn , text_yposn , upcae_outside_font_height ,
2023-06-12 03:25:55 +03:00
textwidth , 2 /*right align*/ , & last_string ) ) return ZINT_ERROR_MEMORY ;
2023-11-19 22:39:54 +03:00
text_xposn = 28.0f + xoffset_comp ;
2020-08-09 22:20:16 +03:00
textwidth = 5.0f * 8.5f ;
2023-11-19 22:39:54 +03:00
if ( ! vector_add_string ( symbol , symbol - > text + 1 , 5 , text_xposn , text_yposn , font_height , textwidth ,
0 /*centre align*/ , & last_string ) ) return ZINT_ERROR_MEMORY ;
text_xposn = 67.0f + xoffset_comp ;
if ( ! vector_add_string ( symbol , symbol - > text + 6 , 5 , text_xposn , text_yposn , font_height , textwidth ,
2023-06-12 03:25:55 +03:00
0 /*centre align*/ , & last_string ) ) return ZINT_ERROR_MEMORY ;
2023-11-19 22:39:54 +03:00
text_xposn = ( 95.0f - 0.35f ) + 5.0f + xoffset_comp ;
2020-08-09 22:20:16 +03:00
textwidth = 6.2f ;
2023-11-19 22:39:54 +03:00
if ( ! vector_add_string ( symbol , symbol - > text + 11 , 1 , text_xposn , text_yposn ,
upcae_outside_font_height , textwidth , 1 /*left align*/ , & last_string ) ) {
return ZINT_ERROR_MEMORY ;
}
2023-02-10 17:44:10 +03:00
if ( addon_len ) {
2023-11-19 22:39:54 +03:00
text_xposn = ( addon_len = = 2 ? 105.0f : 119.0f ) + xoffset_comp + addon_gap ;
2023-02-10 17:44:10 +03:00
textwidth = addon_len * 8.5f ;
2023-06-22 19:48:54 +03:00
if ( ! vector_add_string ( symbol , addon , addon_len , text_xposn , addon_text_yposn , font_height ,
2023-06-12 03:25:55 +03:00
textwidth , 0 /*centre align*/ , & last_string ) ) return ZINT_ERROR_MEMORY ;
if ( upcean_guard_whitespace ) {
2023-12-15 13:51:51 +03:00
text_xposn = symbol - > width + gws_right_fudge + qz_right + xoffset ;
2023-06-12 03:25:55 +03:00
textwidth = 8.5f ;
if ( ! vector_add_string ( symbol , ( const unsigned char * ) " > " , 1 , text_xposn , addon_text_yposn ,
2023-12-15 13:51:51 +03:00
font_height , textwidth , 2 /*right align*/ , & last_string ) ) return ZINT_ERROR_MEMORY ;
2023-06-12 03:25:55 +03:00
}
2020-07-15 21:00:12 +03:00
}
2018-06-10 11:16:18 +03:00
2021-10-21 01:05:30 +03:00
} else { /* EAN-13 */
2023-11-19 22:39:54 +03:00
float text_xposn = - ( 5.0f - 0.1f ) + xoffset_comp ;
2020-08-09 22:20:16 +03:00
textwidth = 8.5f ;
2023-11-19 22:39:54 +03:00
if ( ! vector_add_string ( symbol , symbol - > text , 1 , text_xposn , text_yposn , font_height , textwidth ,
2023-06-12 03:25:55 +03:00
2 /*right align*/ , & last_string ) ) return ZINT_ERROR_MEMORY ;
2023-11-19 22:39:54 +03:00
text_xposn = ( 24.0f + 0.5f ) + xoffset_comp ;
2020-08-09 22:20:16 +03:00
textwidth = 6.0f * 8.5f ;
2023-11-19 22:39:54 +03:00
if ( ! vector_add_string ( symbol , symbol - > text + 1 , 6 , text_xposn , text_yposn , font_height , textwidth ,
2023-06-12 03:25:55 +03:00
0 /*centre align*/ , & last_string ) ) return ZINT_ERROR_MEMORY ;
2023-11-19 22:39:54 +03:00
text_xposn = ( 71.0f - 0.5f ) + xoffset_comp ;
if ( ! vector_add_string ( symbol , symbol - > text + 7 , 6 , text_xposn , text_yposn , font_height , textwidth ,
2023-06-12 03:25:55 +03:00
0 /*centre align*/ , & last_string ) ) return ZINT_ERROR_MEMORY ;
2023-02-10 17:44:10 +03:00
if ( addon_len ) {
2023-11-19 22:39:54 +03:00
text_xposn = ( addon_len = = 2 ? 105.0f : 119.0f ) + xoffset_comp + addon_gap ;
2023-02-10 17:44:10 +03:00
textwidth = addon_len * 8.5f ;
2023-06-22 19:48:54 +03:00
if ( ! vector_add_string ( symbol , addon , addon_len , text_xposn , addon_text_yposn , font_height ,
2023-06-12 03:25:55 +03:00
textwidth , 0 /*centre align*/ , & last_string ) ) return ZINT_ERROR_MEMORY ;
if ( upcean_guard_whitespace ) {
2023-12-15 13:51:51 +03:00
text_xposn = symbol - > width + gws_right_fudge + qz_right + xoffset ;
2023-06-12 03:25:55 +03:00
textwidth = 8.5f ;
if ( ! vector_add_string ( symbol , ( const unsigned char * ) " > " , 1 , text_xposn , addon_text_yposn ,
2023-12-15 13:51:51 +03:00
font_height , textwidth , 2 /*right align*/ , & last_string ) ) return ZINT_ERROR_MEMORY ;
2023-06-12 03:25:55 +03:00
}
} else if ( upcean_guard_whitespace ) {
2023-12-15 13:51:51 +03:00
text_xposn = symbol - > width + gws_right_fudge + qz_right + xoffset ;
2023-06-12 03:25:55 +03:00
textwidth = 8.5f ;
if ( ! vector_add_string ( symbol , ( const unsigned char * ) " > " , 1 , text_xposn , text_yposn ,
2023-12-15 13:51:51 +03:00
font_height , textwidth , 2 /*right align*/ , & last_string ) ) return ZINT_ERROR_MEMORY ;
2020-07-15 21:00:12 +03:00
}
2018-06-10 11:16:18 +03:00
}
2023-06-12 03:25:55 +03:00
} else if ( upceanflag ) { /* EAN-2, EAN-5 (standalone add-ons) */
/* Put at top (and centered) */
2023-11-19 22:39:54 +03:00
float text_xposn = main_width / 2.0f + xoffset ;
float text_yposn = yoffset + font_height - digit_ascender ;
if ( symbol - > border_width > 0
& & ( symbol - > output_options & ( BARCODE_BOX | BARCODE_BIND | BARCODE_BIND_TOP ) ) ) {
text_yposn - = symbol - > border_width ;
}
if ( text_yposn < 0.0f ) {
text_yposn = 0.0f ;
}
addon_len = ( int ) ustrlen ( symbol - > text ) ;
2023-06-12 03:25:55 +03:00
textwidth = addon_len * 8.5f ;
2023-06-22 19:48:54 +03:00
if ( ! vector_add_string ( symbol , symbol - > text , addon_len , text_xposn , text_yposn , font_height ,
2023-06-12 03:25:55 +03:00
textwidth , 0 /*centre align*/ , & last_string ) ) return ZINT_ERROR_MEMORY ;
if ( upcean_guard_whitespace ) {
2023-12-15 13:51:51 +03:00
text_xposn = symbol - > width + gws_right_fudge + qz_right + xoffset ;
2023-06-12 03:25:55 +03:00
textwidth = 8.5f ;
if ( ! vector_add_string ( symbol , ( const unsigned char * ) " > " , 1 , text_xposn , text_yposn ,
2023-12-15 13:51:51 +03:00
font_height , textwidth , 2 /*right align*/ , & last_string ) ) return ZINT_ERROR_MEMORY ;
2023-06-12 03:25:55 +03:00
}
2021-10-21 01:05:30 +03:00
} else {
2020-07-15 21:00:12 +03:00
/* Put normal human readable text at the bottom (and centered) */
2023-11-19 22:39:54 +03:00
float text_xposn = main_width / 2.0f + xoffset_comp ;
float text_yposn = yoffset + symbol - > height + font_height + text_gap ; /* Calculated to bottom of text */
text_yposn - = symbol - > output_options & SMALL_TEXT ? descent_small : descent ;
2023-12-15 13:51:51 +03:00
if ( symbol - > border_width > 0 & & ( symbol - > output_options & ( BARCODE_BOX | BARCODE_BIND ) )
& & ! ( symbol - > output_options & BARCODE_BIND_TOP ) ) { /* Trumps BARCODE_BOX & BARCODE_BIND */
text_yposn + = symbol - > border_width ;
2023-11-19 22:39:54 +03:00
}
2023-06-22 19:48:54 +03:00
if ( ! vector_add_string ( symbol , symbol - > text , - 1 , text_xposn , text_yposn , font_height , symbol - > width , 0 ,
2023-06-12 03:25:55 +03:00
& last_string ) ) return ZINT_ERROR_MEMORY ;
2018-06-10 11:16:18 +03:00
}
}
2022-07-14 18:01:30 +03:00
/* Separator binding for stacked barcodes */
2021-09-20 16:56:27 +03:00
if ( ( symbol - > output_options & BARCODE_BIND ) & & ( symbol - > rows > 1 ) & & is_stackable ( symbol - > symbology ) ) {
float sep_xoffset = xoffset ;
float sep_width = symbol - > width ;
2022-08-08 00:43:49 +03:00
float sep_height = 1.0f , sep_yoffset , sep_half_height ;
2021-09-20 16:56:27 +03:00
if ( symbol - > option_3 > 0 & & symbol - > option_3 < = 4 ) {
sep_height = symbol - > option_3 ;
}
2022-08-08 00:43:49 +03:00
sep_half_height = sep_height / 2.0f ;
sep_yoffset = yoffset - sep_half_height ;
if ( is_codablockf ) {
2021-09-20 16:56:27 +03:00
/* Avoid 11-module start and 13-module stop chars */
sep_xoffset + = 11 ;
sep_width - = 11 + 13 ;
}
2022-08-08 00:43:49 +03:00
/* Adjust original rectangles so don't overlap with separator(s) (important for RGBA) */
for ( r = 0 ; r < symbol - > rows ; r + + ) {
for ( rect = first_row_rects [ r ] , i = 0 ; rect & & rect ! = first_row_rects [ r + 1 ] ; rect = rect - > next , i + + ) {
if ( is_codablockf ) { /* Skip start and stop chars */
if ( i < 3 ) {
continue ;
}
if ( ( i / 3 ) * 11 + 13 > = symbol - > width ) { /* 3 bars and 11 modules per char */
break ;
}
}
if ( r ! = 0 ) {
rect - > y + = sep_height - sep_half_height ;
rect - > height - = r + 1 = = symbol - > rows ? sep_half_height : sep_height ;
} else {
rect - > height - = sep_half_height ;
}
if ( rect - > height < 0 ) {
rect - > height = 0.0f ;
/* TODO: warn? */
}
}
}
2021-09-20 16:56:27 +03:00
for ( r = 1 ; r < symbol - > rows ; r + + ) {
2021-11-07 03:21:02 +03:00
const float row_height = symbol - > row_height [ r - 1 ] ? symbol - > row_height [ r - 1 ] : large_bar_height ;
2023-06-12 03:25:55 +03:00
if ( ! vector_add_rect ( symbol , sep_xoffset , ( r * row_height ) + sep_yoffset , sep_width , sep_height ,
& last_rect ) ) return ZINT_ERROR_MEMORY ;
2018-06-10 11:16:18 +03:00
}
}
2021-09-20 16:56:27 +03:00
2022-07-14 18:01:30 +03:00
/* Bind/box */
2022-11-11 01:13:41 +03:00
if ( symbol - > border_width > 0 & & ( symbol - > output_options & ( BARCODE_BOX | BARCODE_BIND | BARCODE_BIND_TOP ) ) ) {
2022-01-01 18:24:59 +03:00
const int horz_outside = is_fixed_ratio ( symbol - > symbology ) ;
float ybind_top = yoffset - symbol - > border_width ;
2022-07-14 18:01:30 +03:00
/* Following equivalent to yoffset + symbol->height + dot_overspill except for BARCODE_MAXICODE */
2022-01-01 18:24:59 +03:00
float ybind_bot = vector - > height - textoffset - boffset ;
if ( horz_outside ) {
ybind_top = 0 ;
ybind_bot = vector - > height - symbol - > border_width ;
2023-11-19 22:39:54 +03:00
} else if ( upceanflag = = 2 | | upceanflag = = 5 ) {
ybind_top + = textoffset ;
ybind_bot + = textoffset ;
2022-01-01 18:24:59 +03:00
}
2022-07-14 18:01:30 +03:00
/* Top */
2023-06-12 03:25:55 +03:00
if ( ! vector_add_rect ( symbol , 0.0f , ybind_top , vector - > width , symbol - > border_width , & last_rect ) )
return ZINT_ERROR_MEMORY ;
2022-11-11 01:13:41 +03:00
if ( ! ( symbol - > output_options & BARCODE_BOX ) & & no_extend ) {
/* CodaBlockF/DPD bind - does not extend over horizontal whitespace */
2023-06-12 03:25:55 +03:00
last_rect - > x = xoffset ;
last_rect - > width - = xoffset + roffset ;
2018-06-10 11:16:18 +03:00
}
2022-07-14 18:01:30 +03:00
/* Bottom */
2022-11-11 01:13:41 +03:00
if ( ! ( symbol - > output_options & BARCODE_BIND_TOP ) ) { /* Trumps BARCODE_BOX & BARCODE_BIND */
2023-06-12 03:25:55 +03:00
if ( ! vector_add_rect ( symbol , 0.0f , ybind_bot , vector - > width , symbol - > border_width , & last_rect ) )
return ZINT_ERROR_MEMORY ;
2022-11-11 01:13:41 +03:00
if ( ! ( symbol - > output_options & BARCODE_BOX ) & & no_extend ) {
/* CodaBlockF/DPD bind - does not extend over horizontal whitespace */
2023-06-12 03:25:55 +03:00
last_rect - > x = xoffset ;
last_rect - > width - = xoffset + roffset ;
2022-11-11 01:13:41 +03:00
}
2022-01-01 18:24:59 +03:00
}
2020-08-01 00:56:41 +03:00
if ( symbol - > output_options & BARCODE_BOX ) {
2021-11-07 03:21:02 +03:00
const float xbox_right = vector - > width - symbol - > border_width ;
2022-01-01 18:24:59 +03:00
float box_top = yoffset ;
2022-07-14 18:01:30 +03:00
/* Following equivalent to symbol->height except for BARCODE_MAXICODE */
2022-01-01 18:24:59 +03:00
float box_height = vector - > height - textoffset - dot_overspill - yoffset - boffset ;
if ( horz_outside ) {
box_top = symbol - > border_width ;
box_height = vector - > height - symbol - > border_width * 2 ;
2023-11-19 22:39:54 +03:00
} else if ( upceanflag = = 2 | | upceanflag = = 5 ) {
box_top + = textoffset ;
2022-01-01 18:24:59 +03:00
}
2022-07-14 18:01:30 +03:00
/* Left */
2023-06-12 03:25:55 +03:00
if ( ! vector_add_rect ( symbol , 0.0f , box_top , symbol - > border_width , box_height , & last_rect ) )
return ZINT_ERROR_MEMORY ;
2022-07-14 18:01:30 +03:00
/* Right */
2023-06-12 03:25:55 +03:00
if ( ! vector_add_rect ( symbol , xbox_right , box_top , symbol - > border_width , box_height , & last_rect ) )
return ZINT_ERROR_MEMORY ;
2018-06-10 11:16:18 +03:00
}
}
vector_reduce_rectangles ( symbol ) ;
2020-04-01 22:01:02 +03:00
vector_scale ( symbol , file_type ) ;
2021-09-27 01:55:16 +03:00
2020-08-05 23:23:11 +03:00
if ( file_type ! = OUT_EMF_FILE ) {
2020-09-30 14:19:12 +03:00
/* EMF does its own rotation (with mixed results in various apps) */
2020-08-05 23:23:11 +03:00
vector_rotate ( symbol , rotate_angle ) ;
}
2018-06-10 11:16:18 +03:00
switch ( file_type ) {
case OUT_EPS_FILE :
error_number = ps_plot ( symbol ) ;
break ;
case OUT_SVG_FILE :
error_number = svg_plot ( symbol ) ;
break ;
case OUT_EMF_FILE :
2020-09-30 14:19:12 +03:00
error_number = emf_plot ( symbol , rotate_angle ) ;
2018-06-10 11:16:18 +03:00
break ;
2018-06-18 04:36:40 +03:00
/* case OUT_BUFFER: No more work needed */
2018-06-10 11:16:18 +03:00
}
return error_number ;
}
2022-07-14 18:01:30 +03:00
/* vim: set ts=4 sw=4 et : */