ref: bdc09059c1801bb7d6271b85b09040556a271de7
parent: 1d352256dfd09685a98184574d2fb7e046589ec8
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Mon Jul 15 17:39:26 EDT 2024
component glyph scaling; proper baseline; guide lines drawing; combine some of the test functionality
--- a/gen.rkt
+++ b/gen.rkt
@@ -605,8 +605,9 @@
(out (at out-dir "otf.c")
(λ ()
- (printf (string-replace (port->string (open-input-file (at in-dir "otf.c.in")) #:close? #t)
+ (printf "~a"
+ (string-replace (port->string (open-input-file (at in-dir "otf.c.in")) #:close? #t)
"OTF_EXTRA_FIELDS\n"
(format extra-context-fields #:on-all remove-duplicates)))
(printf "\n")
- (printf (format (λ (c) (gen-c c #f #f))))))
+ (printf "~a" (format (λ (c) (gen-c c #f #f))))))
--- a/mkfile
+++ b/mkfile
@@ -22,7 +22,7 @@
otfsys.$O: plan9/otf.c
$CC $CFLAGS plan9/otfsys.c
-test.$O: plan9/test.c
+test.$O: plan9/test.c test.h
$CC $CFLAGS plan9/test.c
plan9/otf.h plan9/otf.c: gen.rkt otf.rkt otf.h.in otf.c.in
--- a/otf.c.in
+++ b/otf.c.in
@@ -257,6 +257,8 @@
enum {
CGLYPH_FL_WORD_ARGS = 1<<0,
+ CGLYPH_FL_SCALE = 1<<3,
+ CGLYPH_FL_UNSCALED_COMPONENT_OFFSET = 1<<12,
};
static int
@@ -277,6 +279,8 @@
v->flags = b[0]<<8 | b[1];
v->glyphIndex = b[2]<<8 | b[3];
instr |= v->flags & CGLYPH_FL_INSTRUCTIONS;
+ if(v->flags & CGLYPH_FL_UNSCALED_COMPONENT_OFFSET)
+ v->flags &= ~(CGLYPH_FL_UNSCALED_COMPONENT_OFFSET | CGLYPH_FL_SCALED_COMPONENT_OFFSET);
if((v->flags & CGLYPH_FL_WORD_ARGS) != 0 && (b = otfreadn(o, 2*2)) != nil){
if(v->flags & CGLYPH_FL_SIGNED_XY){
@@ -298,8 +302,13 @@
if(b == nil)
goto err;
#define f2dot14(o) (f = b[2*o]<<8 | b[2*o+1], (f>>14)+(f&((1<<14)-1))/16384.0)
+ v->scaleX = 1.0;
+ v->scaleY = 1.0;
if((v->flags & CGLYPH_FL_SCALE) != 0 && (b = otfreadn(o, 2)) != nil){
- v->scale = f2dot14(0);
+ v->scaleX = f2dot14(0);
+ v->scaleY = v->scaleX;
+ v->flags &= ~CGLYPH_FL_SCALE;
+ v->flags |= CGLYPH_FL_SCALE_XY;
}else if((v->flags & CGLYPH_FL_SCALE_XY) != 0 && (b = otfreadn(o, 2*2)) != nil){
v->scaleX = f2dot14(0);
v->scaleY = f2dot14(1);
@@ -340,7 +349,7 @@
print_ComponentGlyph(Otfile *f, int indent, Otf *o, ComponentGlyph *v)
{
void *a = f->aux;
- f->print(a, "%*s%s: %#"PRIx16"%s%s%s%s%s%s%s%s%s%s%s\n", indent, "", "flags", v->flags,
+ f->print(a, "%*s%s: %#"PRIx16"%s%s%s%s%s%s%s%s%s%s\n", indent, "", "flags", v->flags,
(v->flags&CGLYPH_FL_SIGNED_XY)?" CGLYPH_FL_SIGNED_XY":"",
(v->flags&CGLYPH_FL_ROUND_TO_GRID_XY)?" CGLYPH_FL_ROUND_TO_GRID_XY":"",
(v->flags&CGLYPH_FL_SCALE)?" CGLYPH_FL_SCALE":"",
@@ -350,8 +359,7 @@
(v->flags&CGLYPH_FL_INSTRUCTIONS)?" CGLYPH_FL_INSTRUCTIONS":"",
(v->flags&CGLYPH_FL_METRICS)?" CGLYPH_FL_METRICS":"",
(v->flags&CGLYPH_FL_OVERLAP_COMPOUND)?" CGLYPH_FL_OVERLAP_COMPOUND":"",
- (v->flags&CGLYPH_FL_SCALED_COMPONENT_OFFSET)?" CGLYPH_FL_SCALED_COMPONENT_OFFSET":"",
- (v->flags&CGLYPH_FL_UNSCALED_COMPONENT_OFFSET)?" CGLYPH_FL_UNSCALED_COMPONENT_OFFSET":""
+ (v->flags&CGLYPH_FL_SCALED_COMPONENT_OFFSET)?" CGLYPH_FL_SCALED_COMPONENT_OFFSET":""
);
f->print(a, "%*s%s: %"PRIu16"\n", indent, "", "glyphIndex", v->glyphIndex);
if(v->arg1 != 0 || v->arg2 != 0){
@@ -358,9 +366,7 @@
f->print(f->aux, "%*s%s: %d\n", indent, "", "arg1", v->arg1);
f->print(f->aux, "%*s%s: %d\n", indent, "", "arg2", v->arg2);
}
- if(v->flags & CGLYPH_FL_SCALE){
- f->print(a, "%*s%s: %g\n", indent, "", "scale", v->scale);
- }else if(v->flags & CGLYPH_FL_SCALE_XY){
+ if(v->flags & CGLYPH_FL_SCALE_XY){
f->print(a, "%*s%s: %g\n", indent, "", "scaleX", v->scaleX);
f->print(a, "%*s%s: %g\n", indent, "", "scaleY", v->scaleY);
}else if(v->flags & CGLYPH_FL_2X2_TRANSFORM){
--- a/otf.h.in
+++ b/otf.h.in
@@ -21,6 +21,7 @@
void *aux;
int (*seek)(void *aux, int off, int whence);
int (*read)(void *aux, void *dst, int sz);
+ int (*write)(void *aux, const void *src, int sz);
int (*print)(void *aux, const char *fmt, ...);
};
@@ -29,7 +30,6 @@
enum {
CGLYPH_FL_SIGNED_XY = 1<<1,
CGLYPH_FL_ROUND_TO_GRID_XY = 1<<2,
- CGLYPH_FL_SCALE = 1<<3,
CGLYPH_FL_MORE_COMPONENTS = 1<<5,
CGLYPH_FL_SCALE_XY = 1<<6,
CGLYPH_FL_2X2_TRANSFORM = 1<<7,
@@ -37,7 +37,6 @@
CGLYPH_FL_METRICS = 1<<9,
CGLYPH_FL_OVERLAP_COMPOUND = 1<<10,
CGLYPH_FL_SCALED_COMPONENT_OFFSET = 1<<11,
- CGLYPH_FL_UNSCALED_COMPONENT_OFFSET = 1<<12,
};
struct ComponentGlyph {
@@ -51,7 +50,7 @@
int arg2;
int dy;
};
- float scale, scaleX, scale01, scale10, scaleY;
+ float scaleX, scale01, scale10, scaleY;
u16int numInstr;
u8int *instr;
ComponentGlyph *next;
@@ -97,5 +96,5 @@
typedef struct Glyf Glyf;
Glyf *otfglyf(Otf *o, int index);
int otfglyfnum(Otf *o);
-int otfdrawglyf(Otf *o, Glyf *g, int ppem, GlyfImage *im);
+int otfdrawglyf(Otf *o, Glyf *g, int ppem, int gap, GlyfImage *im);
int otfupem(Otf *o);
--- a/plan9/otf.c
+++ b/plan9/otf.c
@@ -271,6 +271,8 @@
enum {
CGLYPH_FL_WORD_ARGS = 1<<0,
+ CGLYPH_FL_SCALE = 1<<3,
+ CGLYPH_FL_UNSCALED_COMPONENT_OFFSET = 1<<12,
};
static int
@@ -291,6 +293,8 @@
v->flags = b[0]<<8 | b[1];
v->glyphIndex = b[2]<<8 | b[3];
instr |= v->flags & CGLYPH_FL_INSTRUCTIONS;
+ if(v->flags & CGLYPH_FL_UNSCALED_COMPONENT_OFFSET)
+ v->flags &= ~(CGLYPH_FL_UNSCALED_COMPONENT_OFFSET | CGLYPH_FL_SCALED_COMPONENT_OFFSET);
if((v->flags & CGLYPH_FL_WORD_ARGS) != 0 && (b = otfreadn(o, 2*2)) != nil){
if(v->flags & CGLYPH_FL_SIGNED_XY){
@@ -312,8 +316,13 @@
if(b == nil)
goto err;
#define f2dot14(o) (f = b[2*o]<<8 | b[2*o+1], (f>>14)+(f&((1<<14)-1))/16384.0)
+ v->scaleX = 1.0;
+ v->scaleY = 1.0;
if((v->flags & CGLYPH_FL_SCALE) != 0 && (b = otfreadn(o, 2)) != nil){
- v->scale = f2dot14(0);
+ v->scaleX = f2dot14(0);
+ v->scaleY = v->scaleX;
+ v->flags &= ~CGLYPH_FL_SCALE;
+ v->flags |= CGLYPH_FL_SCALE_XY;
}else if((v->flags & CGLYPH_FL_SCALE_XY) != 0 && (b = otfreadn(o, 2*2)) != nil){
v->scaleX = f2dot14(0);
v->scaleY = f2dot14(1);
@@ -354,7 +363,7 @@
print_ComponentGlyph(Otfile *f, int indent, Otf *o, ComponentGlyph *v)
{
void *a = f->aux;
- f->print(a, "%*s%s: %#"PRIx16"%s%s%s%s%s%s%s%s%s%s%s\n", indent, "", "flags", v->flags,
+ f->print(a, "%*s%s: %#"PRIx16"%s%s%s%s%s%s%s%s%s%s\n", indent, "", "flags", v->flags,
(v->flags&CGLYPH_FL_SIGNED_XY)?" CGLYPH_FL_SIGNED_XY":"",
(v->flags&CGLYPH_FL_ROUND_TO_GRID_XY)?" CGLYPH_FL_ROUND_TO_GRID_XY":"",
(v->flags&CGLYPH_FL_SCALE)?" CGLYPH_FL_SCALE":"",
@@ -364,8 +373,7 @@
(v->flags&CGLYPH_FL_INSTRUCTIONS)?" CGLYPH_FL_INSTRUCTIONS":"",
(v->flags&CGLYPH_FL_METRICS)?" CGLYPH_FL_METRICS":"",
(v->flags&CGLYPH_FL_OVERLAP_COMPOUND)?" CGLYPH_FL_OVERLAP_COMPOUND":"",
- (v->flags&CGLYPH_FL_SCALED_COMPONENT_OFFSET)?" CGLYPH_FL_SCALED_COMPONENT_OFFSET":"",
- (v->flags&CGLYPH_FL_UNSCALED_COMPONENT_OFFSET)?" CGLYPH_FL_UNSCALED_COMPONENT_OFFSET":""
+ (v->flags&CGLYPH_FL_SCALED_COMPONENT_OFFSET)?" CGLYPH_FL_SCALED_COMPONENT_OFFSET":""
);
f->print(a, "%*s%s: %"PRIu16"\n", indent, "", "glyphIndex", v->glyphIndex);
if(v->arg1 != 0 || v->arg2 != 0){
@@ -372,9 +380,7 @@
f->print(f->aux, "%*s%s: %d\n", indent, "", "arg1", v->arg1);
f->print(f->aux, "%*s%s: %d\n", indent, "", "arg2", v->arg2);
}
- if(v->flags & CGLYPH_FL_SCALE){
- f->print(a, "%*s%s: %g\n", indent, "", "scale", v->scale);
- }else if(v->flags & CGLYPH_FL_SCALE_XY){
+ if(v->flags & CGLYPH_FL_SCALE_XY){
f->print(a, "%*s%s: %g\n", indent, "", "scaleX", v->scaleX);
f->print(a, "%*s%s: %g\n", indent, "", "scaleY", v->scaleY);
}else if(v->flags & CGLYPH_FL_2X2_TRANSFORM){
--- a/plan9/otf.h
+++ b/plan9/otf.h
@@ -21,6 +21,7 @@
void *aux;
int (*seek)(void *aux, int off, int whence);
int (*read)(void *aux, void *dst, int sz);
+ int (*write)(void *aux, const void *src, int sz);
int (*print)(void *aux, const char *fmt, ...);
};
@@ -29,7 +30,6 @@
enum {
CGLYPH_FL_SIGNED_XY = 1<<1,
CGLYPH_FL_ROUND_TO_GRID_XY = 1<<2,
- CGLYPH_FL_SCALE = 1<<3,
CGLYPH_FL_MORE_COMPONENTS = 1<<5,
CGLYPH_FL_SCALE_XY = 1<<6,
CGLYPH_FL_2X2_TRANSFORM = 1<<7,
@@ -37,7 +37,6 @@
CGLYPH_FL_METRICS = 1<<9,
CGLYPH_FL_OVERLAP_COMPOUND = 1<<10,
CGLYPH_FL_SCALED_COMPONENT_OFFSET = 1<<11,
- CGLYPH_FL_UNSCALED_COMPONENT_OFFSET = 1<<12,
};
struct ComponentGlyph {
@@ -51,7 +50,7 @@
int arg2;
int dy;
};
- float scale, scaleX, scale01, scale10, scaleY;
+ float scaleX, scale01, scale10, scaleY;
u16int numInstr;
u8int *instr;
ComponentGlyph *next;
@@ -97,7 +96,7 @@
typedef struct Glyf Glyf;
Glyf *otfglyf(Otf *o, int index);
int otfglyfnum(Otf *o);
-int otfdrawglyf(Otf *o, Glyf *g, int ppem, GlyfImage *im);
+int otfdrawglyf(Otf *o, Glyf *g, int ppem, int gap, GlyfImage *im);
int otfupem(Otf *o);
typedef struct SubHeader SubHeader;
--- a/plan9/test.c
+++ b/plan9/test.c
@@ -2,48 +2,8 @@
#include <libc.h>
#include <bio.h>
#include "otf.h"
+#include "test.h"
-static void
-dumpmap(Biobuf *out, GlyfImage *im, int n)
-{
-#define gap 1
- int total, mid, npix, bw, bh, x, y, i, maxh, d;
- u8int *b;
-
- total = 0;
- maxh = 0;
- for(i = 0; i < n; i++){
- if(maxh < im[i].h)
- maxh = im[i].h;
- total += im[i].w;
- }
- mid = total / n;
- npix = (mid+gap)*(maxh+gap)*n;
- bh = sqrt(npix);
- bw = npix/bh;
- bh *= 1.5;
- npix *= 1.5;
- npix += bw*gap;
- if((b = malloc(npix)) == nil)
- sysfatal("no memory");
- memset(b, 0xff, npix);
- x = y = gap;
- for(i = 0; i < n; i++){
- if((bw-x) < im[i].w+gap){
- y += maxh + gap;
- x = gap;
- }
- if((bh-y) < maxh+gap)
- continue;
- for(d = 0; d < im[i].h; d++)
- memcpy(b + (maxh - im[i].h + y + im[i].baseline + d)*bw + x, im[i].b + d*im[i].w, im[i].w);
- x += im[i].w + gap;
- }
- Bprint(out, "%11s %11d %11d %11d %11d ", "k8", 0, 0, bw, y+maxh*2+gap);
- Bwrite(out, b, bw*(y+maxh*2+gap));
- free(b);
-}
-
static int
otfseek(void *aux, int off, int whence)
{
@@ -56,13 +16,16 @@
return Bread(aux, dst, sz);
}
+static int
+otfwrite(void *aux, void *dst, int sz)
+{
+ return Bwrite(aux, dst, sz);
+}
+
static void
-usage(void)
+usage(Otfile *f)
{
- fprint(2, "usage: %s [-g GLYPH_ID] [-G] [-i N] [-p PPM] font.otf ...\n", argv0);
- fprint(2, " -g: specifies a single glyph id\n");
- fprint(2, " -G: print out glyph ids, only ones that can be drawn atm (no compound yet)\n");
- fprint(2, " -p: draw (of size in pixels per em) and write the image to stdout\n");
+ printusage(f);
exits("usage");
}
@@ -69,32 +32,17 @@
void
main(int argc, char **argv)
{
- int i, gi, G, ppem;
+ int i;
Otfile in, out;
Otf *o;
- gi = -1;
- G = 0;
- ppem = 0;
- ARGBEGIN{
- case 'g':
- gi = strtol(EARGF(usage()), nil, 0);
- break;
- case 'G':
- G++;
- break;
- case 'p':
- ppem = strtol(EARGF(usage()), nil, 0);
- break;
- default:
- usage();
- }ARGEND
-
in.seek = otfseek;
in.read = otfread;
out.print = (void*)Bprint;
-
+ out.write = otfwrite;
out.aux = Bfdopen(1, OWRITE);
+ parseoptions();
+
for(i = 0; i < argc; i++){
if((in.aux = Bopen(argv[i], OREAD)) == nil || (o = otfopen(&in)) == nil){
fprint(2, "%r\n");
@@ -102,7 +50,7 @@
}
if(ppem <= 0)
Bprint(out.aux, "%s\n", argv[i]);
- if(G && gi < 0){
+ if(map > 0 && gind < 0){
int i, n = otfglyfnum(o);
GlyfImage *im = ppem > 0 ? calloc(n, sizeof(*im)) : nil;
for(i = 0; i < n; i++){
@@ -110,7 +58,7 @@
if(g == nil)
sysfatal("glyf %d: %r", i);
if(ppem > 0 && g->numberOfContours != 0){
- if(otfdrawglyf(o, g, ppem, &im[i]) != 0)
+ if(otfdrawglyf(o, g, ppem, gap, &im[i]) != 0)
sysfatal("glyf %d: %r", i);
}else if(ppem <= 0){
Bprint(out.aux, "%d (%s):\n", i,
@@ -120,7 +68,7 @@
free(g);
}
if(ppem > 0){
- dumpmap(out.aux, im, n);
+ dumpmap(&out, im, n);
for(i = 0; i < n; i++)
free(im[i].b);
free(im);
@@ -127,24 +75,24 @@
}else{
fprint(2, "\n");
}
- }else if(gi < 0){
+ }else if(gind < 0){
otfprint(o, &out, indentΔ);
}else{
int n = otfglyfnum(o);
- if(gi >= n)
- sysfatal("glyph %d out of range, max %d", gi, n-1);
- Glyf *g = otfglyf(o, gi);
+ if(gind >= n)
+ sysfatal("glyph %d out of range, max %d", gind, n-1);
+ Glyf *g = otfglyf(o, gind);
if(g == nil){
- fprint(2, "%d: %r\n", gi);
+ fprint(2, "%d: %r\n", gind);
}else if(ppem > 0){
GlyfImage im;
- if(otfdrawglyf(o, g, ppem, &im) != 0)
+ if(otfdrawglyf(o, g, ppem, gap, &im) != 0)
sysfatal("%r");
fprint(1, "%11s %11d %11d %11d %11d ", "k8", 0, 0, im.w, im.h);
write(1, im.b, im.w*im.h);
free(im.b);
}else{
- Bprint(out.aux, "\n%d:\n", gi);
+ Bprint(out.aux, "\n%d:\n", gind);
print_Glyf(&out, indentΔ, o, g);
}
}
--- a/rast.c
+++ b/rast.c
@@ -57,10 +57,11 @@
*/
#define QBZR_PIX_SCALE 4.0
-#define GAP 0
+#define MAXCOMPONENTS 16
+#define ε 1.0e-6
+#define min(a,b) ((a)<(b)?(a):(b))
+#define max(a,b) ((a)>(b)?(a):(b))
-#define ε 1.0e-10
-
static int
closest²(int v)
{
@@ -236,7 +237,7 @@
if(α₂ < 0){
α₂ = 0;
β₂ = (y₂-y₁)/(x₂-x₁)*(0-x₁)+y₁;
- }else if(α₂ >= 1){
+ }else if(α₂ > 1){
α₂ = 1;
β₂ = (y₂-y₁)/(x₂-x₁)*(1-x₁)+y₁;
}
@@ -252,7 +253,7 @@
if(β₂ < 0){
β₂ = 0;
α₂ = (x₂-x₁)/(y₂-y₁)*(0-y₁)+x₁;
- }else if(β₂ >= 1){
+ }else if(β₂ > 1){
β₂ = 1;
α₂ = (x₂-x₁)/(y₂-y₁)*(1-y₁)+x₁;
}
@@ -452,7 +453,7 @@
}
static SegQ *
-addpoints(SegQ *s, Spt *pts₀, int max, Glyf *g, int dx, int dy, Sval scale, Sval offY)
+addpoints(SegQ *s, Spt *pts₀, int max, Glyf *g)
{
Point *p₀, *p, *prev;
Spt *e, *pts;
@@ -505,12 +506,12 @@
}
for(; pts <= e-3; pts += 2, s++){
- s->v0[0] = (pts[0].x + dx) * scale;
- s->v0[1] = (pts[0].y + dy) * scale + offY;
- s->v1[0] = (pts[1].x + dx) * scale;
- s->v1[1] = (pts[1].y + dy) * scale + offY;
- s->v2[0] = (pts[2].x + dx) * scale;
- s->v2[1] = (pts[2].y + dy) * scale + offY;
+ s->v0[0] = pts[0].x;
+ s->v0[1] = pts[0].y;
+ s->v1[0] = pts[1].x;
+ s->v1[1] = pts[1].y;
+ s->v2[0] = pts[2].x;
+ s->v2[1] = pts[2].y;
}
}
return s;
@@ -535,16 +536,14 @@
return npts < 2 ? 0 : npts;
}
-#define MAXCOMPONENTS 16
-
int
-otfdrawglyf(Otf *o, Glyf *g, int ppem, GlyfImage *im)
+otfdrawglyf(Otf *o, Glyf *g, int ppem, int gap, GlyfImage *im)
{
int i, j, maxptstotal, maxpts, ngs, w, h, r, npx, baseline;
Glyf *gs[MAXCOMPONENTS];
ComponentGlyph *cg;
Sval scale, offY;
- SegQ *s₀, *s;
+ SegQ *s₀, *s, *p;
Spt *pts;
Sval *fp;
u8int *b;
@@ -552,6 +551,7 @@
r = -1;
ngs = 0;
pts = nil;
+ fp = nil;
if(g->simple != nil){
gs[ngs++] = g;
@@ -568,42 +568,109 @@
maxpts = j;
}
- scale = (Sval)ppem / otfupem(o);
- baseline = g->yMin < 0 ? ceil(scale*-g->yMin) : 0;
- offY = baseline > 0 ? (Sval)baseline - scale*-g->yMin : 0;
- w = ceil((g->xMax - g->xMin)*scale);
- h = ceil((g->yMax - g->yMin)*scale + (baseline ? 1 : 0));
- npx = w*h;
+/*
+FIXME metrics (lsb+rsb)
+ for(cg = g->component, i = 0; cg != nil && i < ngs; cg = cg->next, i++){
+ if(cg->flags & CGLYPH_FL_METRICS){
+ ...
+ break;
+ }
+ }
+*/
- pts = calloc(1, maxpts*sizeof(*pts) + maxptstotal/2*sizeof(*s) + npx*sizeof(*fp));
- s = s₀ = (SegQ*)(pts + maxptstotal);
- fp = (Sval*)(s + maxpts/2);
+ double xMin = 99999, yMin = 99999, xMax = -99999, yMax = -99999;
+ scale = (Sval)ppem / otfupem(o);
+ pts = calloc(1, maxpts*sizeof(*pts) + maxptstotal/2*sizeof(*s));
+ p = s = s₀ = (SegQ*)(pts + maxpts);
cg = g->component;
for(i = 0; i < ngs; i++){
- int dx = -g->xMin, dy = -g->yMin;
+ double dx = 0, dy = 0, gscaleX = scale, gscaleY = scale;
if(cg != nil){
if(cg->flags & CGLYPH_FL_SIGNED_XY){
- dx += cg->dx;
- dy += cg->dy;
+ dx = cg->dx;
+ dy = cg->dy;
+ }else{
+ dx = 0;
+ dy = 0;
}
+ if(cg->flags & CGLYPH_FL_SCALE_XY){
+ gscaleX *= cg->scaleX;
+ gscaleY *= cg->scaleY;
+ }
+ if((cg->flags & CGLYPH_FL_SCALED_COMPONENT_OFFSET) == 0){
+ dx *= gscaleX;
+ dy *= gscaleY;
+ }
+/* FIXME rounding
+ if(cg->flags & CGLYPH_FL_ROUND_TO_GRID_XY){
+ ...
+ }
+*/
cg = cg->next;
}
- if((s = addpoints(s, pts, maxpts, gs[i], dx, dy, scale, offY)) == nil)
+ if((s = addpoints(s, pts, maxpts, gs[i])) == nil)
goto done;
+ for(; p < s; p++){
+ p->p0.x = p->p0.x*gscaleX + dx;
+ xMin = min(xMin, p->p0.x);
+ xMax = max(xMax, p->p0.x);
+ p->p0.y = p->p0.y*gscaleY + dy;
+ yMin = min(yMin, p->p0.y);
+ yMax = max(yMax, p->p0.y);
+ p->p1.x = p->p1.x*gscaleX + dx;
+ xMin = min(xMin, p->p1.x);
+ xMax = max(xMax, p->p1.x);
+ p->p1.y = p->p1.y*gscaleY + dy;
+ yMin = min(yMin, p->p1.y);
+ yMax = max(yMax, p->p1.y);
+ p->p2.x = p->p2.x*gscaleX + dx;
+ xMin = min(xMin, p->p2.x);
+ xMax = max(xMax, p->p2.x);
+ p->p2.y = p->p2.y*gscaleY + dy;
+ yMin = min(yMin, p->p2.y);
+ yMax = max(yMax, p->p2.y);
+ }
}
- if((r = qbzr(s₀, s-s₀, w, h, fp)) == 0){
- b = (u8int*)pts;
+ if(s == s₀){
+ w = h = 1;
+ baseline = 0;
+ }else{
+ xMin -= gap;
+ yMin -= gap;
+ xMax += gap;
+ yMax += gap;
+
+ /* height+baseline is where it is in the image */
+ baseline = floor(yMin);
+ offY = -baseline;
+ yMax += offY;
+ w = ceil(xMax - xMin);
+ h = ceil(yMax);
+
+ for(p = s₀; p != s; p++){
+ p->p0.x -= xMin;
+ p->p1.x -= xMin;
+ p->p2.x -= xMin;
+ p->p0.y += offY;
+ p->p1.y += offY;
+ p->p2.y += offY;
+ }
+ }
+
+ npx = w*h;
+ fp = malloc(npx*sizeof(*fp));
+ if(qbzr(s₀, s-s₀, w, h, fp) == 0){
+ b = (u8int*)fp;
for(i = 0; i < npx; i++)
- b[i] = 255 - (fp[i] <= 0 ? 0 : (fp[i] >= QBZR_PIX_SCALE ? 255 : fp[i]/QBZR_PIX_SCALE*255));
- if((b = realloc(b, npx)) != nil){
+ b[i] = 255 - (fp[i] <= ε ? 0 : (fp[i] >= QBZR_PIX_SCALE ? 255 : fp[i]/QBZR_PIX_SCALE*255));
+ if((b = realloc(fp, npx)) != nil){
im->b = b;
im->w = w;
im->h = h;
im->baseline = baseline;
- pts = nil;
- }else{
- r = -1;
+ fp = nil;
+ r = 0;
}
}
@@ -613,5 +680,6 @@
free(gs[i]);
}
free(pts);
+ free(fp);
return r;
}
--- /dev/null
+++ b/test.h
@@ -1,0 +1,105 @@
+static void
+printusage(Otfile *f)
+{
+ f->print(f->aux, "usage: %s [-i GLYPH_ID] [-m] [-p PX] font.otf ...\n", argv0);
+ f->print(f->aux, " -i: specifies a single glyph id\n");
+ f->print(f->aux, " -g: gap (in pixels) to add to every glyph border\n");
+ f->print(f->aux, " -m: print out glyph ids or render them all (with -p)\n");
+ f->print(f->aux, " -p: draw (of size in pixels per em) and write the image to stdout\n");
+ f->print(f->aux, "Specifying -m more than once makes the program draw guide lines\n");
+}
+
+static int gap, gind = -1, map, ppem;
+
+static int
+dumpmap(Otfile *f, GlyfImage *im, int n)
+{
+ int x, y, i, j, t, maxh, prebase, postbase, d;
+ int gap, total, mid, npix, bw, bh, lines;
+ u8int *b;
+
+ total = 0;
+ maxh = 0;
+ gap = 1;
+ lines = map > 1;
+ for(i = 0; i < n; i++){
+ if(im[i].b == nil)
+ continue;
+ if(maxh < im[i].h)
+ maxh = im[i].h;
+ total += im[i].w;
+ }
+ mid = total / n;
+ npix = (mid+gap)*(maxh+gap)*n;
+ bh = sqrt(npix);
+ bw = npix/bh;
+ npix += bw*gap;
+ if((b = malloc(npix*3)) == nil)
+ return -1;
+ memset(b, 0xff, npix*3);
+ y = gap;
+ for(i = 0; i < n;){
+ for(prebase = postbase = x = 0, j = i; j < n; j++){
+ if(im[j].b == nil)
+ continue;
+ x += im[j].w + gap;
+ if(x > bw)
+ break;
+ if(prebase < im[j].h+im[j].baseline)
+ prebase = im[j].h+im[j].baseline;
+ if(postbase < im[j].baseline)
+ postbase = im[j].baseline;
+ }
+ maxh = prebase + postbase;
+ if(j == i || y+maxh > bh)
+ break;
+
+ for(x = 0; i < j; i++){
+ if(im[i].b == nil)
+ continue;
+ u8int *lt = b + ((y + prebase - (im[i].h+im[i].baseline))*bw + x)*3;
+ for(d = 0; d < im[i].h; d++, lt += bw*3){
+ for(t = 0; t < im[i].w; t++){
+ u8int r, g, b;
+ r = g = b = im[i].b[d*im[i].w + t];
+ if(lines && g == 0xff && (d == im[i].h+im[i].baseline)){
+ g = 0;
+ b = 0;
+ }else if(lines && g == 0xff && (t == 0 || t == im[i].w-1 || d == 0 || d == im[i].h-1)){
+ r = 0;
+ b = 0;
+ }
+ if(r != 0xff || g != 0xff || b != 0xff){
+ lt[t*3+0] = b;
+ lt[t*3+1] = g;
+ lt[t*3+2] = r;
+ }
+ }
+ }
+ x += im[i].w + gap;
+ }
+ y += maxh + gap;
+ }
+ f->print(f->aux, "%11s %11d %11d %11d %11d ", "r8g8b8", 0, 0, bw, y);
+ f->write(f->aux, b, bw*y*3);
+ free(b);
+ return 0;
+}
+
+#define parseoptions() \
+ ARGBEGIN{ \
+ case 'g': \
+ gap = strtol(EARGF(usage(&out)), nil, 0); \
+ break; \
+ case 'i': \
+ gind = strtol(EARGF(usage(&out)), nil, 0); \
+ break; \
+ case 'm': \
+ map++; \
+ break; \
+ case 'p': \
+ ppem = strtol(EARGF(usage(&out)), nil, 0); \
+ break; \
+ default: \
+ usage(&out); \
+ }ARGEND
--- a/unix/test.c
+++ b/unix/test.c
@@ -1,3 +1,4 @@
+#include <assert.h>
#include <err.h>
#include <math.h>
#include <stdio.h>
@@ -5,47 +6,8 @@
#include <string.h>
#include "otf.h"
-static void
-dumpmap(FILE *out, GlyfImage *im, int n)
-{
-#define gap 1
- int total, mid, npix, bw, bh, x, y, i, maxh, d;
- u8int *b;
+#define nil NULL
- total = 0;
- maxh = 0;
- for(i = 0; i < n; i++){
- if(maxh < im[i].h)
- maxh = im[i].h;
- total += im[i].w;
- }
- mid = total / n;
- npix = (mid+gap)*(maxh+gap)*n;
- bh = sqrt(npix);
- bw = npix/bh;
- bh *= 1.5;
- npix *= 1.5;
- npix += bw*gap;
- if((b = malloc(npix)) == NULL)
- err(1, NULL);
- memset(b, 0xff, npix);
- x = y = gap;
- for(i = 0; i < n; i++){
- if((bw-x) < im[i].w+gap){
- y += maxh + gap;
- x = gap;
- }
- if((bh-y) < maxh+gap)
- continue;
- for(d = 0; d < im[i].h; d++)
- memcpy(b + (maxh - im[i].h + y + im[i].baseline + d)*bw + x, im[i].b + d*im[i].w, im[i].w);
- x += im[i].w + gap;
- }
- fprintf(out, "%11s %11d %11d %11d %11d ", "k8", 0, 0, bw, y+maxh+gap);
- fwrite(b, 1, bw*(y+maxh+gap), out);
- free(b);
-}
-
static char *argv0;
#define ARGBEGIN for((argv0? 0: (argv0=*argv)),argv++,argc--;\
@@ -68,6 +30,8 @@
#define EARGF(x) (_argt=_args, _args="",\
(*_argt? _argt: argv[1]? (argc--, *++argv): (x, (char*)0)))
+#include "test.h"
+
static int
otfseek(void *aux, int off, int whence)
{
@@ -82,13 +46,16 @@
return fread(dst, 1, sz, aux);
}
+static int
+otfwrite(void *aux, const void *src, int sz)
+{
+ return fwrite(src, 1, sz, aux);
+}
+
static void
-usage(void)
+usage(Otfile *out)
{
- fprintf(stderr, "usage: %s [-g GLYPH_ID] [-G] [-i N] [-s PX] font.otf ...\n", argv0);
- fprintf(stderr, " -g: specifies a single glyph id\n");
- fprintf(stderr, " -G: print out glyph ids, only ones that can be drawn atm (no compound yet)\n");
- fprintf(stderr, " -p: draw (of size in pixels per em) and write the image to stdout\n");
+ printusage(out);
exit(1);
}
@@ -95,32 +62,17 @@
int
main(int argc, char **argv)
{
- int i, gi, G, ppem;
Otfile in, out;
+ int i;
Otf *o;
- gi = -1;
- G = 0;
- ppem = 0;
- ARGBEGIN{
- case 'g':
- gi = strtol(EARGF(usage()), NULL, 0);
- break;
- case 'G':
- G++;
- break;
- case 'p':
- ppem = strtol(EARGF(usage()), NULL, 0);
- break;
- default:
- usage();
- }ARGEND
-
+ out.print = (void*)fprintf;
+ out.write = otfwrite;
+ out.aux = fdopen(1, "wb");
in.seek = otfseek;
in.read = otfread;
- out.print = (void*)fprintf;
+ parseoptions();
- out.aux = fdopen(1, "wb");
for(i = 0; i < argc; i++){
if((in.aux = fopen(argv[i], "rb")) == NULL)
err(1, "%s", argv[i]);
@@ -127,8 +79,8 @@
if((o = otfopen(&in)) == NULL)
errx(1, "%s: %s", argv[i], otferrstr());
if(ppem <= 0)
- fprintf(out.aux, "%s\n", argv[i]);
- if(G && gi < 0){
+ out.print(out.aux, "%s\n", argv[i]);
+ if(map && gind < 0){
int i, n = otfglyfnum(o);
GlyfImage *im = ppem > 0 ? calloc(n, sizeof(*im)) : NULL;
for(i = 0; i < n; i++){
@@ -136,10 +88,10 @@
if(g == NULL)
errx(1, "glyph %d: %s", i, otferrstr());
if(ppem > 0 && g->numberOfContours != 0){
- if(otfdrawglyf(o, g, ppem, im+i) != 0)
+ if(otfdrawglyf(o, g, ppem, gap, im+i) != 0)
errx(1, "glyph %d: %s", i, otferrstr());
}else if(ppem <= 0){
- fprintf(out.aux, "%d (%s):\n", i,
+ out.print(out.aux, "%d (%s):\n", i,
g->simple ? "simple" : (g->component ? "component" : "empty"));
print_Glyf(&out, indentΔ, o, g);
}
@@ -146,33 +98,30 @@
free(g);
}
if(ppem > 0){
- dumpmap(out.aux, im, n);
+ if(dumpmap(&out, im, n) != 0)
+ err(1, nil);
for(i = 0; i < n; i++)
free(im[i].b);
free(im);
}
- }else if(gi < 0){
+ }else if(gind < 0){
otfprint(o, &out, indentΔ);
}else{
int n = otfglyfnum(o);
- if(gi >= n)
- errx(1, "glyph %d out of range, max %d", gi, n-1);
- Glyf *g = otfglyf(o, gi);
+ if(gind >= n)
+ errx(1, "glyph %d out of range, max %d", gind, n-1);
+ Glyf *g = otfglyf(o, gind);
if(g == NULL){
- errx(1, "glyph %d: %s", gi, otferrstr());
+ errx(1, "glyph %d: %s", gind, otferrstr());
}else if(ppem > 0){
- if(g->component != NULL)
- errx(1, "glyph %d: component", gi);
- else{
- GlyfImage im;
- if(otfdrawglyf(o, g, ppem, &im) != 0)
- errx(1, "glyph %d: %s", gi, otferrstr());
- fprintf(out.aux, "%11s %11d %11d %11d %11d ", "k8", 0, 0, im.w, im.h);
- fwrite(im.b, 1, im.w*im.h, out.aux);
- free(im.b);
- }
+ GlyfImage im;
+ if(otfdrawglyf(o, g, ppem, gap, &im) != 0)
+ errx(1, "glyph %d: %s", gind, otferrstr());
+ out.print(out.aux, "%11s %11d %11d %11d %11d ", "k8", 0, 0, im.w, im.h);
+ out.write(out.aux, im.b, im.w*im.h);
+ free(im.b);
}else{
- fprintf(out.aux, "\n%d:\n", gi);
+ out.print(out.aux, "\n%d:\n", gind);
print_Glyf(&out, indentΔ, o, g);
}
}