mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-25 17:36:18 +03:00
use FT_Bitmap_Convert instead of reimplementing the wheel
This commit is contained in:
parent
55db572467
commit
bf529303de
122
src/_imagingft.c
122
src/_imagingft.c
|
@ -25,6 +25,7 @@
|
||||||
#include <ft2build.h>
|
#include <ft2build.h>
|
||||||
#include FT_FREETYPE_H
|
#include FT_FREETYPE_H
|
||||||
#include FT_GLYPH_H
|
#include FT_GLYPH_H
|
||||||
|
#include FT_BITMAP_H
|
||||||
#include FT_STROKER_H
|
#include FT_STROKER_H
|
||||||
#include FT_MULTIPLE_MASTERS_H
|
#include FT_MULTIPLE_MASTERS_H
|
||||||
#include FT_SFNT_NAMES_H
|
#include FT_SFNT_NAMES_H
|
||||||
|
@ -837,14 +838,17 @@ font_render(FontObject* self, PyObject* args)
|
||||||
FT_Glyph glyph;
|
FT_Glyph glyph;
|
||||||
FT_GlyphSlot glyph_slot;
|
FT_GlyphSlot glyph_slot;
|
||||||
FT_Bitmap bitmap;
|
FT_Bitmap bitmap;
|
||||||
|
FT_Bitmap bitmap_converted; /* initialized lazily, for non-8bpp fonts */
|
||||||
FT_BitmapGlyph bitmap_glyph;
|
FT_BitmapGlyph bitmap_glyph;
|
||||||
FT_Stroker stroker = NULL;
|
FT_Stroker stroker = NULL;
|
||||||
|
int bitmap_converted_ready = 0; /* has bitmap_converted been initialized */
|
||||||
GlyphInfo *glyph_info = NULL; /* computed text layout */
|
GlyphInfo *glyph_info = NULL; /* computed text layout */
|
||||||
size_t i, count; /* glyph_info index and length */
|
size_t i, count; /* glyph_info index and length */
|
||||||
int xx, yy; /* pixel offset of current glyph bitmap */
|
int xx, yy; /* pixel offset of current glyph bitmap */
|
||||||
int x0, x1; /* horizontal bounds of glyph bitmap to copy */
|
int x0, x1; /* horizontal bounds of glyph bitmap to copy */
|
||||||
unsigned int bitmap_y; /* glyph bitmap y index */
|
unsigned int bitmap_y; /* glyph bitmap y index */
|
||||||
unsigned char *source; /* glyph bitmap source buffer */
|
unsigned char *source; /* glyph bitmap source buffer */
|
||||||
|
unsigned char convert_scale; /* scale factor for non-8bpp bitmaps */
|
||||||
Imaging im;
|
Imaging im;
|
||||||
Py_ssize_t id;
|
Py_ssize_t id;
|
||||||
int horizontal_dir; /* is primary axis horizontal? */
|
int horizontal_dir; /* is primary axis horizontal? */
|
||||||
|
@ -980,6 +984,49 @@ font_render(FontObject* self, PyObject* args)
|
||||||
yy = -(py + glyph_slot->bitmap_top);
|
yy = -(py + glyph_slot->bitmap_top);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* convert non-8bpp bitmaps */
|
||||||
|
switch (bitmap.pixel_mode) {
|
||||||
|
case FT_PIXEL_MODE_MONO:
|
||||||
|
convert_scale = 255;
|
||||||
|
break;
|
||||||
|
case FT_PIXEL_MODE_GRAY2:
|
||||||
|
convert_scale = 255 / 3;
|
||||||
|
break;
|
||||||
|
case FT_PIXEL_MODE_GRAY4:
|
||||||
|
convert_scale = 255 / 15;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
convert_scale = 1;
|
||||||
|
}
|
||||||
|
switch (bitmap.pixel_mode) {
|
||||||
|
case FT_PIXEL_MODE_MONO:
|
||||||
|
case FT_PIXEL_MODE_GRAY2:
|
||||||
|
case FT_PIXEL_MODE_GRAY4:
|
||||||
|
if (!bitmap_converted_ready) {
|
||||||
|
FT_Bitmap_Init(&bitmap_converted);
|
||||||
|
bitmap_converted_ready = 1;
|
||||||
|
}
|
||||||
|
error = FT_Bitmap_Convert(library, &bitmap, &bitmap_converted, 1);
|
||||||
|
if (error) {
|
||||||
|
geterror(error);
|
||||||
|
goto glyph_error;
|
||||||
|
}
|
||||||
|
bitmap = bitmap_converted;
|
||||||
|
/* bitmap is now FT_PIXEL_MODE_GRAY, fall through */
|
||||||
|
case FT_PIXEL_MODE_GRAY:
|
||||||
|
break;
|
||||||
|
#ifdef FT_LOAD_COLOR
|
||||||
|
case FT_PIXEL_MODE_BGRA:
|
||||||
|
if (color) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* we didn't ask for color, fall through to default */
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
PyErr_SetString(PyExc_IOError, "unsupported bitmap pixel mode");
|
||||||
|
goto glyph_error;
|
||||||
|
}
|
||||||
|
|
||||||
/* clip glyph bitmap width to target image bounds */
|
/* clip glyph bitmap width to target image bounds */
|
||||||
x0 = 0;
|
x0 = 0;
|
||||||
x1 = bitmap.width;
|
x1 = bitmap.width;
|
||||||
|
@ -994,7 +1041,9 @@ font_render(FontObject* self, PyObject* args)
|
||||||
for (bitmap_y = 0; bitmap_y < bitmap.rows; bitmap_y++, yy++) {
|
for (bitmap_y = 0; bitmap_y < bitmap.rows; bitmap_y++, yy++) {
|
||||||
/* clip glyph bitmap height to target image bounds */
|
/* clip glyph bitmap height to target image bounds */
|
||||||
if (yy >= 0 && yy < im->ysize) {
|
if (yy >= 0 && yy < im->ysize) {
|
||||||
// blend this glyph into the buffer
|
/* blend this glyph into the buffer */
|
||||||
|
int k;
|
||||||
|
unsigned char v;
|
||||||
unsigned char* target;
|
unsigned char* target;
|
||||||
if (color) {
|
if (color) {
|
||||||
/* target[RGB] returns the color, target[A] returns the mask */
|
/* target[RGB] returns the color, target[A] returns the mask */
|
||||||
|
@ -1005,8 +1054,7 @@ font_render(FontObject* self, PyObject* args)
|
||||||
}
|
}
|
||||||
#ifdef FT_LOAD_COLOR
|
#ifdef FT_LOAD_COLOR
|
||||||
if (color && bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) {
|
if (color && bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) {
|
||||||
// paste color glyph
|
/* paste color glyph */
|
||||||
int k;
|
|
||||||
for (k = x0; k < x1; k++) {
|
for (k = x0; k < x1; k++) {
|
||||||
if (target[k * 4 + 3] < source[k * 4 + 3]) {
|
if (target[k * 4 + 3] < source[k * 4 + 3]) {
|
||||||
/* unpremultiply BGRa to RGBA */
|
/* unpremultiply BGRa to RGBA */
|
||||||
|
@ -1018,62 +1066,28 @@ font_render(FontObject* self, PyObject* args)
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
// handle 8bpp separately for performance
|
|
||||||
if (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) {
|
if (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) {
|
||||||
int k;
|
|
||||||
if (color) {
|
if (color) {
|
||||||
for (k = x0; k < x1; k++) {
|
for (k = x0; k < x1; k++) {
|
||||||
if (target[k * 4 + 3] < source[k]) {
|
v = source[k] * convert_scale;
|
||||||
target[k * 4 + 0] = (unsigned char) (foreground_ink);
|
|
||||||
target[k * 4 + 1] = (unsigned char) (foreground_ink >> 8);
|
|
||||||
target[k * 4 + 2] = (unsigned char) (foreground_ink >> 16);
|
|
||||||
target[k * 4 + 3] = source[k];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (k = x0; k < x1; k++) {
|
|
||||||
if (target[k] < source[k]) {
|
|
||||||
target[k] = source[k];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int k, v, m, a, b;
|
|
||||||
switch (bitmap.pixel_mode) {
|
|
||||||
case FT_PIXEL_MODE_MONO:
|
|
||||||
a = 3;
|
|
||||||
b = 7;
|
|
||||||
m = 0x80;
|
|
||||||
break;
|
|
||||||
case FT_PIXEL_MODE_GRAY2:
|
|
||||||
a = 2;
|
|
||||||
b = 3;
|
|
||||||
m = 0xC0;
|
|
||||||
break;
|
|
||||||
case FT_PIXEL_MODE_GRAY4:
|
|
||||||
a = 1;
|
|
||||||
b = 1;
|
|
||||||
m = 0xF0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
PyErr_SetString(PyExc_IOError, "unsupported bitmap pixel mode");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
for (k = x0; k < x1; k++) {
|
|
||||||
v = CLIP8(255 * ((source[k >> a] << (k & b)) & m) / m);
|
|
||||||
if (color) {
|
|
||||||
if (target[k * 4 + 3] < v) {
|
if (target[k * 4 + 3] < v) {
|
||||||
target[k * 4 + 0] = (unsigned char) foreground_ink;
|
target[k * 4 + 0] = (unsigned char)(foreground_ink);
|
||||||
target[k * 4 + 1] = (unsigned char) (foreground_ink >> 8);
|
target[k * 4 + 1] = (unsigned char)(foreground_ink >> 8);
|
||||||
target[k * 4 + 2] = (unsigned char) (foreground_ink >> 16);
|
target[k * 4 + 2] = (unsigned char)(foreground_ink >> 16);
|
||||||
target[k * 4 + 3] = v;
|
target[k * 4 + 3] = v;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
for (k = x0; k < x1; k++) {
|
||||||
|
v = source[k] * convert_scale;
|
||||||
if (target[k] < v) {
|
if (target[k] < v) {
|
||||||
target[k] = v;
|
target[k] = v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
PyErr_SetString(PyExc_IOError, "unsupported bitmap pixel mode");
|
||||||
|
goto glyph_error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
source += bitmap.pitch;
|
source += bitmap.pitch;
|
||||||
|
@ -1085,9 +1099,23 @@ font_render(FontObject* self, PyObject* args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bitmap_converted_ready) {
|
||||||
|
FT_Bitmap_Done(library, &bitmap_converted);
|
||||||
|
}
|
||||||
FT_Stroker_Done(stroker);
|
FT_Stroker_Done(stroker);
|
||||||
PyMem_Del(glyph_info);
|
PyMem_Del(glyph_info);
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
|
|
||||||
|
glyph_error:
|
||||||
|
if (stroker != NULL) {
|
||||||
|
FT_Done_Glyph(glyph);
|
||||||
|
}
|
||||||
|
if (bitmap_converted_ready) {
|
||||||
|
FT_Bitmap_Done(library, &bitmap_converted);
|
||||||
|
}
|
||||||
|
FT_Stroker_Done(stroker);
|
||||||
|
PyMem_Del(glyph_info);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FREETYPE_MAJOR > 2 ||\
|
#if FREETYPE_MAJOR > 2 ||\
|
||||||
|
|
Loading…
Reference in New Issue
Block a user