graphicore / librebarcode

Libre Barcode: barcode fonts for various barcode standards.
https://graphicore.github.io/librebarcode
SIL Open Font License 1.1
429 stars 25 forks source link

Make Code39 work with Brother QL820 printer; AND: fontmake issue building fonts, ttfautohint is required. #19

Closed MMartinezV closed 5 years ago

MMartinezV commented 5 years ago

Hello,

Following the procedure to build the fonts I get these messages:

INFO:fontmake.font_project:Building TTF for LibreBarcode39-Regular
INFO:ufo2ft:Pre-processing glyphs
INFO:ufo2ft.filters:Running DecomposeComponentsFilter on LibreBarcode39-Regular
INFO:ufo2ft.filters:Running CubicToQuadraticFilter on LibreBarcode39-Regular
INFO:ufo2ft.filters.cubicToQuadratic:New spline lengths:
INFO:ufo2ft:Building OpenType tables
WARNING:ufo2ft.fontInfoData:Underline thickness not set in UFO, defaulting to UPM * 0.05
WARNING:ufo2ft.fontInfoData:Underline position not set in UFO, defaulting to UPM * -0.075
WARNING:ufo2ft.fontInfoData:Underline thickness not set in UFO, defaulting to UPM * 0.05
INFO:ufo2ft.postProcessor:Renaming glyphs to final production names
INFO:fontmake.font_project:Saving /tmp/tmp3ZCqt0.ttf
Traceback (most recent call last):
  File "/root/librebarcode/venv/bin/fontmake", line 10, in <module>
    sys.exit(main())
  File "/root/librebarcode/venv/local/lib/python2.7/site-packages/fontmake/__main__.py", line 422, in main
    ufo_paths, is_instance=args.pop("masters_as_instances"), **args
  File "/root/librebarcode/venv/local/lib/python2.7/site-packages/fontmake/font_project.py", line 1026, in run_from_ufos
    self.build_ttfs(ufos, **kwargs)
  File "/root/librebarcode/venv/local/lib/python2.7/site-packages/fontmake/font_project.py", line 311, in build_ttfs
    self.save_otfs(ufos, ttf=True, **kwargs)
  File "/root/librebarcode/venv/local/lib/python2.7/site-packages/fontTools/misc/loggingTools.py", line 375, in wrapper
    return func(*args, **kwds)
  File "/root/librebarcode/venv/local/lib/python2.7/site-packages/fontmake/font_project.py", line 636, in save_otfs
    ttfautohint(otf_path, hinted_otf_path, args=autohint)
  File "/root/librebarcode/venv/local/lib/python2.7/site-packages/fontmake/ttfautohint.py", line 34, in ttfautohint
    rv = subprocess.call(arg_list + args.split() + file_args)
  File "/usr/lib/python2.7/subprocess.py", line 168, in call
    return Popen(*popenargs, **kwargs).wait()
  File "/usr/lib/python2.7/subprocess.py", line 390, in __init__
    errread, errwrite)
  File "/usr/lib/python2.7/subprocess.py", line 1024, in _execute_child
    raise child_exception
OSError: [Errno 2] No such file or directory

Playing with buildAll script I've seen that the problem is related to fontmake, and if I remove the autohint args I get the master_ttf fonts.

The problem is on line 229, fontmake -u $UFO_DIR --production-names --keep-overlaps --keep-direction -a"-I" -o ttf just change it for fontmake -u $UFO_DIR --production-names --keep-overlaps --keep-direction -o ttf Hope it helps to fix the build procedure.

Manuel Martínez

MMartinezV commented 5 years ago

By the way, my target is to build compatible fonts with zbarimg (http://zbar.sourceforge.net/).

I've been using another C39 font for years in combination with zbar without problems but now, that font is to big to use it on some new labels and, after making some tests I believe that LibreBarcode Font would be perfect to fit on the new labels.

The problem now is that zbarimg doesn't recognize the Librebarcode barcodes and I would like to change some parameters to make it work (change height, width, narrow...). I've change many of this params but, after compiling the font, I always get the same result font.

Can you explain me the recommended way to change this params?

Thanks in advance,

Regards,

Manuel Martínez

MMartinezV commented 5 years ago

Ok, I've found how to build the fonts. Just install ttfautohint and I've also installed the python wrapper (don't know if it's needed but it works).

apt-get install ttfautohint
pip install ttfautohint-py

But I'm still trying to change the font properties.

Regards, Manuel Martínez

graphicore commented 5 years ago

Hi @MMartinezV thanks for reporting, I'll add a note to README.md that ttfautohint is required!

The problem now is that zbarimg doesn't recognize the Librebarcode barcodes

I can't reproduce this, but maybe you can explain in more detail what doesn't work for you. In general the Code 39 fonts seem to work with zbar:

Screenshot from 2019-09-18 13-52-38

> zbarimg ~/Pictures/Screenshot\ from\ 2019-09-18\ 13-52-38.png 
Name Error (Connection ":1.342" is not allowed to own the service "org.linuxtv.Zbar" due to security policies in the configuration file)
CODE-39:HELLO WORLD
scanned 1 barcode symbols from 1 images in 0.3 seconds

Ignoring the "Name Error" line, IDK what that is about, the next line successfully states: CODE-39:HELLO WORLD

The problem now is that zbarimg doesn't recognize the Librebarcode barcodes and I would like to change some parameters to make it work (change height, width, narrow...). I've change many of this params but, after compiling the font, I always get the same result font.

Can you explain me the recommended way to change this params?

I suggest to make your own path/to/librebarcode/app/bin/buildAll script.

If you run the buildAll script you get at one point a message like this:

Got following parameters for Code39Builder:
  bottom: 0(default)
  fontBelowHeight: 390(default)
  force: false(default)
  narrow: 30(default)
  top: 590(default)
  wide: 90
  wideToNarrowRatio: 3(default)

That's also the stuff you likely want to modify. If you change top or any other height related property, you'll likely have to change the height related font info parameters as well, e.g. ASCENDER, CAP_HEIGHT etc. and if you are unsure about these, Font Bakery can help you to verify that your settings are OK. But in my opinion, changing width related properties should suffice for what you described. I would try to get it done using narrow and wideToNarrowRatio. E.g.:

PARAMETERS_CODE39TEXT=$(cat <<EOT
{
    "narrow": 60
  , "wideToNarrowRatio": 2.5
}
EOT
)

With that setup I get:

Got following parameters for Code39Builder:
  bottom: 0(default)
  fontBelowHeight: 390(default)
  force: false(default)
  narrow: 60
  top: 590(default)
  wide: 150
  wideToNarrowRatio: 2.5

A quick test of that font (screenshot from mdlFontSpecimen/html/drop-fonts) with the text *HELLO WORLD*:

Screenshot from 2019-09-18 14-48-02

> zbarimg ~/Pictures/Screenshot\ from\ 2019-09-18\ 14-48-02.png 
Name Error (Connection ":1.363" is not allowed to own the service "org.linuxtv.Zbar" due to security policies in the configuration file)
CODE-39:HELLO WORLD
scanned 1 barcode symbols from 1 images in 0.27 seconds

Here's the content of that new build script ./app/bin/buildModifiedCode39:

#!/usr/bin/env bash
# execute like this:
#   $ ./app/bin/buildAll

cd `dirname $BASH_SOURCE`/../../;
SOURCE_DIR=`pwd`/sources
FONTS_DIR=`pwd`/fonts

rm -rf $SOURCE_DIR $FONTS_DIR autohinted master_ttf

mkdir -p $SOURCE_DIR
mkdir -p $FONTS_DIR

TEXT_BELOW_FONT="./app/assets/Inconsolata-Regular.ttf"
BUILD="./app/bin/build"
ADD_DSIG="./app/bin/add-dsig.py"

FAMILY_BASE_NAME="My Modified Libre Barcode"
FILE_BASENAME="MyModifiedLibreBarcode"

UNITS_PER_EM=1000
ASCENDER=600
DESCENDER=-400
STYLE_NAME="Regular"
STYLEMAP_STYLE_NAME="regular"
X_HEIGHT=400
CAP_HEIGHT=590
VENDOR_ID="GRCR"
LICENSE='This Font Software is licensed under the SIL Open Font '\
'License, Version 1.1. This license is available with a FAQ at: http://scripts.sil.org/OFL'
LICENSE_URL='http://scripts.sil.org/OFL'
COPYRIGHT="Copyright 2017 The $FAMILY_BASE_NAME Project Authors (lasse@graphicore.de)"
VERSION="Version 0.001"
VERSION_MAJOR=0
VERSION_MINOR=1

FONTINFO_CODE39TEXT=$(cat <<EOT
{
    "familyName": "${FAMILY_BASE_NAME} 39 Text"
  , "styleMapFamilyName": "${FAMILY_BASE_NAME} 39 Text"
  , "styleMapStyleName": "${STYLEMAP_STYLE_NAME}"
  , "styleName": "${STYLE_NAME}"
  , "unitsPerEm": ${UNITS_PER_EM}
  , "ascender": ${ASCENDER}
  , "descender": ${DESCENDER}
  , "xHeight": ${X_HEIGHT}
  , "capHeight": ${CAP_HEIGHT}
  , "openTypeOS2Type": []
  , "openTypeOS2VendorID": "${VENDOR_ID}"
  , "openTypeNameLicense": "${LICENSE}"
  , "openTypeNameLicenseURL": "${LICENSE_URL}"
  , "openTypeNameVersion": "${VERSION}"
  , "copyright": "${COPYRIGHT}"
  , "versionMajor": ${VERSION_MAJOR}
  , "versionMinor": ${VERSION_MINOR}
  , "openTypeOS2TypoLineGap": 0
}
EOT
)

PARAMETERS_CODE39TEXT=$(cat <<EOT
{
    "narrow": 60
  , "wideToNarrowRatio": 2.5
}
EOT
)

TARGETS=(CODE39TEXT)
              # UFO_BASE CODE_TYPE USEFONT
TARGET_CODE39TEXT=("Code39Text" "Code39" 1)

for TARGET in ${TARGETS[@]}; do
    _FONTINFO_DATA_REFERENCE="FONTINFO_$TARGET"[@]
    FONTINFO=( "${!_FONTINFO_DATA_REFERENCE}" )

    _PARAMETERS_DATA_REFERENCE="PARAMETERS_$TARGET"[@]
    PARAMETERS=( "${!_PARAMETERS_DATA_REFERENCE}")
    if [ "${#PARAMETERS[@]}" -eq 0 ];then
        PARAMETERS='{}'
    fi

    _TARGET_DATA_REFERENCE="TARGET_$TARGET"[@]
    TARGET_DATA=( "${!_TARGET_DATA_REFERENCE}" ) # copies the list
    UFO_BASE=${TARGET_DATA[0]}
    UFO_DIR="$SOURCE_DIR/$FILE_BASENAME${UFO_BASE}-Regular.ufo"
    CODE_TYPE=${TARGET_DATA[1]}
    USEFONT=${TARGET_DATA[2]}
    FONTARG=""
    if [ $USEFONT -eq 1 ];then
        FONTARG=" --fontbelow $TEXT_BELOW_FONT "
    fi

    $BUILD $CODE_TYPE $UFO_DIR --fontinfo "$FONTINFO" --parameters "$PARAMETERS" $FONTARG
    fontmake -u $UFO_DIR --production-names --keep-overlaps --keep-direction -a"-I" -o ttf

done

cp autohinted/master_ttf/* fonts && \
cp OFL.txt fonts && \
rm -rf master_ttf autohinted
ls fonts

FILES=$(find fonts -type f -name "*.ttf")
python $ADD_DSIG $FILES;

And here's the font:

MyModifiedLibreBarcodeCode39Text-Regular.zip

MMartinezV commented 5 years ago

Hi graphicore,

Thanks for your long and detailed answer.

Yesterday I did many tests building different fonts (modifying the narrow and wideToNarrowRatio directly on the js file) and as you say, the zbarimg does recognize LibreBarcodeCode39 fonts.

Now I've realised that the problem is related to the printer or the paper I'm using to print it.

When I print the font with a Brother QL820WNB printer on a small label (54mmx17mm) the result is not recognized by zbarimg. In fact, the barcode is not clear as the white bars between the narrow or wide symbols are very very narrow.

screenshot-librebarcode-code39

But If I print the same font on another laser printer on a A4 paper, the font is clear enough to be recognized by zbarimg.

Maybe it would help to increase the width of the white bars into each glyph, is it possible?

It's extrange because this doesn't happend when using another barcode font (C3936MedLaser) to print labels with the QL820.

By the way, thanks again for your recommendation on how to build the fonts, is really simple and better than modifying the source of code39.js file.

Tomorrow I will post some better photos of the barcodes to show you the problem.

Regards,

Manuel Martínez

graphicore commented 5 years ago

Aha, that's an interesting use case! One quick thing I'd suggest to try out is to remove the hinting of the fonts. It could be that it does more harm than good in that case, also ttfautohint does not know how to hint barcodes optimally, since it's such a niche thing.

To not do autohinting remove the -a"-I" from the fontmake command. Also the fonts will not end in the autohinted directory eventually, so you might want to change the copying commands at the end of the build script as well. The relevant parts would change to something like:

    # ... 
    $BUILD $CODE_TYPE $UFO_DIR --fontinfo "$FONTINFO" --parameters "$PARAMETERS" $FONTARG
    fontmake -u $UFO_DIR --production-names --keep-overlaps --keep-direction -o ttf

done

cp master_ttf/* fonts && \
cp OFL.txt fonts && \
rm -rf master_ttf
ls fonts
# ...

Also, if removing the hinting works, maybe better arguments for ttfautohint could do good as well. ;-) After all, hinting is supposed to improve rendering in small sizes, but still ttfautohint specializes in autohinting human scripts, not barcodes and hinting could change the proportions of wide to narrow a lot.

Maybe it would help to increase the width of the white bars into each glyph, is it possible?

Basically the only relevant parameter for this is the wideToNarrowRatio the rest of the parameters is more relevant for the type setting that's done with the font. So, supposedly, if you go with the plain c39 font without text below, you can concentrate on that and modify the font-size, to make the barcode overall bigger or smaller . Once you are happy with your result (when you can scan it) you can tweak the narrow and maybe top parameters to meet the result you want to have at a given font size. For the scanner, the ratio between thick and thin bars is most important, and maybe (?) that they appear as bars, that are rectangular and taller than wide, but I don't know which assumptions scanners make here.

That said, to make the narrow bars (white and black) wider relative to the wide bars, set wideToNarrowRatio: 2 hence, since there's a narrow white bar between each black bar (if there's not a wide white bar), in relation to the black the white will be bigger, it will also just look as if the black bars got thinner. If that's not enough, we may want to remove the validation of the wideToNarrowRatio (using the --force option is suggested but I just found out that it is broken) Also, being bigger than a ratio of 1/2 is out of the standard.

Eventually, if this is not sufficient, we may have to add a parameter to compensate for the "ink swell" of the black of your printer, but I hope we can avoid this.

graphicore commented 5 years ago

I've been using another C39 font for years in combination with zbar without problems …

It could be an approach to try to rebuild the appearance of the previous font you used and from there tweak the font to be more size efficient.

… but now, that font is to big to use it on some new labels and, after making some tests I believe that LibreBarcode Font would be perfect to fit on the new labels.

If you say the old font is "to big" do you mean to tall or to wide? Too wide is more complicated to achieve, because the C39 format needs horizontal space. C128 could be more efficient, but it's also harder to use, because it needs an encoder to make a valid barcode.

MMartinezV commented 5 years ago

Hi,

Without ttfautohint it doesn't work also. I did the first tests without ttfautohint.

In the next capture you can see different build tests, the first one is the previous font (Cmedlaser): Screenshot 2019-09-19 at 13 56 40

We have problems to use the old font with these labels because there is a problem with right and left margin and the program we use to print generates 3 pages (3 labels): (1)blank-(2)code39-(3)blank, and the users need to do a preview, select just one page, change the paper size, etc. That's a lot of time to write a barcode. With LibreBarcode we can solve this problem as it fits perfectly in the print area but we have the "ink swell" one.

In the next image you can see a photo taken from some printed labels:

etiquetas_impresas

I think it would be great to have the "ink swell" correction parameter, or a parameter to increase the blank gaps between symbols.

And about the top parameter, I don't think there is a need to change it. At the begining I thought that it could be the problem, but I was wrong.

Thanks,

Manuel Martínez

MMartinezV commented 5 years ago

Bad luck,

I've build many fonts with wideToNarrowRatio 2 and below 2 but when I print them I the white gap is too small to recognize it.

Here are some tests (on screen) Screenshot 2019-09-19 at 19 35 00

And here the result after printing some of them:

Screenshot 2019-09-19 at 19 33 39

Regards, Manuel Martínez

graphicore commented 5 years ago

I'll implement parameters to adjust for ink swell next week.

graphicore commented 5 years ago

News!

@MMartinezV I added the parameters, but I also found a subtle bug that could be relevant. See #21 which I fixed and maybe have a test run to see if it is/was relevant.

The new parameters, from general to more specific, some parameters are build using other parameters if they are not set explicitly.


new parameters

blackAdjustment number, = default: 0; OR set explicitly Adjust wide and narrow black bars by adding this to the width. In units per em, can be negative.

narrowBlackAdjustment number, = blackAdjustment (default: 0); OR explicitly set Adjust only narrow black bars by adding this to the width. In units per em, can be negative.

wideBlackAdjustment number, = blackAdjustment (default: 0); OR explicitly set Adjust only wide black bars by adding this to the width. In units per em, can be negative.

whiteAdjustment number, = default: 0; OR set explicitly Adjust wide and narrow white bars by adding this to the width. In units per em, can be negative.

narrowWhiteAdjustment number, = whiteAdjustment (default: 0); OR explicitly set Adjust only narrow white bars by adding this to the width. In units per em, can be negative.

wideWhiteAdjustment number, = whitekAdjustment (default: 0); OR explicitly set Adjust only wide white bars by adding this to the width. In units per em, can be negative.

wideBlack number, = wide + wideBlackAdjustment; OR explicitly set Set the absolute width of the wide black bars. In units per em, must be positive.

wideBlack number, = wide + wideWhiteAdjustment;; OR explicitly set Set the absolute width of the wide white bars. In units per em, must be positive.

narrowBlack number, = wide + narrowBlackAdjustment; OR explicitly set Set the absolute width of the narrow black bars. In units per em, must be positive.

narrowWhite number, `= wide + narrowWhiteAdjustment; OR explicitly set Set the absolute width of the narrow white bars. In units per em, must be positive.


I decided to add all parameters, to allow for really fine grained control over the result. In your case I would try to decrease all the black bars, because the ink swell is making them wider as they should be:

{
    "blackAdjustment": -5
}

But you could also only change the width of the white bars:

{
    "whiteAdjustment": 5
}

or use both:

{
    "blackAdjustment": -5
 ,  "whiteAdjustment": 5
}

I hope you don't need the other paramaters, because it will become more complicated, but in any case, they are there and ready to be used.

When using these adjustments, I wonder if it would make sense to also "center" the glyphs in their "original" position. I did not implement that and I hope we don't need it.

And, if you need it for comparison or so, to recreate the "buggy" version/behavior that I mentioned in #21. if "narrow": 30 set "wideWhiteAdjustment": 30 as well. Code39 is really robust, considering that it did still scan. :sweat_smile:

MMartinezV commented 5 years ago

Good news!

It works :-D

After many tests, using params:

PARAMETERS_CODE39TEXT=$(cat <<EOT
{
  "narrow": 22
  , "narrowWhiteAdjustment": 10
  , "wideWhiteAdjustment": 0
  , "wideBlackAdjustment": -6
}
EOT
)

It's clear that is a printer problem, because if I change narrow 22 to 25, some narrow bars become wider after printing and therefore the code is not recognized. Anyway, we've done many tests and with these parameters it seems that works fine with the Brother QL820 printer. Thanks lots!!

Kind Regards,

Manuel Martínez

graphicore commented 5 years ago

I'm super happy to hear this! Having the possibility with this project to adopt to a special scenario like your printer hardware is a big feature! Thanks for your cooperation on this.

MMartinezV commented 5 years ago

We're very happy too!

Thanks for all your support, you've been so kind and your solution works perfect!

By the way, I've seen that you've updated the building procedure and it doesn't work on the Debian Machine I'm using to build the fonts.

I'm using the previous one: "virtualenv venv" instead of "python -m venv venv". Just for your information.

Kind Regards,

Manuel Martínez

graphicore commented 5 years ago

try python3 -m venv venv

MMartinezV commented 5 years ago

Yes, it works (after installing: python3-venv).

Kind regards,

Manuel Martínez

graphicore commented 5 years ago

Thanks.

I changed the README again. What happened to "batteries included" in python? :man_shrugging: