diff libass/ass_bitmap.c @ 34295:6e7f60f6f9d4

Update libass to 0.10 release. Patch by [subjunk gmail com], see bug #2008.
author reimar
date Sat, 03 Dec 2011 21:35:56 +0000
parents 88eebbbbd6a0
children c3aaaf17c721
line wrap: on
line diff
--- a/libass/ass_bitmap.c	Sat Dec 03 21:33:28 2011 +0000
+++ b/libass/ass_bitmap.c	Sat Dec 03 21:35:56 2011 +0000
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
+ * Copyright (C) 2011 Grigori Goronzy <greg@chown.ath.cx>
  *
  * This file is part of libass.
  *
@@ -22,6 +23,7 @@
 #include <assert.h>
 #include <ft2build.h>
 #include FT_GLYPH_H
+#include FT_OUTLINE_H
 
 #include "ass_utils.h"
 #include "ass_bitmap.h"
@@ -133,10 +135,12 @@
 static Bitmap *alloc_bitmap(int w, int h)
 {
     Bitmap *bm;
+    unsigned s = w; // XXX: alignment
     bm = malloc(sizeof(Bitmap));
-    bm->buffer = calloc(w, h);
+    bm->buffer = calloc(s, h);
     bm->w = w;
     bm->h = h;
+    bm->stride = s;
     bm->left = bm->top = 0;
     return bm;
 }
@@ -153,70 +157,57 @@
     Bitmap *dst = alloc_bitmap(src->w, src->h);
     dst->left = src->left;
     dst->top = src->top;
-    memcpy(dst->buffer, src->buffer, src->w * src->h);
+    memcpy(dst->buffer, src->buffer, src->stride * src->h);
     return dst;
 }
 
-int check_glyph_area(ASS_Library *library, FT_Glyph glyph)
+Bitmap *outline_to_bitmap(ASS_Library *library, FT_Library ftlib,
+                          FT_Outline *outline, int bord)
 {
-    FT_BBox bbox;
-    long long dx, dy;
-    FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &bbox);
-    dx = bbox.xMax - bbox.xMin;
-    dy = bbox.yMax - bbox.yMin;
-    if (dx * dy > 8000000) {
-        ass_msg(library, MSGL_WARN, "Glyph bounding box too large: %dx%dpx",
-               (int) dx, (int) dy);
-        return 1;
-    } else
-        return 0;
-}
-
-static Bitmap *glyph_to_bitmap_internal(ASS_Library *library,
-                                          FT_Glyph glyph, int bord)
-{
-    FT_BitmapGlyph bg;
-    FT_Bitmap *bit;
     Bitmap *bm;
     int w, h;
-    unsigned char *src;
-    unsigned char *dst;
-    int i;
     int error;
+    FT_BBox bbox;
+    FT_Bitmap bitmap;
 
-    if (check_glyph_area(library, glyph))
-        return 0;
-    error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 0);
-    if (error) {
-        ass_msg(library, MSGL_WARN, "FT_Glyph_To_Bitmap error %d",
-               error);
-        return 0;
+    FT_Outline_Get_CBox(outline, &bbox);
+    // move glyph to origin (0, 0)
+    bbox.xMin &= ~63;
+    bbox.yMin &= ~63;
+    FT_Outline_Translate(outline, -bbox.xMin, -bbox.yMin);
+    // bitmap size
+    bbox.xMax = (bbox.xMax + 63) & ~63;
+    bbox.yMax = (bbox.yMax + 63) & ~63;
+    w = (bbox.xMax - bbox.xMin) >> 6;
+    h = (bbox.yMax - bbox.yMin) >> 6;
+    // pen offset
+    bbox.xMin >>= 6;
+    bbox.yMax >>= 6;
+
+    if (w * h > 8000000) {
+        ass_msg(library, MSGL_WARN, "Glyph bounding box too large: %dx%dpx",
+                w, h);
+        return NULL;
     }
 
-    bg = (FT_BitmapGlyph) glyph;
-    bit = &(bg->bitmap);
-    if (bit->pixel_mode != FT_PIXEL_MODE_GRAY) {
-        ass_msg(library, MSGL_WARN, "Unsupported pixel mode: %d",
-               (int) (bit->pixel_mode));
-        FT_Done_Glyph(glyph);
-        return 0;
+    // allocate and set up bitmap
+    bm = alloc_bitmap(w + 2 * bord, h + 2 * bord);
+    bm->left = bbox.xMin - bord;
+    bm->top = -bbox.yMax - bord;
+    bitmap.width = w;
+    bitmap.rows = h;
+    bitmap.pitch = bm->stride;
+    bitmap.buffer = bm->buffer + bord + bm->stride * bord;
+    bitmap.num_grays = 256;
+    bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
+
+    // render into target bitmap
+    if ((error = FT_Outline_Get_Bitmap(ftlib, outline, &bitmap))) {
+        ass_msg(library, MSGL_WARN, "Failed to rasterize glyph: %d\n", error);
+        ass_free_bitmap(bm);
+        return NULL;
     }
 
-    w = bit->width;
-    h = bit->rows;
-    bm = alloc_bitmap(w + 2 * bord, h + 2 * bord);
-    bm->left = bg->left - bord;
-    bm->top = -bg->top - bord;
-
-    src = bit->buffer;
-    dst = bm->buffer + bord + bm->w * bord;
-    for (i = 0; i < h; ++i) {
-        memcpy(dst, src, w);
-        src += bit->pitch;
-        dst += bm->w;
-    }
-
-    FT_Done_Glyph(glyph);
     return bm;
 }
 
@@ -232,16 +223,16 @@
     const int l = bm_o->left > bm_g->left ? bm_o->left : bm_g->left;
     const int t = bm_o->top > bm_g->top ? bm_o->top : bm_g->top;
     const int r =
-        bm_o->left + bm_o->w <
-        bm_g->left + bm_g->w ? bm_o->left + bm_o->w : bm_g->left + bm_g->w;
+        bm_o->left + bm_o->stride <
+        bm_g->left + bm_g->stride ? bm_o->left + bm_o->stride : bm_g->left + bm_g->stride;
     const int b =
         bm_o->top + bm_o->h <
         bm_g->top + bm_g->h ? bm_o->top + bm_o->h : bm_g->top + bm_g->h;
 
     unsigned char *g =
-        bm_g->buffer + (t - bm_g->top) * bm_g->w + (l - bm_g->left);
+        bm_g->buffer + (t - bm_g->top) * bm_g->stride + (l - bm_g->left);
     unsigned char *o =
-        bm_o->buffer + (t - bm_o->top) * bm_o->w + (l - bm_o->left);
+        bm_o->buffer + (t - bm_o->top) * bm_o->stride + (l - bm_o->left);
 
     for (y = 0; y < b - t; ++y) {
         for (x = 0; x < r - l; ++x) {
@@ -250,8 +241,8 @@
             c_o = o[x];
             o[x] = (c_o > c_g) ? c_o - (c_g / 2) : 0;
         }
-        g += bm_g->w;
-        o += bm_o->w;
+        g += bm_g->stride;
+        o += bm_o->stride;
     }
 }
 
@@ -259,27 +250,30 @@
  * \brief Shift a bitmap by the fraction of a pixel in x and y direction
  * expressed in 26.6 fixed point
  */
-static void shift_bitmap(unsigned char *buf, int w, int h, int shift_x,
-                         int shift_y)
+static void shift_bitmap(Bitmap *bm, int shift_x, int shift_y)
 {
     int x, y, b;
+    int w = bm->w;
+    int h = bm->h;
+    int s = bm->stride;
+    unsigned char *buf = bm->buffer;
 
     // Shift in x direction
     if (shift_x > 0) {
         for (y = 0; y < h; y++) {
             for (x = w - 1; x > 0; x--) {
-                b = (buf[x + y * w - 1] * shift_x) >> 6;
-                buf[x + y * w - 1] -= b;
-                buf[x + y * w] += b;
+                b = (buf[x + y * s - 1] * shift_x) >> 6;
+                buf[x + y * s - 1] -= b;
+                buf[x + y * s] += b;
             }
         }
     } else if (shift_x < 0) {
         shift_x = -shift_x;
         for (y = 0; y < h; y++) {
             for (x = 0; x < w - 1; x++) {
-                b = (buf[x + y * w + 1] * shift_x) >> 6;
-                buf[x + y * w + 1] -= b;
-                buf[x + y * w] += b;
+                b = (buf[x + y * s + 1] * shift_x) >> 6;
+                buf[x + y * s + 1] -= b;
+                buf[x + y * s] += b;
             }
         }
     }
@@ -288,18 +282,18 @@
     if (shift_y > 0) {
         for (x = 0; x < w; x++) {
             for (y = h - 1; y > 0; y--) {
-                b = (buf[x + (y - 1) * w] * shift_y) >> 6;
-                buf[x + (y - 1) * w] -= b;
-                buf[x + y * w] += b;
+                b = (buf[x + (y - 1) * s] * shift_y) >> 6;
+                buf[x + (y - 1) * s] -= b;
+                buf[x + y * s] += b;
             }
         }
     } else if (shift_y < 0) {
         shift_y = -shift_y;
         for (x = 0; x < w; x++) {
             for (y = 0; y < h - 1; y++) {
-                b = (buf[x + (y + 1) * w] * shift_y) >> 6;
-                buf[x + (y + 1) * w] -= b;
-                buf[x + y * w] += b;
+                b = (buf[x + (y + 1) * s] * shift_y) >> 6;
+                buf[x + (y + 1) * s] -= b;
+                buf[x + y * s] += b;
             }
         }
     }
@@ -430,16 +424,20 @@
  * \brief Blur with [[1,2,1]. [2,4,2], [1,2,1]] kernel
  * This blur is the same as the one employed by vsfilter.
  */
-static void be_blur(unsigned char *buf, int w, int h)
+static void be_blur(Bitmap *bm)
 {
+    int w = bm->w;
+    int h = bm->h;
+    int s = bm->stride;
+    unsigned char *buf = bm->buffer;
     unsigned int x, y;
     unsigned int old_sum, new_sum;
 
     for (y = 0; y < h; y++) {
-        old_sum = 2 * buf[y * w];
+        old_sum = 2 * buf[y * s];
         for (x = 0; x < w - 1; x++) {
-            new_sum = buf[y * w + x] + buf[y * w + x + 1];
-            buf[y * w + x] = (old_sum + new_sum) >> 2;
+            new_sum = buf[y * s + x] + buf[y * s + x + 1];
+            buf[y * s + x] = (old_sum + new_sum) >> 2;
             old_sum = new_sum;
         }
     }
@@ -447,18 +445,18 @@
     for (x = 0; x < w; x++) {
         old_sum = 2 * buf[x];
         for (y = 0; y < h - 1; y++) {
-            new_sum = buf[y * w + x] + buf[(y + 1) * w + x];
-            buf[y * w + x] = (old_sum + new_sum) >> 2;
+            new_sum = buf[y * s + x] + buf[(y + 1) * s + x];
+            buf[y * s + x] = (old_sum + new_sum) >> 2;
             old_sum = new_sum;
         }
     }
 }
 
-int glyph_to_bitmap(ASS_Library *library, ASS_SynthPriv *priv_blur,
-                    FT_Glyph glyph, FT_Glyph outline_glyph,
-                    Bitmap **bm_g, Bitmap **bm_o, Bitmap **bm_s,
-                    int be, double blur_radius, FT_Vector shadow_offset,
-                    int border_style)
+int outline_to_bitmap3(ASS_Library *library, ASS_SynthPriv *priv_blur,
+                       FT_Library ftlib, FT_Outline *outline, FT_Outline *border,
+                       Bitmap **bm_g, Bitmap **bm_o, Bitmap **bm_s,
+                       int be, double blur_radius, FT_Vector shadow_offset,
+                       int border_style)
 {
     blur_radius *= 2;
     int bbord = be > 0 ? sqrt(2 * be) : 0;
@@ -471,13 +469,13 @@
 
     *bm_g = *bm_o = *bm_s = 0;
 
-    if (glyph)
-        *bm_g = glyph_to_bitmap_internal(library, glyph, bord);
+    if (outline)
+        *bm_g = outline_to_bitmap(library, ftlib, outline, bord);
     if (!*bm_g)
         return 1;
 
-    if (outline_glyph) {
-        *bm_o = glyph_to_bitmap_internal(library, outline_glyph, bord);
+    if (border) {
+        *bm_o = outline_to_bitmap(library, ftlib, border, bord);
         if (!*bm_o) {
             return 1;
         }
@@ -486,9 +484,9 @@
     // Apply box blur (multiple passes, if requested)
     while (be--) {
         if (*bm_o)
-            be_blur((*bm_o)->buffer, (*bm_o)->w, (*bm_o)->h);
+            be_blur(*bm_o);
         else
-            be_blur((*bm_g)->buffer, (*bm_g)->w, (*bm_g)->h);
+            be_blur(*bm_g);
     }
 
     // Apply gaussian blur
@@ -500,12 +498,12 @@
         generate_tables(priv_blur, blur_radius);
         if (*bm_o)
             ass_gauss_blur((*bm_o)->buffer, priv_blur->tmp,
-                           (*bm_o)->w, (*bm_o)->h, (*bm_o)->w,
+                           (*bm_o)->w, (*bm_o)->h, (*bm_o)->stride,
                            (int *) priv_blur->gt2, priv_blur->g_r,
                            priv_blur->g_w);
         else
             ass_gauss_blur((*bm_g)->buffer, priv_blur->tmp,
-                           (*bm_g)->w, (*bm_g)->h, (*bm_g)->w,
+                           (*bm_g)->w, (*bm_g)->h, (*bm_g)->stride,
                            (int *) priv_blur->gt2, priv_blur->g_r,
                            priv_blur->g_w);
     }
@@ -521,8 +519,7 @@
 
     assert(bm_s);
 
-    shift_bitmap((*bm_s)->buffer, (*bm_s)->w,(*bm_s)->h,
-                 shadow_offset.x, shadow_offset.y);
+    shift_bitmap(*bm_s, shadow_offset.x, shadow_offset.y);
 
     return 0;
 }