~ubuntu-branches/ubuntu/wily/python-imaging/wily

« back to all changes in this revision

Viewing changes to .pc/git-updates.diff/_imagingft.c

  • Committer: Package Import Robot
  • Author(s): Matthias Klose
  • Date: 2013-01-31 20:49:20 UTC
  • mfrom: (27.1.1 raring-proposed)
  • Revision ID: package-import@ubuntu.com-20130131204920-b5zshy6vgfvdionl
Tags: 1.1.7+1.7.8-1ubuntu1
Rewrite build dependencies to allow cross builds.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * PIL FreeType Driver
 
3
 *
 
4
 * a FreeType 2.X driver for PIL
 
5
 *
 
6
 * history:
 
7
 * 2001-02-17 fl  Created (based on old experimental freetype 1.0 code)
 
8
 * 2001-04-18 fl  Fixed some egcs compiler nits
 
9
 * 2002-11-08 fl  Added unicode support; more font metrics, etc
 
10
 * 2003-05-20 fl  Fixed compilation under 1.5.2 and newer non-unicode builds
 
11
 * 2003-09-27 fl  Added charmap encoding support
 
12
 * 2004-05-15 fl  Fixed compilation for FreeType 2.1.8
 
13
 * 2004-09-10 fl  Added support for monochrome bitmaps
 
14
 * 2006-06-18 fl  Fixed glyph bearing calculation
 
15
 * 2007-12-23 fl  Fixed crash in family/style attribute fetch
 
16
 * 2008-01-02 fl  Handle Unicode filenames properly
 
17
 *
 
18
 * Copyright (c) 1998-2007 by Secret Labs AB
 
19
 */
 
20
 
 
21
#include "Python.h"
 
22
#include "Imaging.h"
 
23
 
 
24
#if !defined(USE_FREETYPE_2_0)
 
25
/* undef/comment out to use freetype 2.0 */
 
26
#define USE_FREETYPE_2_1
 
27
#endif
 
28
 
 
29
#if defined(USE_FREETYPE_2_1)
 
30
/* freetype 2.1 and newer */
 
31
#include <ft2build.h>
 
32
#include FT_FREETYPE_H
 
33
#else
 
34
/* freetype 2.0 */
 
35
#include <freetype/freetype.h>
 
36
#endif
 
37
 
 
38
#if PY_VERSION_HEX < 0x01060000
 
39
#define PyObject_New PyObject_NEW
 
40
#define PyObject_Del PyMem_DEL
 
41
#endif
 
42
 
 
43
#if PY_VERSION_HEX >= 0x01060000
 
44
#if PY_VERSION_HEX  < 0x02020000 || defined(Py_USING_UNICODE)
 
45
/* defining this enables unicode support (default under 1.6a1 and later) */
 
46
#define HAVE_UNICODE
 
47
#endif
 
48
#endif
 
49
 
 
50
#if !defined(Py_RETURN_NONE)
 
51
#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
 
52
#endif
 
53
 
 
54
#if !defined(FT_LOAD_TARGET_MONO)
 
55
#define FT_LOAD_TARGET_MONO  FT_LOAD_MONOCHROME
 
56
#endif
 
57
 
 
58
/* -------------------------------------------------------------------- */
 
59
/* error table */
 
60
 
 
61
#undef FTERRORS_H
 
62
#undef __FTERRORS_H__
 
63
 
 
64
#define FT_ERRORDEF( e, v, s )  { e, s },
 
65
#define FT_ERROR_START_LIST  {
 
66
#define FT_ERROR_END_LIST    { 0, 0 } };
 
67
 
 
68
struct {
 
69
    int code;
 
70
    const char* message;
 
71
} ft_errors[] =
 
72
 
 
73
#include <freetype/fterrors.h>
 
74
 
 
75
/* -------------------------------------------------------------------- */
 
76
/* font objects */
 
77
 
 
78
static FT_Library library;
 
79
 
 
80
typedef struct {
 
81
    PyObject_HEAD
 
82
    FT_Face face;
 
83
} FontObject;
 
84
 
 
85
staticforward PyTypeObject Font_Type;
 
86
 
 
87
/* round a 26.6 pixel coordinate to the nearest larger integer */
 
88
#define PIXEL(x) ((((x)+63) & -64)>>6)
 
89
 
 
90
static PyObject*
 
91
geterror(int code)
 
92
{
 
93
    int i;
 
94
 
 
95
    for (i = 0; ft_errors[i].message; i++)
 
96
        if (ft_errors[i].code == code) {
 
97
            PyErr_SetString(PyExc_IOError, ft_errors[i].message);
 
98
            return NULL;
 
99
        }
 
100
 
 
101
    PyErr_SetString(PyExc_IOError, "unknown freetype error");
 
102
    return NULL;
 
103
}
 
104
 
 
105
static PyObject*
 
106
getfont(PyObject* self_, PyObject* args, PyObject* kw)
 
107
{
 
108
    /* create a font object from a file name and a size (in pixels) */
 
109
 
 
110
    FontObject* self;
 
111
    int error;
 
112
 
 
113
    char* filename;
 
114
    int size;
 
115
    int index = 0;
 
116
    unsigned char* encoding = NULL;
 
117
    static char* kwlist[] = {
 
118
        "filename", "size", "index", "encoding", NULL
 
119
    };
 
120
 
 
121
#if defined(HAVE_UNICODE) && PY_VERSION_HEX >= 0x02020000
 
122
    if (!PyArg_ParseTupleAndKeywords(args, kw, "eti|is", kwlist,
 
123
                                     Py_FileSystemDefaultEncoding, &filename,
 
124
                                     &size, &index, &encoding))
 
125
        return NULL;
 
126
#else
 
127
    if (!PyArg_ParseTupleAndKeywords(args, kw, "si|is", kwlist,
 
128
                                     &filename, &size, &index, &encoding))
 
129
        return NULL;
 
130
#endif
 
131
 
 
132
    if (!library) {
 
133
        PyErr_SetString(
 
134
            PyExc_IOError,
 
135
            "failed to initialize FreeType library"
 
136
            );
 
137
        return NULL;
 
138
    }
 
139
 
 
140
    self = PyObject_New(FontObject, &Font_Type);
 
141
    if (!self)
 
142
        return NULL;
 
143
 
 
144
    error = FT_New_Face(library, filename, index, &self->face);
 
145
 
 
146
    if (!error)
 
147
        error = FT_Set_Pixel_Sizes(self->face, 0, size);
 
148
 
 
149
    if (!error && encoding && strlen((char*) encoding) == 4) {
 
150
        FT_Encoding encoding_tag = FT_MAKE_TAG(
 
151
            encoding[0], encoding[1], encoding[2], encoding[3]
 
152
            );
 
153
        error = FT_Select_Charmap(self->face, encoding_tag);
 
154
    }
 
155
 
 
156
    if (error) {
 
157
        PyObject_Del(self);
 
158
        return geterror(error);
 
159
    }
 
160
 
 
161
    return (PyObject*) self;
 
162
}
 
163
    
 
164
static int
 
165
font_getchar(PyObject* string, int index, FT_ULong* char_out)
 
166
{
 
167
#if defined(HAVE_UNICODE)
 
168
    if (PyUnicode_Check(string)) {
 
169
        Py_UNICODE* p = PyUnicode_AS_UNICODE(string);
 
170
        int size = PyUnicode_GET_SIZE(string);
 
171
        if (index >= size)
 
172
            return 0;
 
173
        *char_out = p[index];
 
174
        return 1;
 
175
    }
 
176
#endif
 
177
    if (PyString_Check(string)) {
 
178
        unsigned char* p = (unsigned char*) PyString_AS_STRING(string);
 
179
        int size = PyString_GET_SIZE(string);
 
180
        if (index >= size)
 
181
            return 0;
 
182
        *char_out = (unsigned char) p[index];
 
183
        return 1;
 
184
    }
 
185
    return 0;
 
186
}
 
187
 
 
188
static PyObject*
 
189
font_getsize(FontObject* self, PyObject* args)
 
190
{
 
191
    int i, x;
 
192
    FT_ULong ch;
 
193
    FT_Face face;
 
194
    int xoffset;
 
195
    FT_Bool kerning = FT_HAS_KERNING(self->face);
 
196
    FT_UInt last_index = 0;
 
197
 
 
198
    /* calculate size and bearing for a given string */
 
199
 
 
200
    PyObject* string;
 
201
    if (!PyArg_ParseTuple(args, "O:getsize", &string))
 
202
        return NULL;
 
203
 
 
204
#if defined(HAVE_UNICODE)
 
205
    if (!PyUnicode_Check(string) && !PyString_Check(string)) {
 
206
#else
 
207
    if (!PyString_Check(string)) {
 
208
#endif
 
209
        PyErr_SetString(PyExc_TypeError, "expected string");
 
210
        return NULL;
 
211
    }
 
212
 
 
213
    face = NULL;
 
214
    xoffset = 0;
 
215
 
 
216
    for (x = i = 0; font_getchar(string, i, &ch); i++) {
 
217
        int index, error;
 
218
        face = self->face;
 
219
        index = FT_Get_Char_Index(face, ch);
 
220
        if (kerning && last_index && index) {
 
221
            FT_Vector delta;
 
222
            FT_Get_Kerning(self->face, last_index, index, ft_kerning_default,
 
223
                           &delta);
 
224
            x += delta.x;
 
225
        }
 
226
        error = FT_Load_Glyph(face, index, FT_LOAD_DEFAULT);
 
227
        if (error)
 
228
            return geterror(error);
 
229
        if (i == 0)
 
230
            xoffset = face->glyph->metrics.horiBearingX;
 
231
        x += face->glyph->metrics.horiAdvance;
 
232
        last_index = index;
 
233
    }
 
234
 
 
235
    if (face) {
 
236
        int offset;
 
237
        /* left bearing */
 
238
        if (xoffset < 0)
 
239
            x -= xoffset;
 
240
        else
 
241
            xoffset = 0;
 
242
        /* right bearing */
 
243
        offset = face->glyph->metrics.horiAdvance -
 
244
            face->glyph->metrics.width -
 
245
            face->glyph->metrics.horiBearingX;
 
246
        if (offset < 0)
 
247
            x -= offset;
 
248
    }
 
249
 
 
250
    return Py_BuildValue(
 
251
        "(ii)(ii)",
 
252
        PIXEL(x), PIXEL(self->face->size->metrics.height),
 
253
        PIXEL(xoffset), 0
 
254
        );
 
255
}
 
256
 
 
257
static PyObject*
 
258
font_getabc(FontObject* self, PyObject* args)
 
259
{
 
260
    FT_ULong ch;
 
261
    FT_Face face;
 
262
    double a, b, c;
 
263
 
 
264
    /* calculate ABC values for a given string */
 
265
 
 
266
    PyObject* string;
 
267
    if (!PyArg_ParseTuple(args, "O:getabc", &string))
 
268
        return NULL;
 
269
 
 
270
#if defined(HAVE_UNICODE)
 
271
    if (!PyUnicode_Check(string) && !PyString_Check(string)) {
 
272
#else
 
273
    if (!PyString_Check(string)) {
 
274
#endif
 
275
        PyErr_SetString(PyExc_TypeError, "expected string");
 
276
        return NULL;
 
277
    }
 
278
 
 
279
    if (font_getchar(string, 0, &ch)) {
 
280
        int index, error;
 
281
        face = self->face;
 
282
        index = FT_Get_Char_Index(face, ch);
 
283
        error = FT_Load_Glyph(face, index, FT_LOAD_DEFAULT);
 
284
        if (error)
 
285
            return geterror(error);
 
286
        a = face->glyph->metrics.horiBearingX / 64.0;
 
287
        b = face->glyph->metrics.width / 64.0;
 
288
        c = (face->glyph->metrics.horiAdvance - 
 
289
             face->glyph->metrics.horiBearingX -
 
290
             face->glyph->metrics.width) / 64.0;
 
291
    } else
 
292
        a = b = c = 0.0;
 
293
 
 
294
    return Py_BuildValue("ddd", a, b, c);
 
295
}
 
296
 
 
297
static PyObject*
 
298
font_render(FontObject* self, PyObject* args)
 
299
{
 
300
    int i, x, y;
 
301
    Imaging im;
 
302
    int index, error, ascender;
 
303
    int load_flags;
 
304
    unsigned char *source;
 
305
    FT_ULong ch;
 
306
    FT_GlyphSlot glyph;
 
307
    FT_Bool kerning = FT_HAS_KERNING(self->face);
 
308
    FT_UInt last_index = 0;
 
309
 
 
310
    /* render string into given buffer (the buffer *must* have
 
311
       the right size, or this will crash) */
 
312
    PyObject* string;
 
313
    long id;
 
314
    int mask = 0;
 
315
    if (!PyArg_ParseTuple(args, "Ol|i:render", &string, &id, &mask))
 
316
        return NULL;
 
317
 
 
318
#if defined(HAVE_UNICODE)
 
319
    if (!PyUnicode_Check(string) && !PyString_Check(string)) {
 
320
#else
 
321
    if (!PyString_Check(string)) {
 
322
#endif
 
323
        PyErr_SetString(PyExc_TypeError, "expected string");
 
324
        return NULL;
 
325
    }
 
326
 
 
327
    im = (Imaging) id;
 
328
 
 
329
    load_flags = FT_LOAD_RENDER;
 
330
    if (mask)
 
331
        load_flags |= FT_LOAD_TARGET_MONO;
 
332
 
 
333
    for (x = i = 0; font_getchar(string, i, &ch); i++) {
 
334
        if (i == 0 && self->face->glyph->metrics.horiBearingX < 0)
 
335
            x = -PIXEL(self->face->glyph->metrics.horiBearingX);
 
336
        index = FT_Get_Char_Index(self->face, ch);
 
337
        if (kerning && last_index && index) {
 
338
            FT_Vector delta;
 
339
            FT_Get_Kerning(self->face, last_index, index, ft_kerning_default,
 
340
                           &delta);
 
341
            x += delta.x >> 6;
 
342
        }
 
343
        error = FT_Load_Glyph(self->face, index, load_flags);
 
344
        if (error)
 
345
            return geterror(error);
 
346
        glyph = self->face->glyph;
 
347
        if (mask) {
 
348
            /* use monochrome mask (on palette images, etc) */
 
349
            int xx, x0, x1;
 
350
            source = (unsigned char*) glyph->bitmap.buffer;
 
351
            ascender = PIXEL(self->face->size->metrics.ascender);
 
352
            xx = x + glyph->bitmap_left;
 
353
            x0 = 0;
 
354
            x1 = glyph->bitmap.width;
 
355
            if (xx < 0)
 
356
                x0 = -xx;
 
357
            if (xx + x1 > im->xsize)
 
358
                x1 = im->xsize - xx;
 
359
            for (y = 0; y < glyph->bitmap.rows; y++) {
 
360
                int yy = y + ascender - glyph->bitmap_top;
 
361
                if (yy >= 0 && yy < im->ysize) {
 
362
                    /* blend this glyph into the buffer */
 
363
                    unsigned char *target = im->image8[yy] + xx;
 
364
                    int i, j, m = 128;
 
365
                    for (i = j = 0; j < x1; j++) {
 
366
                        if (j >= x0 && (source[i] & m))
 
367
                            target[j] = 255;
 
368
                        if (!(m >>= 1)) {
 
369
                            m = 128;
 
370
                            i++;
 
371
                        }
 
372
                    }
 
373
                }
 
374
                source += glyph->bitmap.pitch;
 
375
            }
 
376
        } else {
 
377
            /* use antialiased rendering */
 
378
            int xx, x0, x1;
 
379
            source = (unsigned char*) glyph->bitmap.buffer;
 
380
            ascender = PIXEL(self->face->size->metrics.ascender);
 
381
            xx = x + glyph->bitmap_left;
 
382
            x0 = 0;
 
383
            x1 = glyph->bitmap.width;
 
384
            if (xx < 0)
 
385
                x0 = -xx;
 
386
            if (xx + x1 > im->xsize)
 
387
                x1 = im->xsize - xx;
 
388
            for (y = 0; y < glyph->bitmap.rows; y++) {
 
389
                int yy = y + ascender - glyph->bitmap_top;
 
390
                if (yy >= 0 && yy < im->ysize) {
 
391
                    /* blend this glyph into the buffer */
 
392
                    int i;
 
393
                    unsigned char *target = im->image8[yy] + xx;
 
394
                    for (i = x0; i < x1; i++) {
 
395
                        if (target[i] < source[i])
 
396
                            target[i] = source[i];
 
397
                    }
 
398
                }
 
399
                source += glyph->bitmap.pitch;
 
400
            }
 
401
        }
 
402
        x += PIXEL(glyph->metrics.horiAdvance);
 
403
        last_index = index;
 
404
    }
 
405
 
 
406
    Py_RETURN_NONE;
 
407
}
 
408
 
 
409
static void
 
410
font_dealloc(FontObject* self)
 
411
{
 
412
    FT_Done_Face(self->face);
 
413
    PyObject_Del(self);
 
414
}
 
415
 
 
416
static PyMethodDef font_methods[] = {
 
417
    {"render", (PyCFunction) font_render, METH_VARARGS},
 
418
    {"getsize", (PyCFunction) font_getsize, METH_VARARGS},
 
419
    {"getabc", (PyCFunction) font_getabc, METH_VARARGS},
 
420
    {NULL, NULL}
 
421
};
 
422
 
 
423
static PyObject*  
 
424
font_getattr(FontObject* self, char* name)
 
425
{
 
426
    PyObject* res;
 
427
 
 
428
    res = Py_FindMethod(font_methods, (PyObject*) self, name);
 
429
 
 
430
    if (res)
 
431
        return res;
 
432
 
 
433
    PyErr_Clear();
 
434
 
 
435
    /* attributes */
 
436
    if (!strcmp(name, "family")) {
 
437
        if (self->face->family_name)
 
438
            return PyString_FromString(self->face->family_name);
 
439
        Py_RETURN_NONE;
 
440
    }
 
441
    if (!strcmp(name, "style")) {
 
442
        if (self->face->style_name)
 
443
            return PyString_FromString(self->face->style_name);
 
444
        Py_RETURN_NONE;
 
445
    }
 
446
    if (!strcmp(name, "ascent"))
 
447
        return PyInt_FromLong(PIXEL(self->face->size->metrics.ascender));
 
448
    if (!strcmp(name, "descent"))
 
449
        return PyInt_FromLong(-PIXEL(self->face->size->metrics.descender));
 
450
 
 
451
    if (!strcmp(name, "glyphs"))
 
452
        /* number of glyphs provided by this font */
 
453
        return PyInt_FromLong(self->face->num_glyphs);
 
454
 
 
455
    PyErr_SetString(PyExc_AttributeError, name);
 
456
    return NULL;
 
457
}
 
458
 
 
459
statichere PyTypeObject Font_Type = {
 
460
    PyObject_HEAD_INIT(NULL)
 
461
    0, "Font", sizeof(FontObject), 0,
 
462
    /* methods */
 
463
    (destructor)font_dealloc, /* tp_dealloc */
 
464
    0, /* tp_print */
 
465
    (getattrfunc)font_getattr, /* tp_getattr */
 
466
};
 
467
 
 
468
static PyMethodDef _functions[] = {
 
469
    {"getfont", (PyCFunction) getfont, METH_VARARGS|METH_KEYWORDS},
 
470
    {NULL, NULL}
 
471
};
 
472
 
 
473
DL_EXPORT(void)
 
474
init_imagingft(void)
 
475
{
 
476
    PyObject* m;
 
477
    PyObject* d;
 
478
    PyObject* v;
 
479
    int major, minor, patch;
 
480
 
 
481
    /* Patch object type */
 
482
    Font_Type.ob_type = &PyType_Type;
 
483
 
 
484
    m = Py_InitModule("_imagingft", _functions);
 
485
    d = PyModule_GetDict(m);
 
486
 
 
487
    if (FT_Init_FreeType(&library))
 
488
        return; /* leave it uninitalized */
 
489
 
 
490
    FT_Library_Version(library, &major, &minor, &patch);
 
491
 
 
492
#if PY_VERSION_HEX >= 0x02020000
 
493
    v = PyString_FromFormat("%d.%d.%d", major, minor, patch);
 
494
#else
 
495
    {
 
496
        char buffer[100];
 
497
        sprintf(buffer, "%d.%d.%d", major, minor, patch);
 
498
        v = PyString_FromString(buffer);
 
499
    }
 
500
#endif
 
501
    PyDict_SetItemString(d, "freetype2_version", v);
 
502
}