]> granicus.if.org Git - libass/blob - libass/ass_bitmap.c
Remove arbitrary bitmap size limit
[libass] / libass / ass_bitmap.c
1 /*
2  * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
3  * Copyright (C) 2011 Grigori Goronzy <greg@chown.ath.cx>
4  * Copyright (c) 2011-2014, Yu Zhuohuang <yuzhuohuang@qq.com>
5  *
6  * This file is part of libass.
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20
21 #include "config.h"
22 #include "ass_compat.h"
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <math.h>
27 #include <stdbool.h>
28 #include <assert.h>
29 #include <ft2build.h>
30 #include FT_GLYPH_H
31 #include FT_OUTLINE_H
32
33 #include "ass_utils.h"
34 #include "ass_bitmap.h"
35 #include "ass_render.h"
36
37
38 #define ALIGN           C_ALIGN_ORDER
39 #define DECORATE(func)  ass_##func##_c
40 #include "ass_func_template.h"
41 #undef ALIGN
42 #undef DECORATE
43
44 #if (defined(__i386__) || defined(__x86_64__)) && CONFIG_ASM
45
46 #define ALIGN           4
47 #define DECORATE(func)  ass_##func##_sse2
48 #include "ass_func_template.h"
49 #undef ALIGN
50 #undef DECORATE
51
52 #define ALIGN           5
53 #define DECORATE(func)  ass_##func##_avx2
54 #include "ass_func_template.h"
55 #undef ALIGN
56 #undef DECORATE
57
58 #endif
59
60
61 void ass_synth_blur(const BitmapEngine *engine, int opaque_box, int be,
62                     double blur_radius, Bitmap *bm_g, Bitmap *bm_o)
63 {
64     bool blur_g = !bm_o || opaque_box;
65     if (blur_g && !bm_g)
66         return;
67
68     // Apply gaussian blur
69     double r2 = blur_radius * blur_radius / log(256);
70     if (r2 > 0.001) {
71         if (bm_o)
72             ass_gaussian_blur(engine, bm_o, r2);
73         if (blur_g)
74             ass_gaussian_blur(engine, bm_g, r2);
75     }
76
77     // Apply box blur (multiple passes, if requested)
78     if (be) {
79         size_t size_o = 0, size_g = 0;
80         if (bm_o)
81             size_o = sizeof(uint16_t) * bm_o->stride * 2;
82         if (blur_g)
83             size_g = sizeof(uint16_t) * bm_g->stride * 2;
84         size_t size = FFMAX(size_o, size_g);
85         uint16_t *tmp = size ? ass_aligned_alloc(32, size, false) : NULL;
86         if (!tmp)
87             return;
88         if (bm_o) {
89             unsigned passes = be;
90             unsigned w = bm_o->w;
91             unsigned h = bm_o->h;
92             unsigned stride = bm_o->stride;
93             unsigned char *buf = bm_o->buffer;
94             if(w && h){
95                 if(passes > 1){
96                     be_blur_pre(buf, w, h, stride);
97                     while(--passes){
98                         memset(tmp, 0, stride * 2);
99                         engine->be_blur(buf, w, h, stride, tmp);
100                     }
101                     be_blur_post(buf, w, h, stride);
102                 }
103                 memset(tmp, 0, stride * 2);
104                 engine->be_blur(buf, w, h, stride, tmp);
105             }
106         }
107         if (blur_g) {
108             unsigned passes = be;
109             unsigned w = bm_g->w;
110             unsigned h = bm_g->h;
111             unsigned stride = bm_g->stride;
112             unsigned char *buf = bm_g->buffer;
113             if(w && h){
114                 if(passes > 1){
115                     be_blur_pre(buf, w, h, stride);
116                     while(--passes){
117                         memset(tmp, 0, stride * 2);
118                         engine->be_blur(buf, w, h, stride, tmp);
119                     }
120                     be_blur_post(buf, w, h, stride);
121                 }
122                 memset(tmp, 0, stride * 2);
123                 engine->be_blur(buf, w, h, stride, tmp);
124             }
125         }
126         ass_aligned_free(tmp);
127     }
128 }
129
130 static bool alloc_bitmap_buffer(const BitmapEngine *engine, Bitmap *bm, int w, int h,
131                                 bool zero)
132 {
133     unsigned align = 1 << engine->align_order;
134     size_t s = ass_align(align, w);
135     // Too often we use ints as offset for bitmaps => use INT_MAX.
136     if (s > (INT_MAX - 32) / FFMAX(h, 1))
137         return false;
138     uint8_t *buf = ass_aligned_alloc(align, s * h + 32, zero);
139     if (!buf)
140         return false;
141     bm->w = w;
142     bm->h = h;
143     bm->stride = s;
144     bm->buffer = buf;
145     return true;
146 }
147
148 Bitmap *alloc_bitmap(const BitmapEngine *engine, int w, int h, bool zero)
149 {
150     Bitmap *bm = malloc(sizeof(Bitmap));
151     if (!bm)
152         return NULL;
153     if (!alloc_bitmap_buffer(engine, bm, w, h, zero)) {
154         free(bm);
155         return NULL;
156     }
157     bm->left = bm->top = 0;
158     return bm;
159 }
160
161 bool realloc_bitmap(const BitmapEngine *engine, Bitmap *bm, int w, int h)
162 {
163     uint8_t *old = bm->buffer;
164     if (!alloc_bitmap_buffer(engine, bm, w, h, false))
165         return false;
166     ass_aligned_free(old);
167     return true;
168 }
169
170 void ass_free_bitmap(Bitmap *bm)
171 {
172     if (bm)
173         ass_aligned_free(bm->buffer);
174     free(bm);
175 }
176
177 Bitmap *copy_bitmap(const BitmapEngine *engine, const Bitmap *src)
178 {
179     Bitmap *dst = alloc_bitmap(engine, src->w, src->h, false);
180     if (!dst)
181         return NULL;
182     dst->left = src->left;
183     dst->top = src->top;
184     memcpy(dst->buffer, src->buffer, src->stride * src->h);
185     return dst;
186 }
187
188 #if CONFIG_RASTERIZER
189
190 Bitmap *outline_to_bitmap(ASS_Renderer *render_priv,
191                           ASS_Outline *outline, int bord)
192 {
193     RasterizerData *rst = &render_priv->rasterizer;
194     if (!rasterizer_set_outline(rst, outline)) {
195         ass_msg(render_priv->library, MSGL_WARN, "Failed to process glyph outline!\n");
196         return NULL;
197     }
198
199     if (bord < 0 || bord > INT_MAX / 2)
200         return NULL;
201
202     if (rst->x_min >= rst->x_max || rst->y_min >= rst->y_max) {
203         Bitmap *bm = alloc_bitmap(render_priv->engine, 2 * bord, 2 * bord, true);
204         if (!bm)
205             return NULL;
206         bm->left = bm->top = -bord;
207         return bm;
208     }
209
210     if (rst->x_max > INT_MAX - 63 || rst->y_max > INT_MAX - 63)
211         return NULL;
212
213     int x_min = rst->x_min >> 6;
214     int y_min = rst->y_min >> 6;
215     int x_max = (rst->x_max + 63) >> 6;
216     int y_max = (rst->y_max + 63) >> 6;
217     int w = x_max - x_min;
218     int h = y_max - y_min;
219
220     int mask = (1 << render_priv->engine->tile_order) - 1;
221
222     if (w < 0 || h < 0 ||
223         w > INT_MAX - (2 * bord + mask) || h > INT_MAX - (2 * bord + mask)) {
224         ass_msg(render_priv->library, MSGL_WARN, "Glyph bounding box too large: %dx%dpx",
225                 w, h);
226         return NULL;
227     }
228
229     int tile_w = (w + 2 * bord + mask) & ~mask;
230     int tile_h = (h + 2 * bord + mask) & ~mask;
231     Bitmap *bm = alloc_bitmap(render_priv->engine, tile_w, tile_h, false);
232     if (!bm)
233         return NULL;
234     bm->left = x_min - bord;
235     bm->top =  y_min - bord;
236
237     if (!rasterizer_fill(render_priv->engine, rst, bm->buffer,
238                          x_min - bord, y_min - bord,
239                          bm->stride, tile_h, bm->stride)) {
240         ass_msg(render_priv->library, MSGL_WARN, "Failed to rasterize glyph!\n");
241         ass_free_bitmap(bm);
242         return NULL;
243     }
244
245     return bm;
246 }
247
248 #else
249
250 static Bitmap *outline_to_bitmap_ft(ASS_Renderer *render_priv,
251                                     FT_Outline *outline, int bord)
252 {
253     Bitmap *bm;
254     int w, h;
255     int error;
256     FT_BBox bbox;
257     FT_Bitmap bitmap;
258
259     FT_Outline_Get_CBox(outline, &bbox);
260     if (bbox.xMin >= bbox.xMax || bbox.yMin >= bbox.yMax) {
261         bm = alloc_bitmap(render_priv->engine, 2 * bord, 2 * bord, true);
262         if (!bm)
263             return NULL;
264         bm->left = bm->top = -bord;
265         return bm;
266     }
267
268     // move glyph to origin (0, 0)
269     bbox.xMin &= ~63;
270     bbox.yMin &= ~63;
271     FT_Outline_Translate(outline, -bbox.xMin, -bbox.yMin);
272     if (bbox.xMax > INT_MAX - 63 || bbox.yMax > INT_MAX - 63)
273         return NULL;
274     // bitmap size
275     bbox.xMax = (bbox.xMax + 63) & ~63;
276     bbox.yMax = (bbox.yMax + 63) & ~63;
277     w = (bbox.xMax - bbox.xMin) >> 6;
278     h = (bbox.yMax - bbox.yMin) >> 6;
279     // pen offset
280     bbox.xMin >>= 6;
281     bbox.yMax >>= 6;
282
283     if (w < 0 || h < 0 ||
284         w > INT_MAX - 2 * bord || h > INT_MAX - 2 * bord) {
285         ass_msg(render_priv->library, MSGL_WARN, "Glyph bounding box too large: %dx%dpx",
286                 w, h);
287         return NULL;
288     }
289
290     // allocate and set up bitmap
291     bm = alloc_bitmap(render_priv->engine, w + 2 * bord, h + 2 * bord, true);
292     if (!bm)
293         return NULL;
294     bm->left = bbox.xMin - bord;
295     bm->top = -bbox.yMax - bord;
296     bitmap.width = w;
297     bitmap.rows = h;
298     bitmap.pitch = bm->stride;
299     bitmap.buffer = bm->buffer + bord + bm->stride * bord;
300     bitmap.num_grays = 256;
301     bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
302
303     // render into target bitmap
304     if ((error = FT_Outline_Get_Bitmap(render_priv->ftlibrary, outline, &bitmap))) {
305         ass_msg(render_priv->library, MSGL_WARN, "Failed to rasterize glyph: %d\n", error);
306         ass_free_bitmap(bm);
307         return NULL;
308     }
309
310     return bm;
311 }
312
313 Bitmap *outline_to_bitmap(ASS_Renderer *render_priv,
314                           ASS_Outline *outline, int bord)
315 {
316     size_t n_points = outline->n_points;
317     if (n_points > SHRT_MAX) {
318         ass_msg(render_priv->library, MSGL_WARN, "Too many outline points: %d",
319                 outline->n_points);
320         n_points = SHRT_MAX;
321     }
322
323     size_t n_contours = FFMIN(outline->n_contours, SHRT_MAX);
324     short contours_small[EFFICIENT_CONTOUR_COUNT];
325     short *contours = contours_small;
326     short *contours_large = NULL;
327     if (n_contours > EFFICIENT_CONTOUR_COUNT) {
328         contours_large = malloc(n_contours * sizeof(short));
329         if (!contours_large)
330             return NULL;
331         contours = contours_large;
332     }
333     for (size_t i = 0; i < n_contours; ++i)
334         contours[i] = FFMIN(outline->contours[i], n_points - 1);
335
336     FT_Outline ftol;
337     ftol.n_points = n_points;
338     ftol.n_contours = n_contours;
339     ftol.points = outline->points;
340     ftol.tags = outline->tags;
341     ftol.contours = contours;
342     ftol.flags = 0;
343
344     Bitmap *bm = outline_to_bitmap_ft(render_priv, &ftol, bord);
345     free(contours_large);
346     return bm;
347 }
348
349 #endif
350
351 /**
352  * \brief fix outline bitmap
353  *
354  * The glyph bitmap is subtracted from outline bitmap. This way looks much
355  * better in some cases.
356  */
357 void fix_outline(Bitmap *bm_g, Bitmap *bm_o)
358 {
359     int x, y;
360     const int l = bm_o->left > bm_g->left ? bm_o->left : bm_g->left;
361     const int t = bm_o->top > bm_g->top ? bm_o->top : bm_g->top;
362     const int r =
363         bm_o->left + bm_o->stride <
364         bm_g->left + bm_g->stride ? bm_o->left + bm_o->stride : bm_g->left + bm_g->stride;
365     const int b =
366         bm_o->top + bm_o->h <
367         bm_g->top + bm_g->h ? bm_o->top + bm_o->h : bm_g->top + bm_g->h;
368
369     unsigned char *g =
370         bm_g->buffer + (t - bm_g->top) * bm_g->stride + (l - bm_g->left);
371     unsigned char *o =
372         bm_o->buffer + (t - bm_o->top) * bm_o->stride + (l - bm_o->left);
373
374     for (y = 0; y < b - t; ++y) {
375         for (x = 0; x < r - l; ++x) {
376             unsigned char c_g, c_o;
377             c_g = g[x];
378             c_o = o[x];
379             o[x] = (c_o > c_g) ? c_o - (c_g / 2) : 0;
380         }
381         g += bm_g->stride;
382         o += bm_o->stride;
383     }
384 }
385
386 /**
387  * \brief Shift a bitmap by the fraction of a pixel in x and y direction
388  * expressed in 26.6 fixed point
389  */
390 void shift_bitmap(Bitmap *bm, int shift_x, int shift_y)
391 {
392     int x, y, b;
393     int w = bm->w;
394     int h = bm->h;
395     int s = bm->stride;
396     unsigned char *buf = bm->buffer;
397
398     assert((shift_x & ~63) == 0 && (shift_y & ~63) == 0);
399
400     // Shift in x direction
401     for (y = 0; y < h; y++) {
402         for (x = w - 1; x > 0; x--) {
403             b = (buf[x + y * s - 1] * shift_x) >> 6;
404             buf[x + y * s - 1] -= b;
405             buf[x + y * s] += b;
406         }
407     }
408
409     // Shift in y direction
410     for (x = 0; x < w; x++) {
411         for (y = h - 1; y > 0; y--) {
412             b = (buf[x + (y - 1) * s] * shift_y) >> 6;
413             buf[x + (y - 1) * s] -= b;
414             buf[x + y * s] += b;
415         }
416     }
417 }
418
419 /**
420  * \brief Blur with [[1,2,1], [2,4,2], [1,2,1]] kernel
421  * This blur is the same as the one employed by vsfilter.
422  * Pure C implementation.
423  */
424 void ass_be_blur_c(uint8_t *buf, intptr_t w, intptr_t h,
425                    intptr_t stride, uint16_t *tmp)
426 {
427     uint16_t *col_pix_buf = tmp;
428     uint16_t *col_sum_buf = tmp + w;
429     unsigned x, y, old_pix, old_sum, temp1, temp2;
430     uint8_t *src, *dst;
431     memset(tmp, 0, sizeof(uint16_t) * w * 2);
432     y = 0;
433
434     {
435         src=buf+y*stride;
436
437         x = 1;
438         old_pix = src[x-1];
439         old_sum = old_pix;
440         for ( ; x < w; x++) {
441             temp1 = src[x];
442             temp2 = old_pix + temp1;
443             old_pix = temp1;
444             temp1 = old_sum + temp2;
445             old_sum = temp2;
446             col_pix_buf[x-1] = temp1;
447             col_sum_buf[x-1] = temp1;
448         }
449         temp1 = old_sum + old_pix;
450         col_pix_buf[x-1] = temp1;
451         col_sum_buf[x-1] = temp1;
452     }
453
454     for (y++; y < h; y++) {
455         src=buf+y*stride;
456         dst=buf+(y-1)*stride;
457
458         x = 1;
459         old_pix = src[x-1];
460         old_sum = old_pix;
461         for ( ; x < w; x++) {
462             temp1 = src[x];
463             temp2 = old_pix + temp1;
464             old_pix = temp1;
465             temp1 = old_sum + temp2;
466             old_sum = temp2;
467
468             temp2 = col_pix_buf[x-1] + temp1;
469             col_pix_buf[x-1] = temp1;
470             dst[x-1] = (col_sum_buf[x-1] + temp2) >> 4;
471             col_sum_buf[x-1] = temp2;
472         }
473         temp1 = old_sum + old_pix;
474         temp2 = col_pix_buf[x-1] + temp1;
475         col_pix_buf[x-1] = temp1;
476         dst[x-1] = (col_sum_buf[x-1] + temp2) >> 4;
477         col_sum_buf[x-1] = temp2;
478     }
479
480     {
481         dst=buf+(y-1)*stride;
482         for (x = 0; x < w; x++)
483             dst[x] = (col_sum_buf[x] + col_pix_buf[x]) >> 4;
484     }
485 }
486
487 void be_blur_pre(uint8_t *buf, intptr_t w, intptr_t h, intptr_t stride)
488 {
489     for (int y = 0; y < h; ++y)
490     {
491         for (int x = 0; x < w; ++x)
492         {
493             // This is equivalent to (value * 64 + 127) / 255 for all
494             // values from 0 to 256 inclusive. Assist vectorizing
495             // compilers by noting that all temporaries fit in 8 bits.
496             buf[y * stride + x] =
497                 (uint8_t) ((buf[y * stride + x] >> 1) + 1) >> 1;
498         }
499     }
500 }
501
502 void be_blur_post(uint8_t *buf, intptr_t w, intptr_t h, intptr_t stride)
503 {
504     for (int y = 0; y < h; ++y)
505     {
506         for (int x = 0; x < w; ++x)
507         {
508             // This is equivalent to (value * 255 + 32) / 64 for all values
509             // from 0 to 96 inclusive, and we only care about 0 to 64.
510             uint8_t value = buf[y * stride + x];
511             buf[y * stride + x] = (value << 2) - (value > 32);
512         }
513     }
514 }
515
516 /*
517  * To find these values, simulate blur on the border between two
518  * half-planes, one zero-filled (background) and the other filled
519  * with the maximum supported value (foreground). Keep incrementing
520  * the \be argument. The necessary padding is the distance by which
521  * the blurred foreground image extends beyond the original border
522  * and into the background. Initially it increases along with \be,
523  * but very soon it grinds to a halt. At some point, the blurred
524  * image actually reaches a stationary point and stays unchanged
525  * forever after, simply _shifting_ by one pixel for each \be
526  * step--moving in the direction of the non-zero half-plane and
527  * thus decreasing the necessary padding (although the large
528  * padding is still needed for intermediate results). In practice,
529  * images are finite rather than infinite like half-planes, but
530  * this can only decrease the required padding. Half-planes filled
531  * with extreme values are the theoretical limit of the worst case.
532  * Make sure to use the right pixel value range in the simulation!
533  */
534 int be_padding(int be)
535 {
536     if (be <= 3)
537         return be;
538     if (be <= 7)
539         return 4;
540     if (be <= 123)
541         return 5;
542     return FFMAX(128 - be, 0);
543 }
544
545 int outline_to_bitmap2(ASS_Renderer *render_priv,
546                        ASS_Outline *outline, ASS_Outline *border,
547                        Bitmap **bm_g, Bitmap **bm_o)
548 {
549     assert(bm_g && bm_o);
550
551     *bm_g = *bm_o = NULL;
552
553     if (outline)
554         *bm_g = outline_to_bitmap(render_priv, outline, 1);
555     if (!*bm_g)
556         return 1;
557
558     if (border) {
559         *bm_o = outline_to_bitmap(render_priv, border, 1);
560         if (!*bm_o) {
561             return 1;
562         }
563     }
564
565     return 0;
566 }
567
568 /**
569  * \brief Add two bitmaps together at a given position
570  * Uses additive blending, clipped to [0,255]. Pure C implementation.
571  */
572 void ass_add_bitmaps_c(uint8_t *dst, intptr_t dst_stride,
573                        uint8_t *src, intptr_t src_stride,
574                        intptr_t height, intptr_t width)
575 {
576     unsigned out;
577     uint8_t* end = dst + dst_stride * height;
578     while (dst < end) {
579         for (unsigned j = 0; j < width; ++j) {
580             out = dst[j] + src[j];
581             dst[j] = FFMIN(out, 255);
582         }
583         dst += dst_stride;
584         src += src_stride;
585     }
586 }
587
588 void ass_sub_bitmaps_c(uint8_t *dst, intptr_t dst_stride,
589                        uint8_t *src, intptr_t src_stride,
590                        intptr_t height, intptr_t width)
591 {
592     short out;
593     uint8_t* end = dst + dst_stride * height;
594     while (dst < end) {
595         for (unsigned j = 0; j < width; ++j) {
596             out = dst[j] - src[j];
597             dst[j] = FFMAX(out, 0);
598         }
599         dst += dst_stride;
600         src += src_stride;
601     }
602 }
603
604 void ass_mul_bitmaps_c(uint8_t *dst, intptr_t dst_stride,
605                        uint8_t *src1, intptr_t src1_stride,
606                        uint8_t *src2, intptr_t src2_stride,
607                        intptr_t w, intptr_t h)
608 {
609     uint8_t* end = src1 + src1_stride * h;
610     while (src1 < end) {
611         for (unsigned x = 0; x < w; ++x) {
612             dst[x] = (src1[x] * src2[x] + 255) >> 8;
613         }
614         dst  += dst_stride;
615         src1 += src1_stride;
616         src2 += src2_stride;
617     }
618 }