diff options
-rw-r--r-- | fontforge/python.c | 218 | ||||
-rw-r--r-- | htdocs/python.html | 100 |
2 files changed, 316 insertions, 2 deletions
diff --git a/fontforge/python.c b/fontforge/python.c index 37ba263b..5ce08b78 100644 --- a/fontforge/python.c +++ b/fontforge/python.c @@ -1043,7 +1043,7 @@ return( NULL ); return( NULL ); } for ( i=0; i<cnt; ++i ) { - PyObject *utf8_name = PYBYTES_UTF8(PyTuple_GetItem(answero,i)); + PyObject *utf8_name = PYBYTES_UTF8(PySequence_GetItem(answero,i)); if ( utf8_name==NULL ) return( NULL ); answers[i] = copy(PyBytes_AsString(utf8_name)); @@ -14748,7 +14748,7 @@ static PyObject *PyFFFont_addSmallCaps(PyObject *self, PyObject *args, PyObject memset(&genchange,0,sizeof(genchange)); SmallCapsFindConstants(&small,fv->sf,fv->active_layer); genchange.small = &small; - genchange.gc = gc_subsuper; + genchange.gc = gc_smallcaps; genchange.extension_for_letters = "sc"; genchange.extension_for_symbols = "taboldstyle"; if ( !PyArg_ParseTupleAndKeywords(args,keywds,"|ddddissddd",smallcaps_keywords, @@ -14788,6 +14788,219 @@ return( NULL ); Py_RETURN( self ); } +static char *genchange_keywords[] = { +/* Stem info */ + "stemType", + "thickThreshold", + "stemScale", "stemAdd", + "stemHeightScale", "thinStemScale", + "stemHeightAdd", "thinStemAdd", + "stemWidthScale", "thickStemScale", + "stemWidthAdd", "thickStemAdd", + "processDiagonalStems", +/* Horizontal counter info */ + "hCounterType", + "hCounterScale", "hCounterAdd", + "lsbScale", "lsbAdd", + "rsbScale", "rsbAdd", +/* Vertical counter info */ + "vCounterType", + "vCounterScale", "vCounterAdd", + "vScale", + "vMap", + NULL}; + +static PyObject *PyFFFont_genericGlyphChange(PyObject *self, PyObject *args, PyObject *keywds) { + FontViewBase *fv = ((PyFF_Font *) self)->fv; + struct smallcaps small; + struct genericchange genchange; + char *stemtype = "uniform", *hcountertype="uniform", *vCounterType="mapped"; + double thickthreshold=0, + stemscale=0, stemadd=0, + stemheightscale=0, thinstemscale=0, + stemheightadd=0, thinstemadd=0, + stemwidthscale=0, thickstemscale=0, + stemwidthadd=0, thickstemadd=0; + int processdiagonalstems=1; + double counterScale=0, counterAdd=0, + lsbScale=0, lsbAdd=0, + rsbScale=0, rsbAdd=0; + double vCounterScale=0, vCounterAdd=0, + vScale=1.0; + PyObject *vMap=NULL; + + memset(&genchange,0,sizeof(genchange)); + SmallCapsFindConstants(&small,fv->sf,fv->active_layer); + genchange.small = &small; + genchange.gc = gc_generic; + if ( !PyArg_ParseTupleAndKeywords(args,keywds,"|sdddddddddddisddddddsdddO",genchange_keywords, +/* Stem info */ + &stemtype, + &thickthreshold, + &stemscale, &stemadd, + &stemheightscale,&thinstemscale, + &stemheightadd, &thinstemadd, + &stemwidthscale, &thickstemscale, + &stemwidthadd, &thickstemadd, + &processdiagonalstems, +/* Horizontal counter info */ + &hcountertype, + &counterScale, &counterAdd, + &lsbScale, &lsbAdd, + &rsbScale, &rsbAdd, +/* Vertical counter info */ + &vCounterType, + &vCounterScale, vCounterAdd, + &vScale, + &vMap + )) +return( NULL ); + +/* Stem info */ + if ( strcasecmp(stemtype,"uniform")==0 ) { + if ( stemscale<=0 ) { + PyErr_Format(PyExc_TypeError, "Unexpected (or unspecified) value for stemScale: %g.", stemscale ); +return( NULL ); + } + genchange.stem_width_scale = genchange.stem_height_scale = stemscale; + genchange.stem_width_add = genchange.stem_height_add = stemadd; + } else if ( strcasecmp( stemtype, "thickThin" )==0 ) { + if ( thinstemscale<=0 ) { + PyErr_Format(PyExc_TypeError, "Unexpected (or unspecified) value for thinStemScale: %g.", thinstemscale ); +return( NULL ); + } + if ( thickstemscale<=0 ) { + PyErr_Format(PyExc_TypeError, "Unexpected (or unspecified) value for thickStemScale: %g.", thickstemscale ); +return( NULL ); + } + if ( thickthreshold<=0 ) { + PyErr_Format(PyExc_TypeError, "Unexpected (or unspecified) value for thickThreshold: %g.", thickthreshold ); +return( NULL ); + } + genchange.stem_width_scale = thickstemscale; + genchange.stem_width_add = thickstemadd; + genchange.stem_height_scale = thinstemscale; + genchange.stem_height_add = thinstemadd; + genchange.stem_threshold = thickthreshold; + } else if ( strcasecmp( stemtype, "horizontalVertical" )==0 ) { + if ( stemheightscale<=0 ) { + PyErr_Format(PyExc_TypeError, "Unexpected (or unspecified) value for stemHeightScale: %g.", stemheightscale ); +return( NULL ); + } + if ( stemwidthscale<=0 ) { + PyErr_Format(PyExc_TypeError, "Unexpected (or unspecified) value for stemWidthScale: %g.", stemwidthscale ); +return( NULL ); + } + genchange.stem_width_scale = stemwidthscale; + genchange.stem_width_add = stemwidthadd; + genchange.stem_height_scale = stemheightscale; + genchange.stem_height_add = stemheightadd; + } else { + PyErr_Format(PyExc_TypeError, "Unexpected value for stemType: %s\n (Try: 'uniform', 'thickThin', or 'horizontalVertical')", stemtype ); +return( NULL ); + } + genchange.dstem_control = processdiagonalstems; + if ( genchange.stem_height_add!=genchange.stem_width_add ) { + if (( genchange.stem_height_add==0 && genchange.stem_width_add!=0 ) || + ( genchange.stem_height_add!=0 && genchange.stem_width_add==0 )) { + PyErr_Format(PyExc_TypeError, _("The horizontal and vertical stem add amounts must either both be zero, or neither may be 0")); +return( NULL ); + } + /* if width_add has a different sign than height_add that's also */ + /* a problem, but this test will catch that too */ + if (( genchange.stem_height_add/genchange.stem_width_add>4 ) || + ( genchange.stem_height_add/genchange.stem_width_add<.25 )) { + PyErr_Format(PyExc_TypeError, _("The horizontal and vertical stem add amounts may not differ by more than a factor of 4")); +return( NULL ); + } + } + +/* Horizontal counter info */ + if ( strcasecmp(hcountertype,"uniform")==0 ) { + if ( counterScale<=0 ) { + PyErr_Format(PyExc_TypeError, "Unexpected (or unspecified) value for hCounterScale: %g.", counterScale ); +return( NULL ); + } + genchange.hcounter_scale = genchange.lsb_scale = genchange.rsb_scale = counterScale; + genchange.hcounter_add = genchange.lsb_add = genchange.rsb_add = counterAdd; + } else if ( strcasecmp(hcountertype,"nonUniform")==0 ) { + if ( counterScale<=0 ) { + PyErr_Format(PyExc_TypeError, "Unexpected (or unspecified) value for hCounterScale: %g.", counterScale ); +return( NULL ); + } + if ( lsbScale<=0 ) { + PyErr_Format(PyExc_TypeError, "Unexpected (or unspecified) value for lsbScale: %g.", lsbScale ); +return( NULL ); + } + if ( rsbScale<=0 ) { + PyErr_Format(PyExc_TypeError, "Unexpected (or unspecified) value for rsbScale: %g.", rsbScale ); +return( NULL ); + } + genchange.hcounter_scale = counterScale; + genchange.lsb_scale = lsbScale; + genchange.rsb_scale = rsbScale; + genchange.hcounter_add = counterAdd; + genchange.lsb_add = lsbAdd; + genchange.rsb_add = rsbAdd; + } else if ( strcasecmp(hcountertype,"center")==0 ) { + genchange.center_in_hor_advance = 1; + } else if ( strcasecmp(hcountertype,"retainScale")==0 ) { + genchange.center_in_hor_advance = 2; + } else { + PyErr_Format(PyExc_TypeError, "Unexpected value for hCounterType: %s\n (Try: 'uniform', 'nonUniform', 'retain', or 'scale')", hcountertype ); +return( NULL ); + } + +/* Vertical counter info */ + if ( strcasecmp(vCounterType,"scaled")==0 ) { + if ( vCounterScale<=0 ) { + PyErr_Format(PyExc_TypeError, "Unexpected (or unspecified) value for vCounterScale: %g.", vCounterScale ); +return( NULL ); + } + genchange.vcounter_scale = vCounterScale; + genchange.vcounter_add = vCounterAdd; + genchange.use_vert_mapping = false; + } else if ( strcasecmp(vCounterType,"mapped")==0 ) { + int cnt,i; + genchange.use_vert_mapping = true; + if ( vScale<=0 ) { + PyErr_Format(PyExc_TypeError, "Unexpected (or unspecified) value for vScale: %g.", vScale ); +return( NULL ); + } + genchange.v_scale = vScale; + if ( vMap==NULL || !PySequence_Check(vMap) || STRING_CHECK(vMap)) { + PyErr_Format(PyExc_TypeError, "vMap should be a tuple (or some other sequence type)." ); +return( NULL ); + } + cnt = PySequence_Size(vMap); + genchange.m.cnt = cnt; + genchange.m.maps = galloc(cnt*sizeof(struct position_maps)); + for ( i=0; i<cnt; ++i ) { + PyObject *subTuple = PySequence_GetItem(vMap,i); + if ( subTuple==NULL || !PySequence_Check(subTuple) || STRING_CHECK(subTuple) || PySequence_Size(subTuple)!=3 ) { + PyErr_Format(PyExc_TypeError, "vMap should be a tuple of 3-tuples." ); + free(genchange.m.maps); +return( NULL ); + } + if ( !PyArg_ParseTuple(subTuple,"ddd", + &genchange.m.maps[i].current, + &genchange.m.maps[i].desired, + &genchange.m.maps[i].cur_width) ) { + free(genchange.m.maps); +return( NULL ); + } + } + } else { + PyErr_Format(PyExc_TypeError, "Unexpected value for vCounterType: %s\n (Try: 'scaled', or 'mapped')", vCounterType ); +return( NULL ); + } + + FVGenericChange( fv, &genchange ); + free(genchange.m.maps); + +Py_RETURN( self ); +} + static PyObject *PyFFFont_autoHint(PyObject *self, PyObject *args) { FontViewBase *fv = ((PyFF_Font *) self)->fv; @@ -15107,6 +15320,7 @@ static PyMethodDef PyFF_Font_methods[] = { /*{ "compareGlyphs", (PyCFunction) PyFFFont_compareGlyphs, METH_VARARGS, "Compares two sets of glyphs"},*/ /* compareGlyphs assumes an old scripting context */ { "correctDirection", (PyCFunction) PyFFFont_Correct, METH_NOARGS, "Orient a layer so that external contours are clockwise and internal counter clockwise." }, + { "genericGlyphChange", (PyCFunction) PyFFFont_genericGlyphChange, METH_VARARGS | METH_KEYWORDS, "Rather like changeWeight or condenseExtend but with more options."}, { "italicize", (PyCFunction) PyFFFont_italicize, METH_VARARGS | METH_KEYWORDS, "Italicize the selected glyphs"}, { "intersect", (PyCFunction) PyFFFont_Intersect, METH_NOARGS, "Leaves the areas where the contours of a glyph overlap."}, { "removeOverlap", (PyCFunction) PyFFFont_RemoveOverlap, METH_NOARGS, "Remove overlapping areas from a glyph"}, diff --git a/htdocs/python.html b/htdocs/python.html index 75b417ba..9da7aac1 100644 --- a/htdocs/python.html +++ b/htdocs/python.html @@ -4211,6 +4211,106 @@ pen = None; # Finalize the pen. This tells FontForge is specified then only data for that lookup will be generated.</TD> </TR> <TR> + <TD><CODE>genericGlyphChange</CODE></TD> + <TD><CODE>(stemType=<str>,<BR> + thickThreshold=<double>,<BR> + stemScale=<double>,<BR> + stemAdd=<double>,<BR> + stemHeightScale=<double>,<BR> + stemHeightAdd=<double>,<BR> + stemWidthScale=<double>,<BR> + stemWidthAdd=<double>,<BR> + thinStemScale=<double>,<BR> + thinStemAdd=<double>,<BR> + thickStemScale=<double>,<BR> + thickStemAdd=<double>,<BR> + processDiagonalStems=<boolean>,<BR> + <BR> + hCounterType=<str>,<BR> + hCounterScale=<double>,<BR> + hCounterAdd=<double>,<BR> + lsbScale=<double>,<BR> + lsbAdd=<double>,<BR> + rsbScale=<double>,<BR> + rsbAdd=<double>,<BR> + <BR> + vCounterType=<str>,<BR> + vCounterScale=<double>,<BR> + vCounterAdd=<double>,<BR> + vScale=<double>,<BR> + vMap=<tuple of tuples>)</CODE></TD> + <TD>This function uses keyword parameters. Which ones are required depends + on the three type arguments (<CODE>stemType, hCounterType, + vCounterType</CODE>). + <P> + If <CODE>stemType</CODE> is omitted, or is the string "uniform", then + the <CODE>stemScale</CODE> parameter must be specified (and + <CODE>stemAdd</CODE> may be). <CODE>stemScale</CODE> specifies a + scaling factor by which all stems (horizontal and vertical, thick and + thin) will be scaled. A value of 1.0 means no change. While + <CODE>stemAdd</CODE> specifies the number of em-units to add to the + width of each stem. + <P> + If <CODE>stemType</CODE> is the string "horizontalVertical", + then values must be specified for <CODE>stemHeightScale</CODE> and + <CODE>stemWidthScale</CODE> (and may be for <CODE>stemHeightAdd, + stemWidthAdd</CODE>). The first of these specifies scaling for the + height of horizontal stems, and the second scaling for the width + of vertical stems. + <P> + If <CODE>stemType</CODE> is the string "thickThin", + then values must be specified for <CODE>thinStemScale</CODE>, + <CODE>thickStemScale</CODE> and <CODE>thickThreshold</CODE> + (and may be for <CODE>thinStemAdd, thickStemAdd</CODE>). The + first of these specifies scaling for the width/height of thin + stems, and the second scaling for the width/height of thick + stems. While the <CODE>thickThreshold</CODE> argument specifies + the size (in em-units) at which a stem is classified as "thick". + <P> + <P> + If <CODE>hCounterType</CODE> is omitted, or is the string "uniform", + then horizontal counters, and the left and right side bearings will + all be scaled using the same rules, and <CODE>hCounterScale</CODE> + must be specified to provide the scaling factor (while + <CODE>hCounterAdd</CODE> may be specified). + <P> + If <CODE>hCounterType</CODE> is the string "nonUniform", + then horizontal counters, and the left and right side bearings may + all be scaled using different rules, and <CODE>hCounterScale, + lsbScale</CODE> and <CODE>rsbScale</CODE> must be specified to + provide the scaling factors (while <CODE>hCounterAdd, lsbAdd,</CODE> + and <CODE>rsbAdd</CODE> may be specified). + <P> + If <CODE>hCounterType</CODE> is the string "center", then the left + and right side-bearings will be set so the new glyph is centered + within the original glyph's width. (Probably more useful for CJK + fonts than LGC fonts). + <P> + If <CODE>hCounterType</CODE> is the string "retainScale", then the + left and right side-bearings will be set so the new glyph is within + within the original glyph's width, and the side-bearings remain in + the same proportion to each other as before. + <P> + <P> + If <CODE>vCounterType</CODE> is omitted, or is the string "mapped", + then certain zones on the glyph may be placed at new (or the same) + locations -- similar to BlueValues. So you can specify a zone for + the baseline, one for the + x-height and another for the top of capitals and ascenders (and perhaps + a fourth for descenders). Each such zone is specified by the + <CODE>vMap</CODE> argument which is a tuple of 3-tuples, each + 3-tuple specifying a zone with: Original location, original width, and + final location. <strong>No default value is provided for this argument + you must figure out all the values yourself</strong>. + <P> + If <CODE>vCounterType</CODE> is the string "scaled", + then vertical counters, and the top and bottom side bearings will + all be scaled using the same rules, and <CODE>vCounterScale</CODE> + must be specified to provide the scaling factor (while + <CODE>vCounterAdd</CODE> may be specified). This is probably most + useful for CJK fonts.</TD> + </TR> + <TR> <TD><CODE>getKerningClass</CODE></TD> <TD><CODE>(subtable-name)</CODE></TD> <TD>Returns a tuple whose entries are: (first-classes, second-classes, offsets). |