2020-05-21 20:22:28 +03:00
/* output.c - Common routines for raster/vector
libzint - the open source barcode library
Copyright ( C ) 2020 Robin Stuart < rstuart114 @ gmail . com >
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 .
*/
/* vim: set ts=4 sw=4 et : */
# include "common.h"
# include "output.h"
# define SSET "0123456789ABCDEF"
/* Check colour options are good. Note: using raster.c error nos 651-654 */
2020-07-15 21:00:12 +03:00
INTERNAL int output_check_colour_options ( struct zint_symbol * symbol ) {
2020-05-21 20:22:28 +03:00
int error_number ;
2020-08-03 00:26:39 +03:00
if ( ( strlen ( symbol - > fgcolour ) ! = 6 ) & & ( strlen ( symbol - > fgcolour ) ! = 8 ) ) {
2020-05-21 20:22:28 +03:00
strcpy ( symbol - > errtxt , " 651: Malformed foreground colour target " ) ;
return ZINT_ERROR_INVALID_OPTION ;
}
2020-08-03 00:26:39 +03:00
if ( ( strlen ( symbol - > bgcolour ) ! = 6 ) & & ( strlen ( symbol - > bgcolour ) ! = 8 ) ) {
2020-05-21 20:22:28 +03:00
strcpy ( symbol - > errtxt , " 652: Malformed background colour target " ) ;
return ZINT_ERROR_INVALID_OPTION ;
}
to_upper ( ( unsigned char * ) symbol - > fgcolour ) ;
to_upper ( ( unsigned char * ) symbol - > bgcolour ) ;
error_number = is_sane ( SSET , ( unsigned char * ) symbol - > fgcolour , strlen ( symbol - > fgcolour ) ) ;
if ( error_number = = ZINT_ERROR_INVALID_DATA ) {
strcpy ( symbol - > errtxt , " 653: Malformed foreground colour target " ) ;
return ZINT_ERROR_INVALID_OPTION ;
}
2020-08-03 00:26:39 +03:00
error_number = is_sane ( SSET , ( unsigned char * ) symbol - > bgcolour , strlen ( symbol - > bgcolour ) ) ;
2020-05-21 20:22:28 +03:00
if ( error_number = = ZINT_ERROR_INVALID_DATA ) {
strcpy ( symbol - > errtxt , " 654: Malformed background colour target " ) ;
return ZINT_ERROR_INVALID_OPTION ;
}
return 0 ;
}
/* Return minimum quiet zones for each symbology */
2020-07-15 21:00:12 +03:00
static int quiet_zones ( struct zint_symbol * symbol , int * left , int * right , int * top , int * bottom ) {
int done = 0 ;
2020-05-21 20:22:28 +03:00
* left = * right = * top = * bottom = 0 ;
2020-07-15 21:00:12 +03:00
/* These always have quiet zones set (previously used whitespace_width) */
2020-05-21 20:22:28 +03:00
switch ( symbol - > symbology ) {
case BARCODE_CODE16K :
2020-07-15 21:00:12 +03:00
/* BS EN 12323:2005 Section 4.5 (c) */
2020-05-21 20:22:28 +03:00
* left = 10 ;
* right = 1 ;
2020-07-15 21:00:12 +03:00
done = 1 ;
2020-05-21 20:22:28 +03:00
break ;
case BARCODE_CODE49 :
/* ANSI/AIM BC6-2000 Section 2.4 */
* left = 10 ;
* right = 1 ;
2020-07-15 21:00:12 +03:00
done = 1 ;
2020-05-21 20:22:28 +03:00
break ;
case BARCODE_CODABLOCKF :
case BARCODE_HIBC_BLOCKF :
/* AIM ISS-X-24 Section 4.6.1 */
* left = 10 ;
* right = 10 ;
2020-07-15 21:00:12 +03:00
done = 1 ;
break ;
case BARCODE_ITF14 :
/* GS1 General Specifications 20.0 Section 5.3.2.2 */
* left = 10 ;
* right = 10 ;
done = 1 ;
break ;
case BARCODE_EANX :
case BARCODE_EANX_CHK :
case BARCODE_EANX_CC :
case BARCODE_ISBNX :
/* GS1 General Specifications 20.0 Section 5.2.3.4 */
switch ( ustrlen ( symbol - > text ) ) {
case 13 : /* EAN-13 */
* left = 11 ;
* right = 7 ;
break ;
case 16 : /* EAN-13/ISBN + 2 digit addon */
case 19 : /* EAN-13/ISBN + 5 digit addon */
* left = 11 ;
* right = 5 ;
break ;
case 5 : /* EAN-5 addon */
case 2 : /* EAN-2 addon */
* left = 7 ;
* right = 5 ;
break ;
default : /* EAN-8 (+/- 2/5 digit addon) */
* left = 7 ;
* right = 7 ;
break ;
}
done = 1 ;
break ;
case BARCODE_UPCA :
case BARCODE_UPCA_CHK :
case BARCODE_UPCA_CC :
/* GS1 General Specifications 20.0 Section 5.2.3.4 */
* left = 9 ;
if ( ustrlen ( symbol - > text ) > 12 ) { /* UPC-A + addon */
* right = 5 ;
} else {
* right = 9 ;
}
done = 1 ;
break ;
case BARCODE_UPCE :
case BARCODE_UPCE_CHK :
case BARCODE_UPCE_CC :
/* GS1 General Specifications 20.0 Section 5.2.3.4 */
* left = 9 ;
if ( ustrlen ( symbol - > text ) > 8 ) { /* UPC-E + addon */
* right = 5 ;
} else {
* right = 7 ;
}
done = 1 ;
break ;
}
if ( done ) {
return done ;
}
/* Only do others if flag set TODO: finish */
#if 0
if ( ! ( symbol - > output_options & BARCODE_QUIET_ZONES ) ) {
return done ;
}
# else
return done ;
# endif
switch ( symbol - > symbology ) {
case BARCODE_CODE11 :
/* TODO */
break ;
2020-07-29 22:43:08 +03:00
case BARCODE_C25STANDARD :
2020-07-15 21:00:12 +03:00
case BARCODE_C25INTER :
case BARCODE_C25IATA :
case BARCODE_C25LOGIC :
case BARCODE_C25IND :
* left = * right = 10 ; // Probably this TODO: check
done = 1 ;
break ;
case BARCODE_CODE39 :
case BARCODE_EXCODE39 :
case BARCODE_LOGMARS :
case BARCODE_PZN :
case BARCODE_VIN :
case BARCODE_HIBC_39 :
case BARCODE_CODE32 :
/* ISO/IEC 16388:2007 Section 4.4 (d) */
* left = * right = 10 ;
done = 1 ;
break ;
2020-07-29 22:43:08 +03:00
case BARCODE_GS1_128 : /* GS1-128 */
case BARCODE_GS1_128_CC :
2020-07-15 21:00:12 +03:00
case BARCODE_EAN14 :
/* GS1 General Specifications 20.0 Section 5.4.4.2 */
* left = * right = 10 ;
done = 1 ;
break ;
case BARCODE_CODABAR :
/* BS EN 798:1995 Section 4.4.1 (d) */
* left = * right = 10 ;
done = 1 ;
break ;
case BARCODE_CODE128 :
case BARCODE_CODE128B :
case BARCODE_HIBC_128 :
case BARCODE_NVE18 :
/* ISO/IEC 15417:2007 4.4.2 */
* left = * right = 10 ;
done = 1 ;
break ;
case BARCODE_DPLEIT :
case BARCODE_DPIDENT :
/* TODO */
break ;
case BARCODE_CODE93 :
/* TODO */
break ;
case BARCODE_FLAT :
/* TODO */
break ;
2020-07-29 22:43:08 +03:00
case BARCODE_DBAR_OMN : /* GS1 Databar Omnidirectional */
case BARCODE_DBAR_LTD : /* GS1 Databar Limited */
case BARCODE_DBAR_EXP : /* GS1 Databar Expanded */
case BARCODE_DBAR_STK : /* GS1 DataBar Stacked */
case BARCODE_DBAR_OMNSTK : /* GS1 DataBar Stacked Omnidirectional */
case BARCODE_DBAR_EXPSTK : /* GS1 Databar Expanded Stacked */
2020-07-15 21:00:12 +03:00
/* GS1 General Specifications 20.0 Section 5.5.1.1 - Quiet Zones: None required */
* left = * right = 0 ;
done = 1 ;
break ;
2020-07-29 22:43:08 +03:00
case BARCODE_DBAR_OMN_CC :
case BARCODE_DBAR_LTD_CC :
case BARCODE_DBAR_EXP_CC :
case BARCODE_DBAR_STK_CC :
case BARCODE_DBAR_OMNSTK_CC :
case BARCODE_DBAR_EXPSTK_CC :
2020-07-15 21:00:12 +03:00
/* GS1 General Specifications 20.0 Sections 5.9.2.1 (CC-A) & 5.9.2.2 (CC-B) */
* left = * right = 1 ;
done = 1 ;
break ;
case BARCODE_TELEPEN :
case BARCODE_TELEPEN_NUM :
/* TODO */
break ;
case BARCODE_POSTNET :
case BARCODE_PLANET :
/* Archived DMM C840 (Dec 09, 2004) left/right 0.125" ~ 6X, top/bottom 0.04" ~ 2X */
* left = * right = 6 ; // TODO: Proper inch to X calc
* top = * bottom = 2 ; // TODO: Proper inch to X calc
done = 1 ;
break ;
case BARCODE_MSI_PLESSEY :
/* TODO */
break ;
case BARCODE_FIM :
/* TODO */
break ;
case BARCODE_PHARMA :
case BARCODE_PHARMA_TWO :
/* TODO */
break ;
case BARCODE_PDF417 :
2020-07-30 00:35:31 +03:00
case BARCODE_PDF417COMP :
2020-07-15 21:00:12 +03:00
case BARCODE_HIBC_PDF :
/* ISO/IEC 15438:2015 Section 5.8.3 */
* left = * right = * top = * bottom = 2 ;
done = 1 ;
break ;
case BARCODE_MICROPDF417 :
case BARCODE_HIBC_MICPDF :
/* ISO/IEC 24728:2006 Section 5.8.3 */
* left = * right = * top = * bottom = 1 ;
done = 1 ;
break ;
case BARCODE_MAXICODE :
/* ISO/IEC 16023:2000 Section 4.11.5 */
* left = * right = * top = * bottom = 1 ;
done = 1 ;
break ;
case BARCODE_QRCODE :
case BARCODE_UPNQR :
case BARCODE_HIBC_QR :
/* ISO/IEC 18004:2015 Section 9.1 */
* left = * right = * top = * bottom = 4 ;
done = 1 ;
break ;
case BARCODE_MICROQR :
/* ISO/IEC 18004:2015 Section 9.1 */
* left = * right = * top = * bottom = 2 ;
done = 1 ;
break ;
case BARCODE_RMQR :
/* ISO/IEC JTC1/SC31N000 Section 6.3.10 */
* left = * right = * top = * bottom = 2 ;
done = 1 ;
break ;
case BARCODE_AUSPOST :
case BARCODE_AUSREPLY :
case BARCODE_AUSROUTE :
case BARCODE_AUSREDIRECT :
/* Customer Barcode Technical Specifications (2012) left/right 6mm ~ 6X, top/bottom 2mm ~ 2X */
* left = * right = 6 ; // TODO: Proper mm to X calc
* top = * bottom = 2 ; // TODO: Proper mm to X calc
done = 1 ;
break ;
case BARCODE_RM4SCC :
/* TODO */
break ;
case BARCODE_DATAMATRIX :
case BARCODE_HIBC_DM :
/* ISO/IEC 16022:2006 Section 7.1 */
* left = * right = * top = * bottom = 1 ;
done = 1 ;
break ;
case BARCODE_JAPANPOST :
/* TODO */
break ;
case BARCODE_KOREAPOST :
/* TODO */
break ;
2020-07-29 22:43:08 +03:00
case BARCODE_USPS_IMAIL :
2020-07-15 21:00:12 +03:00
/* USPS-B-3200 (2015) Section 2.3.2 left/right 0.125" ~ 6X, top/bottom 0.026" ~ 1X */
* left = * right = 6 ; // TODO: Proper inch to X calc
* top = * bottom = 1 ; // TODO: Proper inch to X calc
done = 1 ;
break ;
case BARCODE_PLESSEY :
/* TODO */
break ;
case BARCODE_KIX :
/* Handleiding KIX code brochure left/right/top/bottom 2mm ~ 2X */
* left = * right = * top = * bottom = 2 ; // TODO: Proper mm to X calc
done = 1 ;
break ;
case BARCODE_AZTEC :
case BARCODE_HIBC_AZTEC :
case BARCODE_AZRUNE :
/* ISO/IEC 24778:2008 Section 4.1 (c) & Annex A.1 (Rune) - no quiet zone required */
done = 1 ;
break ;
case BARCODE_DAFT :
/* TODO */
break ;
case BARCODE_DOTCODE :
/* ISS DotCode Rev. 4.0 Section 4.1 (3) (c) */
* left = * right = * top = * bottom = 3 ;
done = 1 ;
break ;
case BARCODE_HANXIN :
/* ISO/IEC DIS 20830:2019 Section 4.2.8 (also Section 6.2) */
* left = * right = * top = * bottom = 3 ;
done = 1 ;
break ;
case BARCODE_MAILMARK :
/* User Guide left/right/top/bottom 2mm ~ 2X */
* left = * right = * top = * bottom = 2 ; // TODO: Proper mm to X calc
done = 1 ;
break ;
case BARCODE_CHANNEL :
/* ANSI/AIM BC12-1998 Section 4.4 (c) */
* left = 1 ;
* right = 2 ;
done = 1 ;
break ;
case BARCODE_CODEONE :
/* TODO */
break ;
case BARCODE_GRIDMATRIX :
/* AIMD014 (v 1.63) Section 7.1 */
* left = * right = * top = * bottom = 6 ;
done = 1 ;
break ;
case BARCODE_ULTRA :
/* AIMD/TSC15032-43 (v 0.99c) Section 9.2 */
* left = * right = * top = * bottom = 1 ;
done = 1 ;
2020-05-21 20:22:28 +03:00
break ;
}
2020-07-15 21:00:12 +03:00
return done ; /* For self-checking */
2020-05-21 20:22:28 +03:00
}
/* Set left (x), top (y), right and bottom offsets for whitespace */
2020-07-15 21:00:12 +03:00
INTERNAL void output_set_whitespace_offsets ( struct zint_symbol * symbol , int * xoffset , int * yoffset , int * roffset , int * boffset ) {
2020-05-21 20:22:28 +03:00
int qz_left , qz_right , qz_top , qz_bottom ;
quiet_zones ( symbol , & qz_left , & qz_right , & qz_top , & qz_bottom ) ;
* xoffset = symbol - > whitespace_width + qz_left ;
* roffset = symbol - > whitespace_width + qz_right ;
if ( symbol - > output_options & BARCODE_BOX ) {
* xoffset + = symbol - > border_width ;
* roffset + = symbol - > border_width ;
}
* yoffset = qz_top ;
* boffset = qz_bottom ;
if ( symbol - > output_options & ( BARCODE_BOX | BARCODE_BIND ) ) {
* yoffset + = symbol - > border_width ;
* boffset + = symbol - > border_width ;
}
}
2020-07-15 21:00:12 +03:00
/* Set composite offset and main width excluding addon (for start of addon calc) and addon text, returning UPC/EAN type */
INTERNAL int output_process_upcean ( struct zint_symbol * symbol , int * p_main_width , int * p_comp_offset , unsigned char addon [ 6 ] , int * p_addon_gap ) {
int main_width ; /* Width of main linear symbol, excluding addon */
int comp_offset ; /* Whitespace offset (if any) of main linear symbol due to having composite */
int upceanflag ; /* UPC/EAN type flag */
int i , j , latch ;
int text_length = ustrlen ( symbol - > text ) ;
latch = 0 ;
j = 0 ;
/* Isolate add-on text */
for ( i = 6 ; i < text_length & & j < 5 ; i + + ) {
if ( latch = = 1 ) {
addon [ j ] = symbol - > show_hrt ? symbol - > text [ i ] : ' ' ; /* Use dummy space-filled addon if no hrt */
j + + ;
} else if ( symbol - > text [ i ] = = ' + ' ) {
latch = 1 ;
}
}
addon [ j ] = ' \0 ' ;
if ( latch ) {
if ( symbol - > symbology = = BARCODE_UPCA | | symbol - > symbology = = BARCODE_UPCA_CHK | | symbol - > symbology = = BARCODE_UPCA_CC ) {
* p_addon_gap = symbol - > option_2 > = 9 & & symbol - > option_2 < = 12 ? symbol - > option_2 : 9 ;
} else {
* p_addon_gap = symbol - > option_2 > = 7 & & symbol - > option_2 < = 12 ? symbol - > option_2 : 7 ;
}
}
/* Calculate composite offset */
comp_offset = 0 ;
if ( is_composite ( symbol - > symbology ) ) {
while ( ! ( module_is_set ( symbol , symbol - > rows - 1 , comp_offset ) ) ) {
comp_offset + + ;
}
}
upceanflag = 0 ;
main_width = symbol - > width ;
if ( ( symbol - > symbology = = BARCODE_EANX ) | | ( symbol - > symbology = = BARCODE_EANX_CHK )
| | ( symbol - > symbology = = BARCODE_EANX_CC ) | | ( symbol - > symbology = = BARCODE_ISBNX ) ) {
switch ( text_length ) {
case 13 : /* EAN-13 */
case 16 : /* EAN-13 + EAN-2 */
case 19 : /* EAN-13 + EAN-5 */
main_width = 95 + comp_offset ; /* EAN-13 main symbol 95 modules wide */
upceanflag = 13 ;
break ;
case 2 :
/* EAN-2 can't have addon or be composite */
upceanflag = 2 ;
break ;
case 5 :
/* EAN-5 can't have addon or be composite */
upceanflag = 5 ;
break ;
default :
main_width = 68 + comp_offset ; /* EAN-8 main symbol 68 modules wide */
upceanflag = 8 ;
break ;
}
} else if ( ( symbol - > symbology = = BARCODE_UPCA ) | | ( symbol - > symbology = = BARCODE_UPCA_CHK )
| | ( symbol - > symbology = = BARCODE_UPCA_CC ) ) {
main_width = 95 + comp_offset ; /* UPC-A main symbol 95 modules wide */
upceanflag = 12 ;
} else if ( ( symbol - > symbology = = BARCODE_UPCE ) | | ( symbol - > symbology = = BARCODE_UPCE_CHK )
| | ( symbol - > symbology = = BARCODE_UPCE_CC ) ) {
main_width = 51 + comp_offset ; /* UPC-E main symbol 51 modules wide */
upceanflag = 6 ;
}
* p_comp_offset = comp_offset ;
* p_main_width = main_width ;
return upceanflag ;
}
/* Calculate large bar height i.e. linear bars */
INTERNAL double output_large_bar_height ( struct zint_symbol * symbol ) {
int i , large_bar_count , preset_height ;
double large_bar_height ;
large_bar_count = 0 ;
preset_height = 0 ;
for ( i = 0 ; i < symbol - > rows ; i + + ) {
preset_height + = symbol - > row_height [ i ] ;
if ( symbol - > row_height [ i ] = = 0 ) {
large_bar_count + + ;
}
}
if ( large_bar_count ) {
large_bar_height = ( double ) ( symbol - > height - preset_height ) / large_bar_count ;
} else {
large_bar_height = 0.0 ; /* Not used if large_bar_count zero */
}
return large_bar_height ;
}
/* Split UPC/EAN add-on text into various constituents */
INTERNAL void output_upcean_split_text ( int upceanflag , unsigned char text [ ] ,
unsigned char textpart1 [ 5 ] , unsigned char textpart2 [ 7 ] , unsigned char textpart3 [ 7 ] , unsigned char textpart4 [ 2 ] ) {
int i ;
if ( upceanflag = = 6 ) { /* UPC-E */
textpart1 [ 0 ] = text [ 0 ] ;
textpart1 [ 1 ] = ' \0 ' ;
for ( i = 0 ; i < 6 ; i + + ) {
textpart2 [ i ] = text [ i + 1 ] ;
}
textpart2 [ 6 ] = ' \0 ' ;
textpart3 [ 0 ] = text [ 7 ] ;
textpart3 [ 1 ] = ' \0 ' ;
} else if ( upceanflag = = 8 ) { /* EAN-8 */
for ( i = 0 ; i < 4 ; i + + ) {
textpart1 [ i ] = text [ i ] ;
}
textpart1 [ 4 ] = ' \0 ' ;
for ( i = 0 ; i < 4 ; i + + ) {
textpart2 [ i ] = text [ i + 4 ] ;
}
textpart2 [ 4 ] = ' \0 ' ;
} else if ( upceanflag = = 12 ) { /* UPC-A */
textpart1 [ 0 ] = text [ 0 ] ;
textpart1 [ 1 ] = ' \0 ' ;
for ( i = 0 ; i < 5 ; i + + ) {
textpart2 [ i ] = text [ i + 1 ] ;
}
textpart2 [ 5 ] = ' \0 ' ;
for ( i = 0 ; i < 5 ; i + + ) {
textpart3 [ i ] = text [ i + 6 ] ;
}
textpart3 [ 5 ] = ' \0 ' ;
textpart4 [ 0 ] = text [ 11 ] ;
textpart4 [ 1 ] = ' \0 ' ;
} else if ( upceanflag = = 13 ) { /* EAN-13 */
textpart1 [ 0 ] = text [ 0 ] ;
textpart1 [ 1 ] = ' \0 ' ;
for ( i = 0 ; i < 6 ; i + + ) {
textpart2 [ i ] = text [ i + 1 ] ;
}
textpart2 [ 6 ] = ' \0 ' ;
for ( i = 0 ; i < 6 ; i + + ) {
textpart3 [ i ] = text [ i + 7 ] ;
}
textpart3 [ 6 ] = ' \0 ' ;
}
}