Menu

#204 Universal ZPL-ticket

2.0
open
nobody
None
2023-01-05
2020-08-26
No

Hi everyone,
I'm following the advice from GitLost to create one big ticket for the ZPL-compatability for Zint. I will use it to collect all the required information that we need.

General design rule: keep it simple. The changes should not only support ZPL, but also other use cases. 80% of the work can be reached by small changes.

1: Performance boost for scaling of regular values 0.5, 1.0, 1.5, 2.0 etc, and direct access to the buffer are solved.

https://sourceforge.net/p/zint/tickets/197/

2: Row size parameter in dots for 2D barcodes is solved.

https://sourceforge.net/p/zint/tickets/197/

3: Replace error messages with warnings. This is critical for GS1-mode to continue to generate the barcodes when dealing with incorrect GS1 ID's and incorrect length. I can perhaps deal with the requirement of inserting an '[' in the beginning of the barcode. As a general Zint-rule however, I would simply like to get warnings back as long as the barcode can be generated. This is also the case for the length of Planet/PostNet barcodes. Zint should only be a library with different return values for me, and should never decide what my frontend should see as an error. These changes are simple because it only requires us to make the return statements for errors conditional. (An FNC1 manual mode would also be an option here if it's easy to implement)

https://sourceforge.net/p/zint/tickets/142/

4: Ratio calculations in the Zint backend. This would require a float parameter like 2.0 to 3.0, and is more of a nice to have. I already have a solution in my frontend. If someone thinks of a fast backend-solution is would be nice for the future.

https://sourceforge.net/p/zint/tickets/203/

5: PDF417 structured append. No customer has ever used this yet, and I hope they never will... can Zint perhaps somehow tell us how many symbols we will need for a certain input, and which the substrings for them were?

6: Option for removing the guard bars from various barcodes. It required a big if statement in the raster.c - this is not for ZPL but for another printing protocol...

7: I will soon think of more...

Related

Code: 6198e0169e0f40f4c582d606

Discussion

  • codemonkey82

    codemonkey82 - 2020-09-11

    Hi guys,
    I was curious enough of all the new features that I decided to make a backend-update of Zint in my software. The machine has been running for several hours and everything looks good. Here are some quick observations.

    Very smooth adjustments in the frontend. The immediate buffer and fast scaling are pure gold for me:

    Symbol->warn_level = WARN_ZPL_COMPAT;
    Symbol->output_options |= OUT_BUFFER_INTERMEDIATE;
    integer_t ZintRet = 
    ZBarcode_Encode_and_Buffer(Symbol,(unsigned char *)Send,Size,0);
    
    if(ZintRet && 
          (ZintRet != ZINT_WARN_NONCOMPLIANT) && 
          (ZintRet != ZINT_WARN_USES_ECI))
    {
         error...
    }
    

    The quiet zone checks are sensible features that I cannot use. I need an option to disable those: (At least when working with printer interpreters)

    static int quiet_zones(struct zint_symbol *symbol, int *left, int *right, int *top, int *bottom) {
        int done = 0;
        *left = *right = *top = *bottom = 0;
        if (!(symbol->output_options & BARCODE_QUIET_ZONES)) {
            return 1;
        }
    

    I have noticed that the images now are generated with room for the text in the bottom. I rather create that myself, and I only want the barcode part from Zint like before. Only when dealing with guardbars I want Zint to generate the room for the text. This small if statement gives me that plus the option to disable the guardbars if I want to. I could also live with setting the textoffset in the symbol. The Zint code is getting more flexible for every release:

    static int plot_raster_default(struct zint_symbol *symbol, int rotate_angle, int file_type) {
    ...
    
        if (ustrlen(symbol->text) != 0) {
            textoffset = 9;
        } else {
            textoffset = 0;
        }
    
        // Patch
        if(!upceanflag || !symbol->guard_bars)
        {
            textoffset = 0;
        }
    

    Small bugfix for the WARN_ZPL_COMPAT. The gs1_verify returns an error, but the calling functions in code128.c and library.c are returning errors when getting warnings:

        error_number = gs1_verify(symbol, source, length, reduced);
        if (error_number >= 5) {
            return error_number;
        }
    

    The WARN_ZPL_COMPAT is also not stopping the size checks for Planet and PostNet. These need to be disabled:

    static int planet(struct zint_symbol *symbol, unsigned char source[], char dest[], int length) {
        int i, sum, check_digit;
        int error_number;
    
        if (length != 11 && length != 13) {
            strcpy(symbol->errtxt, "482: Input wrong length");
            return ZINT_ERROR_TOO_LONG;
        }
    
    static int postnet(struct zint_symbol *symbol, unsigned char source[], char dest[], int length) {
        int i, sum, check_digit;
        int error_number;
    
        if (length != 5 && length != 9 && length != 11) {
            strcpy(symbol->errtxt, "480: Input wrong length");
            return ZINT_ERROR_TOO_LONG;
        }
    

    I also need to disable this check in gs1.c

    for (i = 0; i < ai_count; i++) {
        if (data_length[i] == 0) {
            /* No data for given AI */
            strcpy(symbol->errtxt, "258: Empty data field in input data");
            return ZINT_ERROR_INVALID_DATA;
        }
    }
    

    and this length check in upcean.c

    case BARCODE_UPCE_CHK:
        if ((ustrlen(first_part) >= 6) && (ustrlen(first_part) <= (symbol->symbology == BARCODE_UPCE ? 7 : 8))) {
            error_number = upce(symbol, first_part, (char*) dest);
        } else {
            strcpy(symbol->errtxt, "290: Input wrong length");
            return ZINT_ERROR_TOO_LONG;
        }
        break;
    

    and some remaining gcc warnings:

    dllversion.c:32:0: warning: ISO C forbids an empty translation unit [-Wpedantic]
    
    #endif /* _WIN32 */
    
    ^
    
    gif.c: In function 'gif_lzw':
    
    gif.c:238:17: warning: comparison is always false due to limited range of data type [-Wtype-limits]
    
             if (Res < 0)
    

    I would be great if we can consider to include these patches/bugfixes. My goal is to update Zint every month from now on, and to run my integration tests with Valgrind each time to find eventual problems in the code.

    The WARN_ZPL_COMPAT checks can wait if needed so that we can consider if we want to push through with them everywere, or remove them completely. You guys can decide if the feature is worth the complexity of using different error handlings everywhere, or if a rewrite of the error handling can alleviate this.

     
  • Git Lost

    Git Lost - 2020-09-11

    Re the quiet zones enabled for the specific cases, they're there for backward compatibility with previous behaviour, though a case could be made for breaking this, as it would lessen confusion with the proposed BARCODE_QUIET_ZONES flag. It would have to take into account the EAN/UPC-A/E cases though, as if text is enabled they require quiet zones to fit the outside digits in.

    Re extra space at the bottom if text is disabled, I think that's a regression, which will be fixed.

    Re the gcc warnings, was wondering what version you're using, as I can't reproduce them with gcc 10.1.0 on Ubuntu with -Wall -Wextra -Wpedantic (the type-limits one is puzzling as Res is declared char).

    The WARN_ZP_COMPAT flag can be problematic as you mention. The GS1 ones can probably be dealt with with manual FNC1s (and not using GS1_MODE), as we discussed in #142, though the fix you mention re the return code from gs1_verify() should be made anyway. Re POSTNET/Planet lengths, in what context do your customers use these barcodes with incorrect lengths do you mind me asking, for internal use only? Re UPC-E length, I'm confused as to what should be produced in that case.

     
  • Robin Stuart

    Robin Stuart - 2020-09-12

    Hi - Regarding PostNet and PLANET: At the moment these plot into fixed length strings. e.g...

    /* Puts PostNet barcodes into the pattern matrix */
    INTERNAL int post_plot(struct zint_symbol *symbol, unsigned char source[], int length) {
        char height_pattern[256]; /* 5 + 38 * 5 + 5 + 5 +  1 ~ 256 */
    

    So enforcing the length does two jobs - enforces the published standard and prevents SIGSEGV. While this can easily be fixed by allocating memory based on the length of the input string I was/am planning to have a more general review of fixed-length strings and see how many can be disposed of, otherwise I think we'll just find the same problem coming up for a load of other symbols.

    With that said, however, I'm not sure when I'm likely to be able to do this - I'm expecting to be very busy for the next couple of months... At least this post should serve as a reminder for future me!

     
  • Robin Stuart

    Robin Stuart - 2020-09-12

    Also... I'm not sure how you could process longer UPCE data. What do you do with the extra digits?

     
  • codemonkey82

    codemonkey82 - 2020-09-12

    You guys are absolutly right! The UPCE-issue was a bug in my code! I sent 12345678 in one of my tests to check the guardbars. Even ZPL is cutting it off to 1234567. ZPL normally wants 10 chars and extracts 7 out of those. Thank you for asking questions about my intentions when asking for possibly insane things!

    Robin: I'm also thinking about catching the Planet/Postnet in my frontend. The only issue will be when the customer wants a certain barcode size without caring about it being scannable or not. There actually are such people out there, but will try again to talk to them. Getting rid of fixed sized strings also sounds good, but I don't want to pay with too many mallocs. If I get the manual FNC1 insertion mode, we might remove the WARN_ZPL_COMPAT option until further notice. I'm generally very relaxed about backward compatability on my behalf, so feel free to change any of my requested features if it's for the good of the software.

    GitLost: I'm using gcc for Yocto RT-Linux on ARM Cortex, so it might be a platform thing. Are you still working on the float height, and float row_height in the symbol? I'm not in a hurry for it, but I can't wait to test it :-)

     
  • Git Lost

    Git Lost - 2020-09-12

    Cool codemonkey, your requests are usually excellent so a few insane ones is fine!

    If I get the manual FNC1 insertion mode, we might remove the WARN_ZPL_COMPAT option

    I think the WARN_ZPL_COMPAT could be mutated into NO_GS1_CHECKS or something for now, where it would disable the AI and length checks, but still insist on correct GS1_MODE formatting. This could be useful for people with less than up-to-date GS1 data.

    Are you still working on the float height, and float row_height in the symbol?

    Yes I actually finished it a week back but got distracted when I noticed a bug with the half integer scaling where it's not scaling text, and then got further distracted by raster fonts! Anyway I'm going to commit a fix for the scaling tonight or tomorrow, which will also fix the extra space at the bottom thing you mentioned, and will do the float height branch shortly after.

     
  • codemonkey82

    codemonkey82 - 2020-09-13

    I understand that you have been busy - that was a huge merge request! I use Freetype to render my text so I haven't noticed any problems, but perhaps I will check out the fonts provided by Zint again. When I first tried them when discovering Zint, they didn't work for scale 0.5, so I dismissed them immediately.

    If you are checking out the handling of guardbars etc, I have another suggestion. When using for example:

    int Width = 5;
    symbol->scale = Width*0.5;
    symbol->height /= Width;
    

    to increase the module width for barcodes, I have the problem that the guardbars are also growing in length although the barcode itself isn't. To prevent that, I use the following code in raster.c:

    int GuardBarSize = ((symbol->scale/0.5)-1);
    if(GuardBarSize > 3) GuardBarSize = 3;
    
    draw_bar(pixelbuf, (0 + xoffset) * si, 1 * si, ((4+GuardBarSize) + yoffset) * si, (5-GuardBarSize) * si, image_width, image_height, DEFAULT_INK);
    
    draw_bar(pixelbuf, (2 + xoffset) * si, 1 * si, ((4+GuardBarSize) + yoffset) * si, (5-GuardBarSize) * si, image_width, image_height, DEFAULT_INK);
    
    draw_bar(pixelbuf, (46 + xoffset) * si, 1 * si, ((4+GuardBarSize) + yoffset) * si, (5-GuardBarSize) * si, image_width, image_height, DEFAULT_INK);
    
    draw_bar(pixelbuf, (48 + xoffset) * si, 1 * si, ((4+GuardBarSize) + yoffset) * si, (5-GuardBarSize) * si, image_width, image_height, DEFAULT_INK);
    
    draw_bar(pixelbuf, (92 + xoffset) * si, 1 * si, ((4+GuardBarSize) + yoffset) * si, (5-GuardBarSize) * si, image_width, image_height, DEFAULT_INK);
    
    draw_bar(pixelbuf, (94 + xoffset) * si, 1 * si, ((4+GuardBarSize) + yoffset) * si, (5-GuardBarSize) * si, image_width, image_height, DEFAULT_INK);
    

    Could we include the following two patches regarding guardbars? Being able to disable them through the symbol, and making their length more independent of the scale?

     
  • Git Lost

    Git Lost - 2020-09-13

    If the bar/space ratio suggestion 4 above, #203 is implemented then the guard bar size fix isn't needed, isn't that right? #203 is top of my list after height and manual FNC1s, as after investigating it it seems to be a fairly crucial feature that Zint is missing.

    I'd be reluctant to set guard bar size to anything but the standard 5X, but no guard bars at all could be a reasonably useful option to add to the UPC/EAN symbologies.

    Re raster text, it's still very basic and scales poorly and is still disabled for scales < 1.0. I've vague plans to improve it by implementing/stealing a bit-smoothing routine, but FreeType is the way to go I think, using it if available similar to how libpng works, with the current font stuff as a fallback.

     
  • codemonkey82

    codemonkey82 - 2020-09-13

    I would still need the guardbar adjustment, because width and ratio being different things in ZPL. In many barcodes you can change both independently of each other, and with upcean barcodes you can only change the width and not the ratio. Here is an example with an EAN-8:

    http://labelary.com/viewer.html

    ^XA
    ^BY3,2.0^FO100,100^B8N,100,Y,N^FD1234567^FS
    ^BY4,2.0^FO100,250^B8N,100,Y,N^FD1234567^FS
    ^BY5,2.5^FO100,400^B8N,100,Y,N^FD1234567^FS
    ^BY6,3.0^FO100,550^B8N,100,Y,N^FD1234567^FS
    ^BY7,3.0^FO100,700^B8N,100,Y,N^FD1234567^FS
    ^XZ
    

    You can see that the guardbar length remains the same. The first parameter in ^BY is the width, and the second one is the ratio. The ratio has no effect but the width is expanding the barcode for each step.

    Here is standard 2 of 5 where ratio has effect in combination with the width:

    ^XA
    ^BY3,2.0^FO100,100^BJN,100,Y,N^FD1234567^FS
    ^BY3,3.0^FO100,250^BJN,100,Y,N^FD1234567^FS
    ^BY4,2.0^FO100,400^BJN,100,Y,N^FD1234567^FS
    ^BY4,3.0^FO100,550^BJN,100,Y,N^FD1234567^FS
    ^BY5,2.0^FO100,700^BJN,100,Y,N^FD1234567^FS
    ^XZ
    

    1: Float height
    2: Manual FNC1
    3: Ratios

    That is a great list! If would definitly be my top 3!

     
  • Git Lost

    Git Lost - 2020-09-13

    I see, ^B8 EAN-8 is marked as fixed-ratio. I wouldn't see this restriction as applying to Zint's bar/space ratio implementation (it doesn't for BWIPP or tec-it for instance). So with a bit of sums, you could emulate this via bar/space ratio without the guard bar size change?

    (It would be easy to implement the guard bar size change but I'm put off by its hacky feel)

     

    Last edit: Git Lost 2020-09-13
  • codemonkey82

    codemonkey82 - 2020-09-14

    Yes, I would also allow the setting of ratio for all barcodes where it makes sense, independently of the ZPL. It isn't possible however to emulate width changes with ratio changes, and the width will always increase the guardbar height because of the scaling. This isnt't an important problem, and you are definitly right about the solution being hacky. I will play around with it and see if there's a better solution. Until then, the float height, manual FNC1, and ratios will be more than enough to keep me happy!

     
  • Git Lost

    Git Lost - 2021-07-13

    Hi just to warn anyone using WARN_ZPL_COMPAT that it is proposed to replace this with GS1NOCHECK_MODE - see MR #128.

     

    Last edit: Git Lost 2021-07-13
  • codemonkey82

    codemonkey82 - 2021-09-12

    Hi guys,
    I finally got some time to update my Zint backend to the latest version, and as usual it was a very pleasant experience. The new options and the ongoing refactoring has been big wins for me, and the patches needed when updating are just speedbumps now.

    Here are the ones still remaining for me. If we could integrate some of these points in some form in Zint it would be great, but I already consider myself a very satisfied user:

    First some warnings from the compiler. I use the -pedantic option, and the type limit thing could be a platform thing. (Embedded Linux on ARM-Cortex).

    dllversion.c:32:0: warning: ISO C forbids an empty translation unit [-Wpedantic]
    #endif /* _WIN32 */
    gs1.c: In function 'cset82':
    gs1.c:96:55: warning: comparison is always false due to limited range of data type [-Wtype-limits]
    if (*d < '!' || *d > 'z' || c82[*d - '!'] == -1) {
    tif.c: In function 'tif_pixel_plot':
    tif.c:97:5: warning: missing braces around initializer [-Wmissing-braces]
    tiff_color_t color_map[256] = {0};
    tif.c:97:5: warning: (near initialization for 'color_map[0]') [-Wmissing-braces]
    

    I need ITF14 barcodes without any boxes around them. I don't know any way of making this happen through the interface, so I comment this part out in 2of5.c:

    /*if (!((symbol->output_options & BARCODE_BOX) || (symbol->output_options & BARCODE_BIND))) {
        // If no option has been selected then uses default box option
        symbol->output_options |= BARCODE_BOX;
        if (symbol->border_width == 0) { // Allow override if non-zero
            // GS1 General Specifications 21.0.1 Sections 5.3.2.4 & 5.3.6 (4.83 / 1.016 ~ 4.75)
            symbol->border_width = 5; // Note change from previous value 8
        }
    }*/
    

    I once encountered a crash when using ITF14 with boxes. The problem was in raster.c in the function draw_bar, when the parameter image_height is zero. I fixed it with the following patch, although it might be a case of healing the symptoms instead of the disease. If I just return from the function instead of setting png_ypos to zero, the upper line of the box is missing. If setting to zero, everything looks good:

    static void draw_bar(unsigned char *pixelbuf, const int xpos, 
                         const int xlen, const int ypos, const int ylen,
                         const int image_width, const int image_height, const char fill) {
    
        int i, j, png_ypos;
        png_ypos = image_height - ypos - ylen;
        if(png_ypos < 0) png_ypos = 0; // Patch
    

    In the same file (raster.c) I can disable the guard bars with just two lines of code before setting image height and image width. I need this option for certain printing protocols:

        if(!symbol->guard_bars) // Patch
            textoffset = 0;
    
        image_width = (symbol->width + xoffset + roffset) * si;
        image_height = (symbol->height + textoffset + yoffset + boffset) * si;
    

    The code93 has been standardized into not showing the checksums (good decision), but I need those checksums for some printing protocols like the ZPL. Could we provide an option to enable the checksum in the text again, although the default of course should be to have them disabled? I restored the old lines of code in code.c:

        symbol->text[length] = set_copy[c];
        symbol->text[length + 1] = set_copy[k];
        symbol->text[length + 2] = '\0';
    

    I need to disable the quiet zones in output.c. It would be great to have an option for this, and there seems to be something planned in this direction by using BARCODE_QUIET_ZONES. The feature of enforcing quiet zones is 100% correct for 99 of 100 users, and I am sadly enough the last one. Certain customers would eat me alive if I tried to make them use quiet zones. I disable them today with this code:

    /* Return minimum quiet zones for each symbology */
    static int quiet_zones(struct zint_symbol *symbol, 
                           float *left, float *right, 
                           float *top, float *bottom) {
    
        int done = 0;
        *left = *right = *top = *bottom = 0.0f;
        return(0); // Patch
    

    The GS1NOCHECK_MODE is working perfectly for me. I would just like two additional errors disabled when using it. For some reason people love to send data before the first AI, and also to send AI's without any data following it. Very large companies have been doing this systematically for years, and I would love the option to allow this in Zint. (Leaving out the question of it's sane or not). Here are the error check being commented out in gs1.c:

        /*if (source[0] != obracket) {
            strcpy(symbol->errtxt, "252: Data does not start with an AI");
            return ZINT_ERROR_INVALID_DATA;
        }*/
    
        /*if (data_length[i] == 0) {
            // No data for given AI
            strcpy(symbol->errtxt, "258: Empty data field in input data");
            return ZINT_ERROR_INVALID_DATA;
        }*/
    

    And now to my more extravagant cravings. I want to set the row height in dots for Codablock and PDF417. I love the present function to set the total height using symbol->height, and I'm using that most of the time, but there are cases where I need to set the row height without knowing how many rows the symbol will finally have.

    Because of the elegant refactoring of the code, this is simple to patch. I change the height before the function set_height, and I also allow less than 3 rows as minimum. In pdf417.c:

    if(symbol->row_height_input)
        symbol->height = symbol->row_height_input * symbol->rows;
    error_number = set_height(symbol, 0.0f, 0.0f, 0.0f, 0 /*no_errtxt*/);
    

    and in codablock.c:

    symbol->height *= symbol->row_height_input * rows;
    (void) set_height(symbol, min_row_height, 10.0f * rows, 0.0f, 1 /*no_errtxt*/);
    

    Ok, I think that's all of it. Some general thoughts when writing this: Zint was already brilliant the first time I downloaded it after getting the BSD-license, and it has since matured into an absolute industry standard. I even recommend Zint to our competitors, because so much human time will be saved with everyone using this flexible software instead of trying to imitate it for themselves. I don't think I'm the only one using Zint in a real time embedded system today, which is great!

     
    • Git Lost

      Git Lost - 2021-09-13

      Hi codemonkey82, nice to hear from you again and thanks for the kind words.

      Re warnings, [922963] may have addressed those.

      Re ITF14 with no box, you can do this already although it's a bit counter-intuitive - specify BARCODE_BOX (or BARCODE_BIND) explicitly and leave border_width zero.

      Re ITF14 crash - I can't reproduce this after trying a number of things - could you post the settings (and data if relevant) that caused this if possible?

      Re guard bars, will add something to disable them - thinking of adding a guardheight field to zint_symbol which defaults to 5.0f and can be set to 0.0f to disable.

      Re CODE93 displaying check chars, added [bd0640] to address this.

      Re quiet zones, thinking of implementing the BARCODE_QUIET_ZONES option that's more or less there at the moment and then also adding an e.g. BARCODE_NEVER_QZONES option to disable quiet zones for the ones that currently always have a quiet zone (with allowances for space for the outside characters of EAN-13 and UPC-A/E).

      Re GS1NOCHECK_MODE the 0-length data part of this has been addressed by [86c157]. Will come back to you on the not starting with an AI - if you could post some examples of data that requires this it would be good.

      Re "extravagant cravings" (lol) will come back to you on these.

      Also will mention that barcode ratios (#203) is still near the top of my to-do list (one year later!).

      Thanks, regards, Martin

       

      Related

      Commit: [86c157]
      Commit: [922963]
      Commit: [bd0640]

      • codemonkey82

        codemonkey82 - 2021-09-13

        Hi Martin,
        don't worry about the ratios. I have an acceptable solution in my frontend, and I'm ready to wait for a solution which is both efficient and maintainable. I'm always around to watch your progress through the code jungle from the trees above. It has been an awesome journey so far.

        The guardheight suggestion is absolutely perfect! Then I can also decrease this value while increasing the scale to avoid the guardbars growing too long. One customer has complained about it, and I have promised him for a year or so that I will fix it. These are great news that I will actually be able to deliver on that promise so easily!

        Code93 and quiet zone options both sound great. I will also try the ITF14 trick. Here is the code which crashes the draw_bar function. I just managed to reproduce it on my platform. It seems to react on the decimals in the height:

        bool Test(void)
        {
            char Send[100] = "0501054800395";
            struct zint_symbol *Symbol = ZBarcode_Create();
            if(!Symbol) return(false);
        
            Symbol->input_mode = UNICODE_MODE;
            Symbol->warn_level = WARN_DEFAULT;
            Symbol->output_options |= OUT_BUFFER_INTERMEDIATE;
            Symbol->scale = 3.000000;
            Symbol->height = 61.8;
            Symbol->symbology = BARCODE_ITF14;
            Symbol->whitespace_width = 24;
            Symbol->border_width = 4;
            Symbol->output_options |= BARCODE_BIND;
        
            int ZintRet = 
            ZBarcode_Encode_and_Buffer(Symbol,(unsigned char*) Send,strlen(Send),0);
        
            if(ZintRet && 
                  (ZintRet != ZINT_WARN_NONCOMPLIANT) && 
                  (ZintRet != ZINT_WARN_USES_ECI))
            {
                printf("Error: %d\n",ZintRet);
                fflush(stdout);
                ZBarcode_Delete(Symbol);
                return(false);
            }
        
            ZBarcode_Delete(Symbol);   
            return(true);
        }
        

        Here is some typical ZPL code which uses GS1 without any valid ID's. The ID is unknown to ZPL, which then just shoves all the data into the barcode without trying to identify any ID's at all. The solution in Zint is just to write the whole value into the code: "44125123400109" without any "[]". This triggers the error message about "252: Data does not start with an AI".

        ^XA
        ^FO100,100^BY4,3.0^BCN,300,N,N,Y,N^FD>;>844125123400109^FS
        ^XZ
        

        Try it out in the ZPL-viewer:
        http://labelary.com/viewer.html

         
  • codemonkey82

    codemonkey82 - 2021-10-25

    Hi Martin,
    I have once again succumbed to the temptation of spending another day with Zint. I have a deadline looming in the background, but your latest updates just looked too good to wait for. I will test your raster optimizations on a live machine this week, and the needed patches from my side have been reduced to just two. What a difference from the earlier days! I still remember when I needed about 10 different complicated patches, changing with every release, to get things working! Now I just copy the backend folder into my project, and within minutes I can type "make":

    First a suspected bugfix in gs1.c, where I think the error is triggered even when using the GS1NOCHECK_MODE:

    // Patch
    if (!(symbol->input_mode & GS1NOCHECK_MODE) && (min_ai_length == 1 || ai_no_data)) {
    // if (!(symbol->input_mode & GS1NOCHECK_MODE) || min_ai_length == 1 || ai_no_data) {
        /* AI is too short */
        strcpy(symbol->errtxt, "256: Invalid AI in input data (AI too short)");
        return ZINT_ERROR_INVALID_DATA;
    }
    

    The next one is the additional feature of deciding the height by setting the size of the rows generated in the symbol. Thanks to the unifying function of set_height(), this is possible with just some few lines of code in common.c and zint.h

    INTERNAL int set_height(struct zint_symbol *symbol, float min_row_height, float default_height, float max_height, int no_errtxt) {
    
        int error_number = 0;
        float fixed_height = 0.0f;
        int zero_count = 0;
        float row_height;
        int i;
        int rows = symbol->rows ? symbol->rows : 1; /* Sometimes called before expand() */
    
        // Patch
        if(symbol->row_height_input)
        {
            min_row_height = 0;
            symbol->height = (symbol->row_height_input * symbol->rows);
        }
    
    
    struct zint_symbol {
        …
        // Patch
        float row_height_input;
    }
    

    The last patch is in pdf417.c, requiring a small adjustment of the standard size of the symbol, and the feature of setting the number of desired rows in option_3. Needless to say; the reference for default size in Zint should be the official barcode standards and not the ZPL, so it would be ok for me to continue patching this in the future. To set the rows additionally to the columns however, would be great to have in the standard code:

    if (symbol->option_3) {
        symbol->option_2 = (longueur / symbol->option_3);
    }
    if (symbol->option_2 < 1) {
        symbol->option_2 = (int) (sqrt(longueur / 3.0))-0.5;
        //symbol->option_2 = (int) (0.5 + sqrt(longueur / 3.0));
    }
    

    Some small things in the end. I'm using warnings for C function prototypes without parameters, so it would be great to change this one function in zint.h by adding void as a parameter: ZINT_EXTERN int ZBarcode_Version(void);

    Also the pdf417 sometimes get white lines within the symbol on my platform. This got much better with your update dealing with the float values, but still happens sometimes. I just filter them out in my frontend for now.

    BTW, my other wishes about Codablock etc were just bugs in my own software. Those bugs disappeared after my body decided to bring my brain to the coffee machine :p

     
    • Git Lost

      Git Lost - 2021-10-27

      Hi CM, thanks very much for the feedback.

      Re the AI too short bug, commit [eb6e5da] allows the use of a dummy prefix [] if the AI is unknown, which I was hoping would address your use case, on the assumption that you lookup AIs and format them in square brackets for Zint if found - the requirement now being to insert a dummy [] prefix for those not found. Please let me know if I got this wrong...

      Re setting height based on row height - yes, plan to support this very shortly. Was thinking of using an input mode flag e.g.BARCODE_ROW_HEIGHT to change the interpretation of the height input to per-row height, to avoid adding another zint_symbol field, but may use your row_height field instead if that works out better.

      Re being able to specify the number of rows for PDF417, yes this is a missing feature that should be added. Will use option_3 as you suggest.

      Re doing the change to the default which uses sqrt() to do in effect a floor() instead of a ceil() as of now, my only concern is with back-compatibility, as it's not mentioned in the standard that I can see - will do some experimentation.

      Re ZBarcode_Version(void) - will do.

      Re blank lines in PDF417 - this is very bad. Could you isolate the instances where this happens and post the data and settings if possible?

      Good to hear about Codablock wishes (which I can't trace tbh!)

      Thanks, Martin

       
  • codemonkey82

    codemonkey82 - 2021-10-28

    Hi Martin,
    yes the dummy [] for GS1 data work perfectly. I no longer need to have the error message disabled, but I suspect that we have a bug in the if statement. I still get the error when using the [] dummy, because the if statement basically says:

    if(!RelaxMode || ErrorNoticed)
        SetError()
    

    it should instead be:

    if(!RelaxMode && ErrorNoticed)
        SetError()
    

    Your other plans also sound good. Our pattern has worked great so far: I give you a hacky example of my intentions, and you do something flexible and maintainable out of it. (BARCODE_ROW_HEIGHT is probably much better compared to an extra variable)

    I will try to reproduce the PDF417 problem in the next days. Also I forgot to thank you for the structured append. I really look forward to implement it in my frontend!

     
    • Git Lost

      Git Lost - 2021-10-28

      Hi re dummy [] it should only go into that if (!RelaxMode || ...) statement though if there's an ErrorNoticed already, i.e. if min_ai_length <= 1.

      However the OR-ed checks were buggy, and have been corrected via [706f02] to only check that zero-length AIs have data and that there're no single-digit AIs. So the following data will fail:

      "[]" (no data), "[1]1" and "[1]"(single-digit AI with or without data)

      but these will succeed:

      "[]1", "[]11", "[11]"

      Hope that works for you. Thanks for the other comments, have plans to add an API helper re Structured Append to calculate QR parity (simple to do), regards, Martin

       

      Related

      Commit: [706f02]

  • codemonkey82

    codemonkey82 - 2021-10-30

    Hi Martin,
    that sounds really good with the GS1 data. I will soon try it out again.

    Here is a test for the white lines in PDF417. Hopefully the the problem can be reproduced:

    void Test(void)
    {
        struct zint_symbol *Symbol = ZBarcode_Create();
        Symbol->symbology = BARCODE_PDF417;
        Symbol->height = 16.000;
        Symbol->scale = 1.5;
        Symbol->option_1 = 5;
        Symbol->option_2 = 8;
        Symbol->option_3 = 0;
    
        const char *Send = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBB";
    
        size_t Size = strlen(Send);
        Symbol->warn_level = WARN_DEFAULT;
        Symbol->output_options |= OUT_BUFFER_INTERMEDIATE | BARCODE_NO_QUIET_ZONES;
    
        int ZintRet = ZBarcode_Encode_and_Buffer(Symbol,(unsigned char *)Send,Size,0);
    
        if(ZintRet && (ZintRet != ZINT_WARN_NONCOMPLIANT) && (ZintRet != ZINT_WARN_USES_ECI))
        {
            puts("Error");
            fflush(stdout);
            return;
        }
        printf("Total Rows: %d\n",Symbol->bitmap_height);
        fflush(stdout);
    
        unsigned char *Data = Symbol->bitmap;
        for(int Row=Symbol->bitmap_height-1; Row >= 0; Row--)
        {
            if(Data[0] == '0')
            {
                printf("Empty Row: %d\n",Row);
                fflush(stdout);
            }
            Data+=(Symbol->bitmap_width*1);
        }
        ZBarcode_Delete(Symbol);
    }
    
     
    • Git Lost

      Git Lost - 2021-10-30

      That's fab Null, can reproduce, will investigate....

       
  • codemonkey82

    codemonkey82 - 2023-01-02

    Hi guys,
    I hope the new year made a good impression on you all so far. In my case it made a hacky start. A customer wants to switch between mode B and mode C in a code128 to achieve a specified width instead of only using the module width. A new IT-system insists on sending such horrors after a software update in the production plant. Here is an example for the ZPL-viewer:
    http://labelary.com/viewer.html

    ^XA
    ^BY3^FO100,100^BCN,100^FD>:12345>56789^FS
    ^XZ
    

    We start in B, and after 12345 we switch to C for 6789. Zint has the convenient option BARCODE_CODE128B which works perfectly to suppress mode C for whole barcodes, but this time it won't do because of the suppression only targeting subsets of the data. Mode A and other stuff I can handle in my frontend, but now I need to dive into Zint to expand the suppression feature. Here is my hacky solution so far which uses the primary-string: when a 'B' is found, the data on the corresponding position is forbidden to use mode C. It seems to work fine, but I would feel calmer when using a standard feature in Zint which has been reviewed by people that actually know what they are doing. May this code fill the role as a negative inspiration for a more consistent standard feature (if possible) :p

    In code128.c:

        do {
            list[1][indexliste] = mode;
            while ((list[1][indexliste] == mode) && (indexchaine < sourcelen)) {
                list[0][indexliste]++;
                indexchaine++;
                if (indexchaine == sourcelen) {
                    break;
                }
                mode = c128_parunmodd(source[indexchaine]);
                if ((symbol->symbology == BARCODE_CODE128B) && (mode == C128_ABORC)) {
                    mode = C128_AORB;
                }
    
                // Here comes the hack...
                if (symbol->primary[indexchaine] == 'B') {
                    mode = C128_AORB;
                }
    
            }
            indexliste++;
        } while (indexchaine < sourcelen);
    
     
    • Git Lost

      Git Lost - 2023-01-05

      Hi codemonkey, good to hear from you again, and Happy New Year. That's an ingenious workaround to use primary.

      Although as you say this insistence on specifying the subsets to use manually in CODE128 makes no sense to me , it has been requested before and so I think I will implement a scheme to enable it.

      Was thinking of using escapes similar to ZPL, e.g. \A, \B and \C, but making them available for CODE128 (and GS1_128 and maybe some other CODE128-based barcodes) only. Hope that's the "negative inspiration" (lol) you were seeking....

      Am in a bit of post-solstice lull (hence the delay in replying, apologies), so it may be a few weeks before I get round to doing this, all the best, Martin

       

Log in to post a comment.

MongoDB Logo MongoDB