Skip to content

Commit

Permalink
Merge pull request #68 from kyamagu/improve-font-apis
Browse files Browse the repository at this point in the history
Improve Font APIs
  • Loading branch information
kyamagu authored Jun 12, 2020
2 parents ade2671 + 6c74863 commit f5b5ee8
Show file tree
Hide file tree
Showing 9 changed files with 905 additions and 62 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ For unsupported environment, check the [build instruction](https://kyamagu.githu
- [Path Overview](https://github.com/kyamagu/skia-python/blob/master/notebooks/Path-Overview.ipynb)
- [Paint Overview](https://github.com/kyamagu/skia-python/blob/master/notebooks/Paint-Overview.ipynb)
- [Python Image I/O](https://github.com/kyamagu/skia-python/blob/master/notebooks/Python-Image-IO.ipynb)
- [Drawing Texts](https://github.com/kyamagu/skia-python/blob/master/notebooks/Drawing-Texts.ipynb)

## Documentation

Expand Down
1 change: 1 addition & 0 deletions docs/tutorial/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ Notebook examples
- `Canvas Creation <https://github.com/kyamagu/skia-python/blob/master/notebooks/Canvas-Creation.ipynb>`_
- `Path Overview <https://github.com/kyamagu/skia-python/blob/master/notebooks/Path-Overview.ipynb>`_
- `Paint Overview <https://github.com/kyamagu/skia-python/blob/master/notebooks/Paint-Overview.ipynb>`_
- `Drawing Texts <https://github.com/kyamagu/skia-python/blob/master/notebooks/Drawing-Texts.ipynb>`_
- `Python Image I/O <https://github.com/kyamagu/skia-python/blob/master/notebooks/Python-Image-IO.ipynb>`_
586 changes: 586 additions & 0 deletions notebooks/Drawing-Texts.ipynb

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
pass

NAME = 'skia-python'
__version__ = '0.0.4'
__version__ = '0.0.5'

SKIA_PATH = os.getenv('SKIA_PATH', 'skia')
SKIA_OUT_PATH = os.getenv(
Expand Down
179 changes: 158 additions & 21 deletions src/skia/Font.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ using Coordinate = SkFontArguments::VariationPosition::Coordinate;

PYBIND11_MAKE_OPAQUE(std::vector<Coordinate>);


namespace {

void SetVariationPositionCoordinates(
SkFontArguments::VariationPosition& vp,
const std::vector<Coordinate>& coords) {
Expand All @@ -15,6 +18,35 @@ void SetVariationPositionCoordinates(
}


py::tuple SkFontStyleSet_getStyle(SkFontStyleSet* self, int index) {
SkFontStyle style;
SkString name;
if (index < 0 || index >= self->count())
throw py::index_error();
self->getStyle(index, &style, &name);
return py::make_tuple(style, py::str(name.c_str(), name.size()));
}

py::str SkFontMgr_getFamilyName(const SkFontMgr& fontmgr, int index) {
SkString familyName;
if (index < 0 || index >= fontmgr.countFamilies())
throw py::index_error();
fontmgr.getFamilyName(index, &familyName);
return py::str(familyName.c_str(), familyName.size());
}

sk_sp<SkTypeface> SkTypeface_MakeFromName(
py::object familyName,
const SkFontStyle* fontStyle) {
return SkTypeface::MakeFromName(
(familyName.is_none()) ?
nullptr : familyName.cast<std::string>().c_str(),
(fontStyle) ? *fontStyle : SkFontStyle());
}

} // namespace


void initFont(py::module &m) {
// FontStyle
py::class_<SkFontStyle> fontstyle(m, "FontStyle");
Expand Down Expand Up @@ -54,6 +86,11 @@ py::enum_<SkFontStyle::Slant>(fontstyle, "Slant")
fontstyle
.def(py::init<int, int, SkFontStyle::Slant>())
.def(py::init<>())
.def("__repr__",
[] (const SkFontStyle& self) {
return py::str("FontStyle({}, {}, {})").format(
self.weight(), self.width(), self.slant());
})
.def("weight", &SkFontStyle::weight)
.def("width", &SkFontStyle::width)
.def("slant", &SkFontStyle::slant)
Expand Down Expand Up @@ -149,6 +186,14 @@ py::class_<SkTypeface, sk_sp<SkTypeface>, SkRefCnt> typeface(
appears when drawn (and measured).
Typeface objects are immutable, and so they can be shared between threads.
Example::
typeface = skia.Typeface()
typeface = skia.Typeface('Arial')
typeface = skia.Typeface('Arial', skia.FontStyle.Bold())
)docstring");

py::enum_<SkTypeface::SerializeBehavior>(typeface, "SerializeBehavior",
Expand All @@ -165,6 +210,30 @@ py::enum_<SkTypeface::SerializeBehavior>(typeface, "SerializeBehavior",
.export_values();

typeface
.def(py::init([] () { return SkTypeface::MakeDefault(); }),
R"docstring(
Returns the default normal typeface.
)docstring")
.def(py::init(&SkTypeface_MakeFromName),
R"docstring(
Creates a new reference to the typeface that most closely matches the
requested familyName and fontStyle.
This method allows extended font face specifiers as in the
:py:class:`FontStyle` type. Will never return null.
:param str familyName: May be NULL. The name of the font family.
:param skia.FontStyle fontStyle: The style of the typeface.
:return: reference to the closest-matching typeface.
)docstring",
py::arg("familyName"), py::arg("fontStyle") = nullptr)
.def("__repr__",
[] (const SkTypeface& self) {
SkString name;
self.getFamilyName(&name);
return py::str("Typeface('{}', {})").format(
name.c_str(), self.fontStyle());
})
.def("fontStyle", &SkTypeface::fontStyle,
R"docstring(
Returns the typeface's intrinsic style attributes.
Expand Down Expand Up @@ -410,11 +479,7 @@ typeface
R"docstring(
Returns the default normal typeface, which is never nullptr.
)docstring")
.def_static("MakeFromName",
[] (const std::string* familyName, const SkFontStyle& fontStyle) {
return SkTypeface::MakeFromName(
(familyName) ? familyName->c_str() : nullptr, fontStyle);
},
.def_static("MakeFromName", &SkTypeface_MakeFromName,
R"docstring(
Creates a new reference to the typeface that most closely matches the
requested familyName and fontStyle.
Expand All @@ -426,7 +491,7 @@ typeface
:param skia.FontStyle fontStyle: The style of the typeface.
:return: reference to the closest-matching typeface.
)docstring",
py::arg("familyName"), py::arg("fontStyle"))
py::arg("familyName"), py::arg("fontStyle") = nullptr)
.def_static("MakeFromFile",
[] (const std::string& path, int index) {
return SkTypeface::MakeFromFile(&path[0], index);
Expand Down Expand Up @@ -467,22 +532,38 @@ typeface

// FontMgr
py::class_<SkFontStyleSet, sk_sp<SkFontStyleSet>, SkRefCnt>(m, "FontStyleSet")
.def("__getitem__", &SkFontStyleSet_getStyle, py::arg("index"))
.def("__len__", &SkFontStyleSet::count)
.def("__repr__",
[] (SkFontStyleSet& self) {
return py::str("FontStyleSet({})").format(self.count());
})
.def("count", &SkFontStyleSet::count)
.def("getStyle", &SkFontStyleSet::getStyle)
.def("createTypeface", &SkFontStyleSet::createTypeface)
.def("matchStyle", &SkFontStyleSet::matchStyle)
.def("getStyle", &SkFontStyleSet_getStyle, py::arg("index"))
.def("createTypeface", &SkFontStyleSet::createTypeface, py::arg("index"))
.def("matchStyle", &SkFontStyleSet::matchStyle, py::arg("pattern"))
.def_static("CreateEmpty", &SkFontStyleSet::CreateEmpty)
;

py::class_<SkFontMgr, sk_sp<SkFontMgr>, SkRefCnt>(m, "FontMgr")
py::class_<SkFontMgr, sk_sp<SkFontMgr>, SkRefCnt>(m, "FontMgr",
R"docstring(
Font manager that knows system fonts.
Example::
fontmgr = skia.FontMgr()
print(list(fontmgr))
familyName = fontmgr[0]
typeface = fontmgr.matchFamilyStyle(familyName, skia.FontStyle.Normal())
assert typeface is not None
)docstring")
.def(py::init([] () { return SkFontMgr::RefDefault(); }))
.def("__getitem__", &SkFontMgr_getFamilyName, py::arg("index"))
.def("__len__", &SkFontMgr::countFamilies)
.def("countFamilies", &SkFontMgr::countFamilies)
.def("getFamilyName",
[] (const SkFontMgr& fontmgr, int index) {
SkString familyName;
fontmgr.getFamilyName(index, &familyName);
return py::str(familyName.c_str(), familyName.size());
},
py::arg("index"))
.def("getFamilyName", &SkFontMgr_getFamilyName, py::arg("index"))
.def("createStyleSet",
[] (const SkFontMgr& fontmgr, int index) {
return sk_sp<SkFontStyleSet>(fontmgr.createStyleSet(index));
Expand Down Expand Up @@ -622,6 +703,12 @@ py::enum_<SkFont::Edging>(font, "Edging", R"docstring(
.export_values();

font
.def("__repr__",
[] (const SkFont& self) {
return py::str("Font({}, {}, {}, {})").format(
self.getTypefaceOrDefault(), self.getSize(), self.getScaleX(),
self.getSkewX());
})
.def(py::init<>(),
R"docstring(
Constructs :py:class:`Font` with default values.
Expand Down Expand Up @@ -1073,7 +1160,13 @@ font
:return: glyphs x-positions
)docstring",
py::arg("glyphs"), py::arg("origin") = 0)
.def("getPath", &SkFont::getPath,
.def("getPath",
[] (const SkFont& font, SkGlyphID glyphID) -> py::object {
SkPath path;
if (font.getPath(glyphID, &path))
return py::cast(path);
return py::none();
},
R"docstring(
Modifies path to be the outline of the glyph.
Expand All @@ -1083,11 +1176,33 @@ font
returns false and ignores path parameter.
:param int glyphID: index of glyph
:param skia.Path path: pointer to existing :py:class:`Path`
:return: true if glyphID is described by path
)docstring",
py::arg("glyphID"), py::arg("path"))
// .def("getPaths", &SkFont::getPaths)
py::arg("glyphID"))
.def("getPaths",
[] (const SkFont& font,
const std::vector<SkGlyphID>& glyphIDs) -> py::object {
std::vector<SkPath> paths;
paths.reserve(glyphIDs.size());
font.getPaths(
&glyphIDs[0],
glyphIDs.size(),
[] (const SkPath* pathOrNull, const SkMatrix& mx, void* ctx) {
auto paths_ = static_cast<std::vector<SkPath>*>(ctx);
if (pathOrNull)
paths_->push_back(*pathOrNull);
},
static_cast<void*>(&paths));
if (paths.empty())
return py::none();
return py::cast(paths);
},
R"docstring(
Returns path corresponding to glyph array.
:param glyphIDs: array of glyph indices
:return: list of :py:class:`Path`
)docstring")
.def("getMetrics",
[] (const SkFont& font) {
SkFontMetrics metrics;
Expand Down Expand Up @@ -1157,6 +1272,28 @@ py::enum_<SkFontMetrics::FontMetricsFlags>(fontmetrics, "FontMetricsFlags",

fontmetrics
.def(py::init<>())
.def("__repr__",
[] (const SkFontMetrics& self) {
std::stringstream stream;
stream << "FontMetrics("
<< "Flags=" << self.fFlags << ", "
<< "Top=" << self.fTop << ", "
<< "Ascent=" << self.fAscent << ", "
<< "Descent=" << self.fDescent << ", "
<< "Bottom=" << self.fBottom << ", "
<< "Leading=" << self.fLeading << ", "
<< "AvgCharWidth=" << self.fAvgCharWidth << ", "
<< "MaxCharWidth=" << self.fMaxCharWidth << ", "
<< "XMin=" << self.fXMin << ", "
<< "XMax=" << self.fXMax << ", "
<< "XHeight=" << self.fXHeight << ", "
<< "CapHeight=" << self.fCapHeight << ", "
<< "UnderlineThickness=" << self.fUnderlineThickness << ", "
<< "UnderlinePosition=" << self.fUnderlinePosition << ", "
<< "StrikeoutThickness=" << self.fStrikeoutThickness << ", "
<< "StrikeoutPosition=" << self.fStrikeoutPosition << ")";
return stream.str();
})
.def("hasUnderlineThickness", &SkFontMetrics::hasUnderlineThickness,
R"docstring(
Returns true if :py:class:`FontMetrics` has a valid underline thickness,
Expand Down
6 changes: 3 additions & 3 deletions src/skia/Point.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ py::class_<SkIPoint>(m, "IPoint", R"docstring(
.def("__iter__",
[] (const SkIPoint& p) {
return py::make_iterator(&p.fX, &p.fX + 2);
})
}, py::keep_alive<0, 1>())
.def("__len__", [] (const SkIPoint& p) { return 2; })
.def("__repr__",
[] (const SkIPoint& p) {
Expand Down Expand Up @@ -546,7 +546,7 @@ py::class_<SkPoint>(m, "Point", R"docstring(
.def("__iter__",
[] (const SkPoint& p) {
return py::make_iterator(&p.fX, &p.fX + 2);
})
}, py::keep_alive<0, 1>())
.def("__len__", [] (const SkPoint& p) { return 2; })
.def("__repr__",
[] (const SkPoint& p) {
Expand Down Expand Up @@ -665,7 +665,7 @@ py::class_<SkPoint3>(m, "Point3",
.def("__iter__",
[] (const SkPoint3& p) {
return py::make_iterator(&p.fX, &p.fX + 3);
})
}, py::keep_alive<0, 1>())
.def("__len__", [] (const SkPoint3& p) { return 3; })
.def("__repr__",
[] (const SkPoint3& p) {
Expand Down
Loading

0 comments on commit f5b5ee8

Please sign in to comment.