Skip to content

Conversation

@Fahad-Alsaidi
Copy link
Contributor

This pull request adds support for languages that require complex text layout.

We are using the Raqm library, that wraps FriBidi (for bidirectional
text support) and HarfBuzz (for text shaping), and does proper BiDi and script
itemization:
https://github.com/HOST-Oman/libraqm

This should fix #1089, #2255

@andreymal

.travis.yml Outdated
- 3.4
- nightly

sudo: required # needed for trusty beta

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t think this is needed anymore, see https://docs.travis-ci.com/user/trusty-ci-environment/.

@Fahad-Alsaidi Fahad-Alsaidi force-pushed the CTL branch 2 times, most recently from 38969d5 to d5b8434 Compare December 13, 2016 07:01
@Fahad-Alsaidi
Copy link
Contributor Author

Finally, passed all tests. I welcome any feedback.

Copy link
Member

@hugovk hugovk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for getting this all passing!

It might be good to squash some of these later commits.

I don't think it's a problem, especially as 12.04 is at end-of-life next April, but it's worth noting this swaps Precise (12.04.5 LTS) for Trusty (14.04.5 LTS).

Do we need to mention the Noto fonts' licence if we include NotoNastaliqUrdu-Regular.ttf in the test suite? Details on the SIL Open Font License (OFL) v1 here: https://github.com/googlei18n/noto-fonts

.travis.yml Outdated
# Then run the remainder.
python:
- "pypy"
- "pypy-5.3.1"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please could you include a comment to say why PyPy is pinned to 5.3.1?

Copy link
Contributor Author

@Fahad-Alsaidi Fahad-Alsaidi Dec 14, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since switching to Trusty, the default version of PyPy in Trusty is PyPy 5.4.1. There is a known error in it: TypeError: PyPy does not yet implement the new buffer interface (issue #2163).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Fahad-Alsaidi That looks good (I've edited it slightly). Please could you add it as a comment in .travis.yml, above - "pypy-5.3.1"?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we've got one test that is failing on a specific version of pypy, we should document that at the test and skip it for just that version. We've done it before, and recently.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wiredfool but the test not related to adding CTL support. Is it fine to edit that test or you may edit later?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That can be a separate PR, and note that it has to be merged prior to this one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wiredfool done

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed via PR #2294.

except (KeyError, ImportError):
class TestImagecomplextext(PillowTestCase):
def test_skip(self):
self.skipTest("KeyError")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's have a more descriptive skip message (because it could be ImportError rather than KeyError).

FREETYPE_ROOT = None
LCMS_ROOT = None

RAQM_ROOT = None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can delete the empty newline above this to bring these all together.


if feature.want('raqm'):
if _find_include_file(self, "raqm.h"):
if _find_library_file(self, "raqm") and \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can these two if be a single if with an extra and?

_imagingft.c Outdated
yoffset = face->glyph->metrics.horiBearingY;

last_index = index;
//last_index = index;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this line isn't needed, delete it.


count = 0;
while (font_getchar(string, count, &ch))
count++;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add brackets for while.


load_flags = FT_LOAD_RENDER|FT_LOAD_NO_BITMAP;
if (mask)
load_flags |= FT_LOAD_TARGET_MONO;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add brackets for if.

_imagingft.c Outdated

static size_t
text_layout(PyObject* string, FontObject* self, const char* dir,
PyObject *features ,GlyphInfo **glyph_info, int mask);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space after comma, not before.

glyph_info = NULL;
count = text_layout(string, self, dir, features, &glyph_info, mask);
if (count == 0)
return NULL;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add brackets for if.

PyObject *features = NULL;

if (!PyArg_ParseTuple(args, "On|izO:render", &string, &id, &mask, &dir, &features))
return NULL;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add brackets for if.

@wiredfool
Copy link
Member

I've done a quick review of this PR. In general, this covers most of the issues that I had with the initial PR.

I'm still concerned with the dependency on the not well known library raqm, especially on platforms other than Ubuntu Trusty.

  • Documentation is still too sparse:
    • There are three new libraries, only one is mentioned.
    • The parameter values for direction and features are unspecified.
  • depends/* needs to be touched up and tested where possible.
  • I think that the text_layout function should be broken up into two implementations, text_layout_raqm and text_layout_[something else] and use a #ifdef in text_layout to delegate to one or the other. Furthermore, I think splitting out text_layout_raqm to a separate source file makes sense to minimize the implementation specific changes to _imagingft.
  • There are a lot of places where you've got PY_VERSION_HEX #ifdefs. Check to see if the definitions in py3.h cover the use cases. If they don't, maybe we should look at that.

@khaledhosny
Copy link

I'm still concerned with the dependency on the not well known library raqm, especially on platforms other than Ubuntu Trusty.

The alternative would be to roll your own solution (not essentially a bad thing, but more code for your to maintain) or depend on large package with even larger dependencies like Pango (again not essentially bad, if you can afford Pango then it is indeed the more mature and featureful choice).

@Fahad-Alsaidi
Copy link
Contributor Author

@wiredfool

There are three new libraries, only one is mentioned.

what is the right place to mention them?

The parameter values for direction and features are unspecified.

I hope now they are clear, if not please give me a guideline.

depends/* needs to be touched up and tested where possible.

I update all files but need testing at least in FreeBSD & Fedora. BTW, Fedora have already a package for libraqm.

I think that the text_layout function should be broken up into two implementations, text_layout_raqm and text_layout_[something else] and use a #ifdef in text_layout to delegate to one or the other. Furthermore, I think splitting out text_layout_raqm to a separate source file makes sense to minimize the implementation specific changes to _imagingft.

I spite text_layout to two implementations as you request but I don't think it is needed to put it to a separate file.

There are a lot of places where you've got PY_VERSION_HEX #ifdefs. Check to see if the definitions in py3.h cover the use cases. If they don't, maybe we should look at that.

I really need help in this point.

@hugovk I did all modifications as requested. Please review.

.travis.yml Outdated
# Then run the remainder.
python:
- "pypy"
- "pypy-5.3.1"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That can be a separate PR, and note that it has to be merged prior to this one.

"tkinter": "PIL._imagingtk",
"freetype2": "PIL._imagingft",
"littlecms2": "PIL._imagingcms",
"raqm": "PIL._imagingft",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is going to trigger on raqm being available when it's not compiled in but freetype is.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when I delete it, all builds fails the error is

Traceback (most recent call last):
  File "selftest.py", line 184, in <module>
    supported = features.check_module(name)
  File "build\bdist.win-amd64\egg\PIL\features.py", line 15, in check_module
ValueError: Unknown module raqm

from PIL import ImageFont

# check if raqm is available
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be a way to check if raqm is installed. As it stands, if there is an error that triggers an import error on ImageFont, then this whole set of tests are going to get skipped.

There are version flags for several of the libraries, that would be something to add to _imagingft.c, potentially for all three libraries, but at least raqm.

RAQM_DIRECTION_LTR,
RAQM_DIRECTION_TTB
} raqm_direction_t;
#endif
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't look like this is ever used outside of the HAVE_RAQM #ifdef

if (!PyArg_ParseTuple(args, "O:getsize", &string))
return NULL;

if (features != Py_None || dir != NULL) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This caveat needs to make it into the documentation

#

sudo add-apt-repository -y ppa:as-bahanta/raqm
sudo apt-get update
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is extraneous with the ./install_raqm line below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is needed it to install a required harfbuzz version for raqm.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't work with the version in trusty?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed now.



if [ ! -f raqm-0.2.0.tar.gz ]; then
wget -O 'raqm-0.2.0.tar.gz' 'https://github.com/HOST-Oman/libraqm/releases/download/v0.2.0/raqm-0.2.0.tar.gz?raw=true'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should add a PR to add this to our depends repo.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so it is unlikely to work with any Python prior to 3.5 on Windows.

* **libraqm** provides complex text layout support.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to mention the other libraries. Also, below there are build flags that need to be updated.

the number of pixels between lines.
:param align: If the text is passed on to multiline_text(),
"left", "center" or "right".
:param direction: Direction of the text. It can be 'rtl', 'ltr', 'ttb' or 'btt'.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs a Requires raqm note here, and all similar locations.

class pil_build_ext(build_ext):
class feature:
features = ['zlib', 'jpeg', 'tiff', 'freetype', 'lcms', 'webp',
features = ['zlib', 'jpeg', 'tiff', 'freetype', 'raqm', 'lcms', 'webp',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to filter and error if raqm is requested and freetype is either not found or disabled.

@wiredfool
Copy link
Member

Libraries should be mentioned in docs/installation.rst. It should be clear from the discussion there what libraries we rely on, as well as filling in the examples that are there. There are also the build flags that need to be updated.

Do you know what the status of the dependencies are on Windows and OSX?

@wiredfool
Copy link
Member

@hugovk We do need to mention the licence for the font somewhere.

PIL/ImageDraw.py Outdated
return self.multiline_text(xy, text, fill, font, anchor,
*args, **kwargs)

return self.multiline_text(xy, text, fill, font, anchor, *args, **kwargs)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pep8

@wiredfool
Copy link
Member

Closed, merged with #2576

Thanks to everyone who worked on this, I think it's a valuable addition to the library.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug in rendering Indic fonts

7 participants