Hello community, here is the log from the commit of package hxtools for openSUSE:Factory checked in at 2020-03-31 17:15:45 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/hxtools (Old) and /work/SRC/openSUSE:Factory/.hxtools.new.3160 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "hxtools" Tue Mar 31 17:15:45 2020 rev:38 rq:789916 version:20200331 Changes: -------- --- /work/SRC/openSUSE:Factory/hxtools/hxtools.changes 2020-03-18 12:43:22.408878058 +0100 +++ /work/SRC/openSUSE:Factory/.hxtools.new.3160/hxtools.changes 2020-03-31 17:16:00.531656694 +0200 @@ -1,0 +2,8 @@ +Mon Mar 30 23:28:58 UTC 2020 - Jan Engelhardt <[email protected]> + +- Update to release 20200331 + * vfontas: add "N2" vectorizer + * vfontas: new -saven2 command to use N2 + * vfontas: moved N1 to historic status + +------------------------------------------------------------------- @@ -5 +13 @@ - * vfontas: add new N1 vectorizer + * vfontas: add "N1" vectorizer Old: ---- hxtools-20200310.tar.asc hxtools-20200310.tar.xz New: ---- hxtools-20200331.tar.asc hxtools-20200331.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ hxtools.spec ++++++ --- /var/tmp/diff_new_pack.qKeCqE/_old 2020-03-31 17:16:01.839657525 +0200 +++ /var/tmp/diff_new_pack.qKeCqE/_new 2020-03-31 17:16:01.839657525 +0200 @@ -17,7 +17,7 @@ Name: hxtools -Version: 20200310 +Version: 20200331 Release: 0 Summary: Collection of day-to-day tools (binaries) License: GPL-2.0+ and WTFPL @@ -160,7 +160,9 @@ %description -n vfontas vfontas (originally "VGA font file assembler") can transform raster font files in various ways - scaling, moving, row-filling, convert -between formats (bdf/clt/pbm/psf/raw) and vector export to sfd/ttf. +between formats (bdf/clt/pbm/psf/raw DOS font) and vector export to +sfd (and then TrueType/OpenType/WOFF/etc. via FontForge). The vector +export is able to smoothen the jagged edges of bitmap fonts. %prep %setup -q ++++++ hxtools-20200310.tar.xz -> hxtools-20200331.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hxtools-20200310/configure new/hxtools-20200331/configure --- old/hxtools-20200310/configure 2020-03-10 10:30:35.462411142 +0100 +++ new/hxtools-20200331/configure 2020-03-31 01:26:20.475923272 +0200 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for hxtools 20200310. +# Generated by GNU Autoconf 2.69 for hxtools 20200331. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -577,8 +577,8 @@ # Identity of this package. PACKAGE_NAME='hxtools' PACKAGE_TARNAME='hxtools' -PACKAGE_VERSION='20200310' -PACKAGE_STRING='hxtools 20200310' +PACKAGE_VERSION='20200331' +PACKAGE_STRING='hxtools 20200331' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1301,7 +1301,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures hxtools 20200310 to adapt to many kinds of systems. +\`configure' configures hxtools 20200331 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1367,7 +1367,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of hxtools 20200310:";; + short | recursive ) echo "Configuration of hxtools 20200331:";; esac cat <<\_ACEOF @@ -1486,7 +1486,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -hxtools configure 20200310 +hxtools configure 20200331 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1946,7 +1946,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by hxtools $as_me 20200310, which was +It was created by hxtools $as_me 20200331, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2811,7 +2811,7 @@ # Define the identity of the package. PACKAGE='hxtools' - VERSION='20200310' + VERSION='20200331' cat >>confdefs.h <<_ACEOF @@ -5897,7 +5897,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by hxtools $as_me 20200310, which was +This file was extended by hxtools $as_me 20200331, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -5963,7 +5963,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -hxtools config.status 20200310 +hxtools config.status 20200331 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hxtools-20200310/configure.ac new/hxtools-20200331/configure.ac --- old/hxtools-20200310/configure.ac 2020-03-10 10:29:07.000000000 +0100 +++ new/hxtools-20200331/configure.ac 2020-03-31 01:25:27.000000000 +0200 @@ -1,4 +1,4 @@ -AC_INIT([hxtools], [20200310]) +AC_INIT([hxtools], [20200331]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_HEADERS([config.h]) AC_PROG_INSTALL diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hxtools-20200310/doc/NEWS.txt new/hxtools-20200331/doc/NEWS.txt --- old/hxtools-20200310/doc/NEWS.txt 2020-03-10 10:29:07.000000000 +0100 +++ new/hxtools-20200331/doc/NEWS.txt 2020-03-31 01:25:27.000000000 +0200 @@ -1,12 +1,39 @@ +rel-20200331 +============ +* vfontas: add new N2 vectorizer +* vfontas: new -saven2 command to use N2 + +The N2 vectorizer is able to recognize logical 45-degree angles in +bitmap glyphs and will output the outlines as such. Unlike N1, +it analyzes glyph outlines rather than pixel patterns, and produces +higher quality output due to a larger working radius. + +N2 can reproduce the "Nouveau IBM" font quite closely now (e.g. from +Fontraption's VGA9.F16 file). A few differences have just become apparent (one +can inspect in e.g. Inkscape by overlaying both fontfaces) that may be +addressed in a later release. + +N2: +* Serifs are subject to diagonalization (but maybe should become exempt). +* Isthmuses tend to get washed out, noticable in glyphs like 'G'. +* Sumps in the 'K', 'M', 'N' glyphs could be improved. + This is noticable in glyphs like 'G'. + +Nouveau IBM: +* Kerning is not original: too closely spaced. +* Node points are not at pixel or half-pixel locations. + 'B' has a 30.78 diagonal for no apparent reason. This is bad for integral + scaling. Other values can be observed in 'W'. +* Glyph 'C' is asymmetric. + + rel-20200309 ============ -* vfontas: add new N1 vectorizer +* vfontas: add N1 vectorizer * vfontas: new -saven1 command to use N1 * vfontas: remove -xbrz -The N1 vectorizer is able to recognize logical 45-degree angles in -bitmap glyphs and will output the outlines as such. rel-20200124 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hxtools-20200310/doc/vfontas.1 new/hxtools-20200331/doc/vfontas.1 --- old/hxtools-20200310/doc/vfontas.1 2020-03-10 10:29:07.000000000 +0100 +++ new/hxtools-20200331/doc/vfontas.1 2020-03-31 01:25:27.000000000 +0200 @@ -41,6 +41,8 @@ .PP \fB\-saven1\fP \fInew.sfd\fP .PP +\fB\-saven2\fP \fInew.sfd\fP +.PP \fB\-savepbm\fP \fIoutdir/\fP .PP \fB\-savepsf\fP \fInew.psfu\fP @@ -129,41 +131,48 @@ Saves the current in-memory Unicode mapping table to the given file. .SS saven1 .PP +N1 was an experiment to try and model the "diagonalization idea" (cf. \-saven2) +by analyzing the original glyph \fIbitmap\fP. Its defining characteristic is a +lookaround window of 3x3 pixels, whose contents are mapped to a set of +triangles. N1 has some drawbacks over the newer N2: +.IP \(bu 4 +N1 adds diagonals on single-pixel protrusions (e.g. the left end of the +horizontal bar in an 'f' in certain fonts). This is definitely not fixable with +a 3x3 window and would require using 5x5. +.IP \(bu 4 +N1 adds triangles between pixels that do not necessarily belong together, such +as in spirals like U+0040 or jampacked glyphs like U+20A7. N2 operates on edges +and knows their direction, and avoids making connections to "pixel islands" at +certain angles. +.SS saven2 +.PP Similar to \fB\-savesfd\fP, this produces an SFD file, but uses an alternate -vectorizer (aptly named "N1"), which smoothens the jagged edges of a bitmap +vectorizer (aptly named "N2"), which smoothens the jagged edges of a bitmap font. .PP -The N1 vectorizer is able to recognize logical 45-degree angles in bitmap -glyphs. Each 90 degree corner followed by a 270 degree corner is replaced by a -diagonal segment. This diagonalization was originally employed by Arto Hatanpää -(possibly in a long session of manual work) for the "Nouveau IBM" and "Nouveau -IBM Stretch" vector font versions of the IBM VGA 9x16 ROM font. -.PP -In a twist, N1 does not look at the angles of the corners of the glyph -outlines, but rather inspects source pixel patterns in a 3x3 window and emits -triangles accordingly that implement the replacement rule. +The N2 vectorizer is able to recognize the "stair" pattern of pixels and +transform these sections to 45-degree angles. This diagonalization was +originally employed by Arto Hatanpää (possibly in a long session of manual +work) for the "Nouveau IBM" and "Nouveau IBM Stretch" vector font versions of +the IBM VGA 9x16 ROM font. +.PP +The defining characteristic of N2 is that it analyzes glyph edges (similar to +those produced by \-savesfd) using a lookaround window of 7 edge segments, +which is used to work on areas of effectively 5x5 pixels. When a 90/270 corner +is found, it will be transformed by adding diagonal edges. .PP In comparison to other scalers, .IP \(bu 4 -xBRZ erroneously round the ends of strokes (e.g. the '-' dash). -.IP \(bu 4 -N1 adds diagonals on single-pixel protrusions (e.g. the left end of the -horizontal bar in an 'f'). This is definitely not fixable with a 3x3 window, -and is probably not solvable for the general case either. -.IP \(bu 4 -N1 adds links between pixels that do not necessarily belong there (such as in -spirals like U+0040 or jampacked glyphs like U+20A7). This is probably not -fixable for the general case without making the vectorizer aware of expected -shapes. +xBRZ erroneously round the ends of strokes (e.g. the '-' dash), N1/N2 does not. .IP \(bu 4 While xBRZ is a bitmap-to-bitmap procedure (also limited to 6x magnification -as of writing), N1 converts to vector. +as of writing), N1/N2 converts to vector. .IP \(bu 4 Autotrace/Potrace just is not targeted for low resolution sources (as 8x16 bitmap fonts are). Either it will convert the bitmap 1:1 with jagged edges, or turn it into three or so beziers, which is not nearly enough for '&'. .IP \(bu 4 -N1 is only specified for monochrome input. +N1/N2 is only specified for monochrome input. .SS savepsf .PP Saves the current in-memory glyphs as a PC Screen Font PSF2.0 file, which can diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hxtools-20200310/smm/vfalib.cpp new/hxtools-20200331/smm/vfalib.cpp --- old/hxtools-20200310/smm/vfalib.cpp 2020-03-10 10:29:07.000000000 +0100 +++ new/hxtools-20200331/smm/vfalib.cpp 2020-03-31 01:25:27.000000000 +0200 @@ -68,14 +68,16 @@ public: std::vector<std::vector<edge>> simple(const glyph &, int descent = 0); std::vector<std::vector<edge>> n1(const glyph &, int descent = 0); + std::vector<std::vector<edge>> n2(const glyph &, int descent = 0); static constexpr const unsigned int scale_factor = 2; private: void finalize(); - std::vector<edge> pop_poly(); + std::vector<edge> pop_poly(unsigned int flags); void set(int, int); std::set<edge> emap; + static const unsigned int P_SIMPLIFY_LINES = 1 << 0; }; static const char vfhex[] = "0123456789abcdef"; @@ -757,7 +759,7 @@ } } -std::vector<edge> vectorizer::pop_poly() +std::vector<edge> vectorizer::pop_poly(unsigned int flags) { std::vector<edge> poly; if (emap.size() == 0) @@ -815,7 +817,7 @@ * polygon has a vertex in the same location.) */ auto next_dir = next->trivial_dir(); - if (next_dir == prev_dir) + if ((flags & P_SIMPLIFY_LINES) && next_dir == prev_dir) tail_vtx = next->end_vtx; else poly.push_back(*next); @@ -839,7 +841,7 @@ finalize(); std::vector<std::vector<edge>> pmap; while (true) { - auto poly = pop_poly(); + auto poly = pop_poly(P_SIMPLIFY_LINES); if (poly.size() == 0) break; pmap.push_back(std::move(poly)); @@ -918,7 +920,7 @@ finalize(); std::vector<std::vector<edge>> pmap; while (true) { - auto poly = pop_poly(); + auto poly = pop_poly(P_SIMPLIFY_LINES); if (poly.size() == 0) break; pmap.push_back(std::move(poly)); @@ -926,6 +928,160 @@ return pmap; } +static void n2_angle(std::vector<edge> &poly) +{ + static const unsigned int M_HEAD = 0x20, M_TAIL = 0x02; + std::vector<unsigned int> flags(poly.size()); + + for (size_t xm3 = 0; xm3 < poly.size(); ++xm3) { + auto xm2 = (xm3 + 1) % poly.size(); + auto xm1 = (xm3 + 2) % poly.size(); + auto x00 = (xm3 + 3) % poly.size(); + auto xp1 = (xm3 + 4) % poly.size(); + auto xp2 = (xm3 + 5) % poly.size(); + auto xp3 = (xm3 + 6) % poly.size(); + auto dm3 = poly[xm3].trivial_dir(), dm2 = poly[xm2].trivial_dir(); + auto dm1 = poly[xm1].trivial_dir(), d00 = poly[x00].trivial_dir(); + auto dp1 = poly[xp1].trivial_dir(), dp2 = poly[xp2].trivial_dir(); + auto dp3 = poly[xp3].trivial_dir(); + +#if 0 + printf("I%zu dm3:\e[32m%d\e[0m,dm2:\e[32m%d\e[0m," + "dm1:\e[32m%d\e[0m,d:\e[32m%d\e[0m,dp1:\e[32m%d\e[0m," + "dp2:\e[32m%d\e[0m,dp3:\e[32m%d\e[0m\n", + x00, dm3, dm2, dm1, d00, dp1, dp2, dp3); +#endif + + if (d00 == dm2 && d00 == dp2) { + /* _|~|_ or ~|_|~ pattern seen */ + if ((dm3 == d00 || dm3 == dp1) && + (dp3 == d00 || dp3 == dm1) && + dm1 == (dm2 + 270) % 360 && dp1 == (dm2 + 90) % 360) + /* pimple __|~|__ ('f', '4'), retain */ + continue; + + if (dm1 == (dm2 + 90) % 360 && dp1 == (dm2 + 270) % 360) { + /* dimple ~~|_|~~ ('8'), sink it */ + if (dm3 == dm2) { + /* with left-side flat zone */ + flags[xm2] |= M_TAIL; + flags[xm1] = M_HEAD | M_TAIL; + flags[x00] |= M_HEAD; + } + if (dp3 == dp2) { + /* with right-side flat zone */ + flags[x00] |= M_TAIL; + flags[xp1] = M_HEAD | M_TAIL; + flags[xp2] |= M_HEAD; + } + continue; + } + } + + /* Test for chicane */ + if (dm1 != dp1) + continue; + if ((d00 + 270) % 360 != dp1 && (d00 + 90) % 360 != dp1) + continue; + + /* + * #1: single step, with or without sump, + * #2: bottom of stairs, with or without sump, + * #3: stairs midpart, + * #4: top of stairs (implies no sump) + */ + flags[xm1] |= M_TAIL; + flags[x00] = M_HEAD | M_TAIL; + flags[xp1] |= M_HEAD; + + if (dp2 == d00) { + flags[xp1] |= M_TAIL; + flags[xp2] |= M_HEAD; + } + if (dm2 == d00) { + flags[xm2] |= M_TAIL; + flags[xm1] |= M_HEAD; + } + } + + auto p_iter = poly.begin(); + auto f_iter = flags.begin(); + for (size_t ia = 0; ia < poly.size(); ++ia, ++p_iter, ++f_iter) { + auto ix = ia + 1; + auto ib = ix % poly.size(); + if (!(flags[ia] & M_TAIL && flags[ib] & M_HEAD)) + continue; + + flags[ia] &= ~M_TAIL; + flags[ib] &= ~M_HEAD; + p_iter = poly.insert(std::next(p_iter), edge{{-64, -64}, {-64, -64}}); + f_iter = flags.insert(std::next(f_iter), 0); + ib = (ia + 2) % poly.size(); + + auto da = poly[ia].trivial_dir(), db = poly[ib].trivial_dir(); + if (da == 0) + --poly[ia].end_vtx.y; + else if (da == 90) + --poly[ia].end_vtx.x; + else if (da == 180) + ++poly[ia].end_vtx.y; + else if (da == 270) + ++poly[ia].end_vtx.x; + if (db == 0) + ++poly[ib].start_vtx.y; + else if (db == 90) + ++poly[ib].start_vtx.x; + else if (db == 180) + --poly[ib].start_vtx.y; + else if (db == 270) + --poly[ib].start_vtx.x; + poly[ix].start_vtx = poly[ia].end_vtx; + poly[ix].end_vtx = poly[ib].start_vtx; + ++ia; + } + poly.erase(std::remove_if(poly.begin(), poly.end(), [](const edge &e) { + return e.start_vtx == e.end_vtx; + }), poly.end()); + + p_iter = poly.begin(); + while (p_iter != poly.cend()) { + auto next = std::next(p_iter); + if (next == poly.end()) + break; + auto d1 = p_iter->trivial_dir(), d2 = next->trivial_dir(); + if (d1 != d2) { + ++p_iter; + continue; + } + p_iter->end_vtx = next->end_vtx; + poly.erase(next); + } +} + +std::vector<std::vector<edge>> vectorizer::n2(const glyph &g, int desc) +{ + const auto &sz = g.m_size; + for (unsigned int y = 0; y < sz.h; ++y) { + int yy = sz.h - 1 - static_cast<int>(y) - desc; + for (unsigned int x = 0; x < sz.w; ++x) { + bitpos ipos = y * sz.w + x; + if (g.m_data[ipos.byte] & ipos.mask) + set(x, yy); + } + } + finalize(); + std::vector<std::vector<edge>> pmap; + while (true) { + /* Have all edges retian length 1 */ + auto poly = pop_poly(0); + if (poly.size() == 0) + break; + n2_angle(poly); + pmap.push_back(std::move(poly)); + } + return pmap; +} + void font::save_sfd_glyph(FILE *fp, size_t idx, char32_t cp, int asc, int desc, enum vectoalg vt) { @@ -944,6 +1100,8 @@ pmap = vectorizer().simple(m_glyph[idx], desc); else if (vt == V_N1) pmap = vectorizer().n1(m_glyph[idx], desc); + else if (vt == V_N2) + pmap = vectorizer().n2(m_glyph[idx], desc); for (const auto &poly : pmap) { const auto &v1 = poly.cbegin()->start_vtx; fprintf(fp, "%d %d m 25\n", v1.x, v1.y); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hxtools-20200310/smm/vfalib.hpp new/hxtools-20200331/smm/vfalib.hpp --- old/hxtools-20200310/smm/vfalib.hpp 2020-03-10 10:29:07.000000000 +0100 +++ new/hxtools-20200331/smm/vfalib.hpp 2020-03-31 01:25:27.000000000 +0200 @@ -80,6 +80,7 @@ enum vectoalg { V_SIMPLE = 0, V_N1, + V_N2, }; class glyph { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hxtools-20200310/smm/vfontas.cpp new/hxtools-20200331/smm/vfontas.cpp --- old/hxtools-20200310/smm/vfontas.cpp 2020-03-10 10:29:07.000000000 +0100 +++ new/hxtools-20200331/smm/vfontas.cpp 2020-03-31 01:25:27.000000000 +0200 @@ -258,6 +258,15 @@ return false; } +static bool vf_saven2(font &f, char **args) +{ + auto ret = f.save_sfd(args[0], vectoalg::V_N2); + if (ret >= 0) + return true; + fprintf(stderr, "Error saving %s: %s\n", args[0], strerror(-ret)); + return false; +} + static bool vf_setname(font &f, char **args) { f.name = args[0]; @@ -416,6 +425,7 @@ {"savefnt", 1, vf_savefnt}, {"savemap", 1, vf_savemap}, {"saven1", 1, vf_saven1}, + {"saven2", 1, vf_saven2}, {"savepbm", 1, vf_savepbm}, {"savepsf", 1, vf_savepsf}, {"savesfd", 1, vf_savesfd},
