mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-25 17:36:18 +03:00
fix text clipping due to rounding
(cherry picked from commit 35500aad08fb18a904f326df2ce8c59ae6413801)
This commit is contained in:
parent
e3450d1f6e
commit
5d57261b9c
199
src/_imagingft.c
199
src/_imagingft.c
|
@ -612,7 +612,7 @@ font_getsize(FontObject* self, PyObject* args)
|
||||||
int position, advanced;
|
int position, advanced;
|
||||||
int x_max, x_min, y_max, y_min;
|
int x_max, x_min, y_max, y_min;
|
||||||
FT_Face face;
|
FT_Face face;
|
||||||
int xoffset, yoffset;
|
int x_anchor, y_anchor;
|
||||||
int horizontal_dir;
|
int horizontal_dir;
|
||||||
int mask = 0;
|
int mask = 0;
|
||||||
int load_flags;
|
int load_flags;
|
||||||
|
@ -621,6 +621,7 @@ font_getsize(FontObject* self, PyObject* args)
|
||||||
size_t i, count;
|
size_t i, count;
|
||||||
GlyphInfo *glyph_info = NULL;
|
GlyphInfo *glyph_info = NULL;
|
||||||
PyObject *features = Py_None;
|
PyObject *features = Py_None;
|
||||||
|
FT_Vector pen;
|
||||||
|
|
||||||
/* calculate size and bearing for a given string */
|
/* calculate size and bearing for a given string */
|
||||||
|
|
||||||
|
@ -643,6 +644,29 @@ font_getsize(FontObject* self, PyObject* args)
|
||||||
FT_Glyph glyph;
|
FT_Glyph glyph;
|
||||||
face = self->face;
|
face = self->face;
|
||||||
index = glyph_info[i].index;
|
index = glyph_info[i].index;
|
||||||
|
|
||||||
|
if (horizontal_dir) {
|
||||||
|
pen.x = position + glyph_info[i].x_offset;
|
||||||
|
pen.y = glyph_info[i].y_offset;
|
||||||
|
|
||||||
|
position += glyph_info[i].x_advance;
|
||||||
|
advanced = PIXEL(position);
|
||||||
|
if (advanced > x_max) {
|
||||||
|
x_max = advanced;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pen.x = glyph_info[i].x_offset;
|
||||||
|
pen.y = position + glyph_info[i].y_offset;
|
||||||
|
|
||||||
|
position += glyph_info[i].y_advance;
|
||||||
|
advanced = PIXEL(position);
|
||||||
|
if (advanced < y_min) {
|
||||||
|
y_min = advanced;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_Set_Transform(face, NULL, &pen);
|
||||||
|
|
||||||
/* Note: bitmap fonts within ttf fonts do not work, see #891/pr#960
|
/* Note: bitmap fonts within ttf fonts do not work, see #891/pr#960
|
||||||
* Yifu Yu<root@jackyyf.com>, 2014-10-15
|
* Yifu Yu<root@jackyyf.com>, 2014-10-15
|
||||||
*/
|
*/
|
||||||
|
@ -655,74 +679,24 @@ font_getsize(FontObject* self, PyObject* args)
|
||||||
return geterror(error);
|
return geterror(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
FT_Get_Glyph(face->glyph, &glyph);
|
error = FT_Get_Glyph(face->glyph, &glyph);
|
||||||
FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_SUBPIXELS, &bbox);
|
if (error) {
|
||||||
if (horizontal_dir) {
|
return geterror(error);
|
||||||
// adjust start position if glyph bearing extends before origin
|
}
|
||||||
offset = position + face->glyph->metrics.horiBearingX + glyph_info[i].x_offset;
|
|
||||||
if (offset < x_min) {
|
|
||||||
x_min = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
position += glyph_info[i].x_advance;
|
|
||||||
advanced = position;
|
|
||||||
|
|
||||||
// adjust glyph end position if bearing extends past advanced point
|
FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_PIXELS, &bbox);
|
||||||
offset = glyph_info[i].x_advance -
|
|
||||||
glyph_info[i].x_offset -
|
|
||||||
face->glyph->metrics.horiBearingX -
|
|
||||||
face->glyph->metrics.width;
|
|
||||||
if (offset < 0) {
|
|
||||||
advanced -= offset;
|
|
||||||
}
|
|
||||||
if (advanced > x_max) {
|
|
||||||
x_max = advanced;
|
|
||||||
}
|
|
||||||
|
|
||||||
bbox.yMax += glyph_info[i].y_offset;
|
if (bbox.xMax > x_max) {
|
||||||
bbox.yMin += glyph_info[i].y_offset;
|
x_max = bbox.xMax;
|
||||||
if (bbox.yMax > y_max) {
|
}
|
||||||
y_max = bbox.yMax;
|
if (bbox.xMin < x_min) {
|
||||||
}
|
x_min = bbox.xMin;
|
||||||
if (bbox.yMin < y_min) {
|
}
|
||||||
y_min = bbox.yMin;
|
if (bbox.yMax > y_max) {
|
||||||
}
|
y_max = bbox.yMax;
|
||||||
} else {
|
}
|
||||||
// NOTE: harfbuzz (called from raqm) assumes that we are using horizontal
|
if (bbox.yMin < y_min) {
|
||||||
// bearings even for vertical text and adjusts offsets to compensate as follows:
|
y_min = bbox.yMin;
|
||||||
// hb-ft.cc: hb_ft_get_glyph_v_origin():
|
|
||||||
// x_offset += horiBearingX - vertBearingX;
|
|
||||||
// y_offset += horiBearingY - (-vertBearingY);
|
|
||||||
|
|
||||||
// adjust start position if glyph bearing extends before origin
|
|
||||||
offset = position + face->glyph->metrics.horiBearingY + glyph_info[i].y_offset;
|
|
||||||
if (offset > y_max) {
|
|
||||||
y_max = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
position += glyph_info[i].y_advance;
|
|
||||||
advanced = position;
|
|
||||||
|
|
||||||
// adjust glyph end position if bearing extends past advanced point
|
|
||||||
offset = glyph_info[i].y_advance -
|
|
||||||
glyph_info[i].y_offset -
|
|
||||||
face->glyph->metrics.horiBearingY +
|
|
||||||
face->glyph->metrics.height;
|
|
||||||
if (offset > 0) {
|
|
||||||
advanced -= offset;
|
|
||||||
}
|
|
||||||
if (advanced < y_min) {
|
|
||||||
y_min = advanced;
|
|
||||||
}
|
|
||||||
|
|
||||||
bbox.xMax += glyph_info[i].x_offset;
|
|
||||||
bbox.xMin += glyph_info[i].x_offset;
|
|
||||||
if (bbox.xMax > x_max) {
|
|
||||||
x_max = bbox.xMax;
|
|
||||||
}
|
|
||||||
if (bbox.xMin < x_min) {
|
|
||||||
x_min = bbox.xMin;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FT_Done_Glyph(glyph);
|
FT_Done_Glyph(glyph);
|
||||||
|
@ -733,21 +707,23 @@ font_getsize(FontObject* self, PyObject* args)
|
||||||
glyph_info = NULL;
|
glyph_info = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
x_anchor = y_anchor = 0;
|
||||||
if (face) {
|
if (face) {
|
||||||
|
FT_Set_Transform(face, NULL, NULL);
|
||||||
if (horizontal_dir) {
|
if (horizontal_dir) {
|
||||||
xoffset = 0;
|
x_anchor = 0;
|
||||||
yoffset = self->face->size->metrics.ascender - y_max;
|
y_anchor = PIXEL(self->face->size->metrics.ascender);
|
||||||
} else {
|
} else {
|
||||||
xoffset = 0;
|
x_anchor = x_min;
|
||||||
yoffset = -y_max;
|
y_anchor = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Py_BuildValue(
|
return Py_BuildValue(
|
||||||
"(ii)(ii)",
|
"(ii)(ii)",
|
||||||
PIXEL(x_max - x_min), PIXEL(y_max - y_min),
|
(x_max - x_min), (y_max - y_min),
|
||||||
PIXEL(xoffset), PIXEL(yoffset)
|
(-x_anchor + x_min), -(-y_anchor + y_max)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
|
@ -777,6 +753,7 @@ font_render(FontObject* self, PyObject* args)
|
||||||
size_t i, count;
|
size_t i, count;
|
||||||
GlyphInfo *glyph_info;
|
GlyphInfo *glyph_info;
|
||||||
PyObject *features = NULL;
|
PyObject *features = NULL;
|
||||||
|
FT_Vector pen;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "On|izOzi:render", &string, &id, &mask, &dir, &features, &lang,
|
if (!PyArg_ParseTuple(args, "On|izOzi:render", &string, &id, &mask, &dir, &features, &lang,
|
||||||
&stroke_width)) {
|
&stroke_width)) {
|
||||||
|
@ -808,10 +785,15 @@ font_render(FontObject* self, PyObject* args)
|
||||||
load_flags |= FT_LOAD_TARGET_MONO;
|
load_flags |= FT_LOAD_TARGET_MONO;
|
||||||
}
|
}
|
||||||
|
|
||||||
x = y = baseline = offset = 0;
|
pen.x = pen.y = x = y = baseline = offset = 0;
|
||||||
horizontal_dir = (dir && strcmp(dir, "ttb") == 0) ? 0 : 1;
|
horizontal_dir = (dir && strcmp(dir, "ttb") == 0) ? 0 : 1;
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
index = glyph_info[i].index;
|
index = glyph_info[i].index;
|
||||||
|
|
||||||
|
pen.x = x + glyph_info[i].x_offset;
|
||||||
|
pen.y = y + glyph_info[i].y_offset;
|
||||||
|
FT_Set_Transform(self->face, NULL, &pen);
|
||||||
|
|
||||||
error = FT_Load_Glyph(self->face, index, load_flags | FT_LOAD_RENDER);
|
error = FT_Load_Glyph(self->face, index, load_flags | FT_LOAD_RENDER);
|
||||||
if (error) {
|
if (error) {
|
||||||
return geterror(error);
|
return geterror(error);
|
||||||
|
@ -822,40 +804,30 @@ font_render(FontObject* self, PyObject* args)
|
||||||
|
|
||||||
// compute baseline and adjust start position if glyph bearing extends before origin
|
// compute baseline and adjust start position if glyph bearing extends before origin
|
||||||
if (horizontal_dir) {
|
if (horizontal_dir) {
|
||||||
temp = glyph_slot->metrics.horiBearingY + glyph_info[i].y_offset;
|
if (glyph_slot->bitmap_top > baseline) {
|
||||||
if (temp > baseline) {
|
baseline = glyph_slot->bitmap_top;
|
||||||
baseline = temp;
|
|
||||||
}
|
}
|
||||||
|
if (glyph_slot->bitmap_left < offset) {
|
||||||
temp = x + glyph_slot->metrics.horiBearingX + glyph_info[i].x_offset;
|
offset = glyph_slot->bitmap_left;
|
||||||
if (temp < offset) {
|
|
||||||
offset = temp;
|
|
||||||
}
|
}
|
||||||
x += glyph_info[i].x_advance;
|
x += glyph_info[i].x_advance;
|
||||||
} else {
|
} else {
|
||||||
// NOTE: harfbuzz (called from raqm) assumes that we are using horizontal
|
if (glyph_slot->bitmap_top > offset) {
|
||||||
// bearings even for vertical text and adjusts offsets to compensate as follows:
|
offset = glyph_slot->bitmap_top;
|
||||||
// hb-ft.cc: hb_ft_get_glyph_v_origin():
|
|
||||||
// x_offset += horiBearingX - vertBearingX;
|
|
||||||
// y_offset += horiBearingY - (-vertBearingY);
|
|
||||||
|
|
||||||
temp = -(glyph_slot->metrics.horiBearingX + glyph_info[i].x_offset);
|
|
||||||
if (temp > baseline) {
|
|
||||||
baseline = temp;
|
|
||||||
}
|
}
|
||||||
|
if (glyph_slot->bitmap_left < baseline) {
|
||||||
temp = y + glyph_slot->metrics.horiBearingY + glyph_info[i].y_offset;
|
baseline = glyph_slot->bitmap_left;
|
||||||
if (temp > offset) {
|
|
||||||
offset = temp;
|
|
||||||
}
|
}
|
||||||
y += glyph_info[i].y_advance;
|
y += glyph_info[i].y_advance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (horizontal_dir) {
|
if (horizontal_dir) {
|
||||||
x = -offset;
|
x = (-offset + stroke_width) * 64;
|
||||||
|
y = (-baseline + (-stroke_width)) * 64;
|
||||||
} else {
|
} else {
|
||||||
y = -offset;
|
x = (-baseline + stroke_width) * 64;
|
||||||
|
y = (-offset + (-stroke_width)) * 64;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stroker == NULL) {
|
if (stroker == NULL) {
|
||||||
|
@ -864,6 +836,11 @@ font_render(FontObject* self, PyObject* args)
|
||||||
|
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
index = glyph_info[i].index;
|
index = glyph_info[i].index;
|
||||||
|
|
||||||
|
pen.x = x + glyph_info[i].x_offset;
|
||||||
|
pen.y = y + glyph_info[i].y_offset;
|
||||||
|
FT_Set_Transform(self->face, NULL, &pen);
|
||||||
|
|
||||||
error = FT_Load_Glyph(self->face, index, load_flags);
|
error = FT_Load_Glyph(self->face, index, load_flags);
|
||||||
if (error) {
|
if (error) {
|
||||||
return geterror(error);
|
return geterror(error);
|
||||||
|
@ -886,19 +863,12 @@ font_render(FontObject* self, PyObject* args)
|
||||||
bitmap_glyph = (FT_BitmapGlyph)glyph;
|
bitmap_glyph = (FT_BitmapGlyph)glyph;
|
||||||
|
|
||||||
bitmap = bitmap_glyph->bitmap;
|
bitmap = bitmap_glyph->bitmap;
|
||||||
|
xx = bitmap_glyph->left;
|
||||||
|
yy = -bitmap_glyph->top;
|
||||||
} else {
|
} else {
|
||||||
bitmap = glyph_slot->bitmap;
|
bitmap = glyph_slot->bitmap;
|
||||||
}
|
xx = glyph_slot->bitmap_left;
|
||||||
|
yy = -glyph_slot->bitmap_top;
|
||||||
// NOTE: harfbuzz (called from raqm) assumes that we are using horizontal
|
|
||||||
// bearings even for vertical text and adjusts offsets to compensate as follows:
|
|
||||||
// hb-ft.cc: hb_ft_get_glyph_v_origin():
|
|
||||||
// x_offset += horiBearingX - vertBearingX;
|
|
||||||
// y_offset += horiBearingY - (-vertBearingY);
|
|
||||||
if (horizontal_dir) {
|
|
||||||
xx = PIXEL(x + glyph_slot->metrics.horiBearingX + glyph_info[i].x_offset);
|
|
||||||
} else {
|
|
||||||
xx = PIXEL(baseline + glyph_slot->metrics.horiBearingX + glyph_info[i].x_offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
x0 = 0;
|
x0 = 0;
|
||||||
|
@ -911,17 +881,7 @@ font_render(FontObject* self, PyObject* args)
|
||||||
}
|
}
|
||||||
|
|
||||||
source = (unsigned char*) bitmap.buffer;
|
source = (unsigned char*) bitmap.buffer;
|
||||||
for (bitmap_y = 0; bitmap_y < bitmap.rows; bitmap_y++) {
|
for (bitmap_y = 0; bitmap_y < bitmap.rows; bitmap_y++, yy++) {
|
||||||
// NOTE: harfbuzz (called from raqm) assumes that we are using horizontal
|
|
||||||
// bearings even for vertical text and adjusts offsets to compensate as follows:
|
|
||||||
// hb-ft.cc: hb_ft_get_glyph_v_origin():
|
|
||||||
// x_offset += horiBearingX - vertBearingX;
|
|
||||||
// y_offset += horiBearingY - (-vertBearingY);
|
|
||||||
if (horizontal_dir) {
|
|
||||||
yy = PIXEL(baseline - glyph_slot->metrics.horiBearingY - glyph_info[i].y_offset) + bitmap_y;
|
|
||||||
} else {
|
|
||||||
yy = PIXEL(-(y + glyph_slot->metrics.horiBearingY + glyph_info[i].y_offset)) + bitmap_y;
|
|
||||||
}
|
|
||||||
if (yy >= 0 && yy < im->ysize) {
|
if (yy >= 0 && yy < im->ysize) {
|
||||||
// blend this glyph into the buffer
|
// blend this glyph into the buffer
|
||||||
unsigned char *target = im->image8[yy] + xx;
|
unsigned char *target = im->image8[yy] + xx;
|
||||||
|
@ -956,6 +916,7 @@ font_render(FontObject* self, PyObject* args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FT_Set_Transform(self->face, NULL, NULL);
|
||||||
FT_Stroker_Done(stroker);
|
FT_Stroker_Done(stroker);
|
||||||
PyMem_Del(glyph_info);
|
PyMem_Del(glyph_info);
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user