chiark / gitweb /
Generate PANOSE classification.
authorBen Harris <bjh21@bjh21.me.uk>
Wed, 28 Jun 2017 21:15:02 +0000 (22:15 +0100)
committerBen Harris <bjh21@bjh21.me.uk>
Wed, 28 Jun 2017 21:15:02 +0000 (22:15 +0100)
This is a mandatory part of the 'OS/2' table, so we may as well get it
right.  Gratuitously generalised across all possible character widths.

bedstead.c

index c9e445b5db19903c848c8856ed4451d816f6a68b..832a95cf82d38e9c098b227e2e2e17bf810b3738 100644 (file)
@@ -157,6 +157,7 @@ struct param *param = &default_param;
 void doprologue(void);
 void dochar(char const data[YSIZE], unsigned flags);
 static void domosaic(unsigned code, bool sep);
+static void dopanose();
 
 struct glyph {
        char data[YSIZE];
@@ -1263,6 +1264,7 @@ main(int argc, char **argv)
        printf("OS2SubYOff: %d\n", 2 * YPIX);
        printf("OS2SupYOff: %d\n", 2 * YPIX);
        printf("TTFWidth: %d\n", param->ttfwidth);
+       dopanose();
        printf("LayerCount: 2\n");
        printf("Layer: 0 0 \"Back\" 1\n");
        printf("Layer: 1 0 \"Fore\" 0\n");
@@ -1323,6 +1325,114 @@ main(int argc, char **argv)
        return 0;
 }
 
+static void
+dopanose()
+{
+       /*
+        * PANOSE is a complex font categorisation scheme.  I suspect
+        * no-one uses it, but it's a mandatory part of the 'OS/2'
+        * table, so it would be nice to get it right.  This procedure
+        * calculates the PANOSE code for a Bedstead variant based on
+        * its design parameters.
+        *
+        * See <http://panose.com> for the full details.
+        */
+       int panose[10];
+       /* Common digits */
+       /* WeightRat == 700/XPIX */
+       if (XPIX <= 20) /* WeightRat >= 35 */
+               panose[2] = 2; /* Very Light */
+       else if (XPIX < 39) /* WeightRat > 17.9 */
+               panose[2] = 3; /* Light */
+       else if (XPIX <= 70) /* WeightRat >= 10 */
+               panose[2] = 4; /* Thin */
+       else if (XPIX <= 94) /* WeightRat > 7.44 */
+               panose[2] = 5; /* Book */
+       else if (XPIX < 128) /* WeightRat > 5.5 */
+               panose[2] = 6; /* Medium */
+       else if (XPIX < 156) /* WeightRat > 4.5 */
+               panose[2] = 7; /* Demi */
+       else if (XPIX <= 200) /* WeightRat >= 3.5 */
+               panose[2] = 8; /* Bold */
+       else if (XPIX <= 280) /* WeightRat >= 2.5 */
+               panose[2] = 9; /* Heavy */
+       else if (XPIX <= 350) /* WeightRat >= 2.0 */
+               panose[2] = 10; /* Black */
+       else
+               panose[2] = 11; /* Extra Black */
+       /*
+        * To make life simpler, ignore diagonals when calculating
+        * ConRat.
+        */
+       /* ConRat == min(XPIX / 100, 100 / XPIX) */
+       if (XPIX > 80 && XPIX < 125)
+               panose[4] = 2; /* None */
+       else if (XPIX > 65 && XPIX < 154)
+               panose[4] = 3; /* Very Low */
+       else if (XPIX > 48 && XPIX < 209)
+               panose[4] = 4; /* Low */
+       else if (XPIX > 30 && XPIX < 334)
+               panose[4] = 5; /* Medium Low */
+       else if (XPIX > 20 && XPIX < 500)
+               panose[4] = 6; /* Medium */
+       else if (XPIX > 15 && XPIX < 667)
+               panose[4] = 7; /* Medium High */
+       else if (XPIX > 8 && XPIX < 1250)
+               panose[4] = 8; /* High */
+       else
+               panose[4] = 9; /* Very High */
+       /*
+        * First digit is overall style.  Bedstead is a text font, but
+        * PANOSE says that fonts with horizontal stress and extreme
+        * aspect ratios should be classified as decorative.
+        */
+       if (XPIX < 100 || /* ConRat > 1.00 */
+           XPIX > 164) { /* ORat < 0.85 */
+               panose[0] = 4; /* Latin Decorative */
+               panose[1] = 2; /* Derivative */
+               /* ORat == 140/XPIX */
+               if (XPIX <= 53)
+                       panose[3] = 2; /* Super Condensed */
+               else if (XPIX <= 66)
+                       panose[3] = 3; /* Very Condensed */
+               else if (XPIX <= 110)
+                       panose[3] = 4; /* Condensed */
+               else if (XPIX <= 152)
+                       panose[3] = 5; /* Normal */
+               else if (XPIX <= 155)
+                       panose[3] = 6; /* Extended */
+               else if (XPIX <= 164)
+                       panose[3] = 7; /* Very Extended */
+               else
+                       panose[3] = 8; /* Super Extended */
+               panose[5] = 11; /* Normal Sans Serif */
+               panose[6] = 2; /* Standard Solid Fill */
+               panose[7] = 2; /* No Lining */
+               panose[8] = 3; /* Square */
+               panose[9] = 2; /* Extended Collection */
+       } else {
+               panose[0] = 2; /* Latin Text */
+               panose[1] = 11; /* Normal Sans Serif */
+               /* J and M are the same width. */
+               panose[3] = 9; /* Monospaced */
+               if (panose[4] == 2)
+                       panose[5] = 2; /* No Variation */
+               else if (XPIX > 100)
+                       panose[5] = 5; /* Gradual/Vertical */
+               else
+                       panose[5] = 6; /* Gradual/Hoizontal */
+               /* Unusually shaped 'A' means no fit here. */
+               panose[6] = 1; /* No Fit */
+               /* OutCurv == 0.791 */
+               panose[7] = 5; /* Normal/Boxed */
+               panose[8] = 3; /* Standard/Pointed */
+               panose[9] = 7; /* Ducking/Large */
+       }
+       printf("Panose: %d %d %d %d %d %d %d %d %d %d\n",
+              panose[0], panose[1], panose[2], panose[3], panose[4], 
+              panose[5], panose[6], panose[7], panose[8], panose[9]);
+}
+
 static void
 dopalt(struct glyph const *g)
 {