Beispiel #1
0
        /// <summary>
        /// Smoothing renderer for larger sizes. Does not gurantee sharp pixel edges, loses edges on small sizes
        /// This renderer will not cache its output
        /// </summary>
        public static void RenderSuperSampled(BitmapProxy img, float dx, float dy, float scale, Glyph glyph, bool inverted)
        {
            // Over-scale sizes. More y precision works well for latin glyphs
            const int xos = 2;
            const int yos = 3;

            // Render over-sized, then average back down
            var workspace = BresenhamEdgeRasteriser.Rasterise(glyph, scale * xos, scale * yos);
            var height    = workspace.Height / yos;
            var width     = workspace.Width / xos;
            var baseline  = workspace.Baseline;
            var leftShift = workspace.Shift;

            baseline /= yos;
            baseline += 1; // account for Y overrun in our sampling

            var data = workspace.Data;
            var w    = workspace.Width;
            var w2   = 2 * workspace.Width;
            var w3   = 3 * workspace.Width;
            var w4   = 4 * workspace.Width;

            for (int y = 0; y < height - 1; y++)
            {
                var sy = y * yos * w;

                for (int x = 0; x < width - 1; x++)
                {
                    var sx = x * xos;
                    int v;
                    v  = data[sy + sx] & BresenhamEdgeRasteriser.Inside;     // based on `INSIDE` == 1
                    v += data[sy + sx + 1] & BresenhamEdgeRasteriser.Inside;
                    v += data[sy + w + sx] & BresenhamEdgeRasteriser.Inside;
                    v += data[sy + w + sx + 1] & BresenhamEdgeRasteriser.Inside;
                    v += data[sy + w2 + sx] & BresenhamEdgeRasteriser.Inside;
                    v += data[sy + w2 + sx + 1] & BresenhamEdgeRasteriser.Inside;

                    // slightly over-run in Y to smooth slopes further. The `ScanlineRasteriser` adds some buffer space for this
                    v += data[sy + w3 + sx] & BresenhamEdgeRasteriser.Inside;
                    v += data[sy + w3 + sx + 1] & BresenhamEdgeRasteriser.Inside;
                    v += data[sy + w4 + sx] & BresenhamEdgeRasteriser.Inside;
                    v += data[sy + w4 + sx + 1] & BresenhamEdgeRasteriser.Inside;

                    if (v == 0)
                    {
                        continue;
                    }
                    v *= 255 / 10;

                    if (inverted)
                    {
                        v = 255 - v;
                    }

                    img.SetPixel((int)(dx + x - leftShift), (int)(dy - y - baseline), v, v, v);
                }
            }
        }
Beispiel #2
0
 /// <summary>
 /// Draw a single glyph, picking a renderer based on size
 /// </summary>
 public static void DrawGlyph(BitmapProxy img, float dx, float dy, float scale, Glyph glyph, bool inverted)
 {
     try
     {
         if (scale <= 0.03f) // Optimised for smaller sizes
         {
             RenderSubPixel_RGB_Super3(img, dx, dy, scale, glyph, inverted);
         }
         else // Optimised for larger sizes
         {
             RenderSuperSampled(img, dx, dy, scale, glyph, inverted);
         }
     }
     catch (ArgumentOutOfRangeException)
     {
         // tried to write off the end of the img
     }
 }
Beispiel #3
0
        /// <summary>
        /// Render small font sizes with a super-sampling sub-pixel algorithm. Super-samples only in the x direction.
        /// This renderer may cache its output
        /// </summary>
        public static void RenderSubPixel_RGB_Super3(BitmapProxy img, float dx, float dy, float scale, Glyph glyph, bool inverted)
        {
            if (glyph == null)
            {
                throw new ArgumentNullException(nameof(glyph));
            }
            const int bright = 17;

            float leftShift;
            float baseline;

            int[] table;
            int   height;
            int   width;

            var cacheKey = glyph.SourceCharacter + scale + glyph.SourceFont;

            if (RenderCache.ContainsKey(cacheKey))
            {
                var ce = RenderCache[cacheKey];
                table     = ce.Table;
                width     = ce.Width;
                height    = ce.Height;
                leftShift = ce.LeftShift;
                baseline  = ce.Baseline;
            }
            else
            {
                var workspace = BresenhamEdgeRasteriser.Rasterise(glyph, scale * 3, scale);
                height    = workspace.Height;
                width     = workspace.Width / 3;
                baseline  = workspace.Baseline;
                leftShift = workspace.Shift;

                if (baseline * baseline < 1)
                {
                    baseline = 0;
                }

                var topsFlag = BresenhamEdgeRasteriser.DirRight | BresenhamEdgeRasteriser.DirLeft | BresenhamEdgeRasteriser.Dropout;

                var data      = workspace.Data;
                var w         = workspace.Width;
                var tableSize = width * height;

                // Not cached: Build the RGB table for the char
                table = new int[tableSize];
                for (int y = 0; y < height; y++)
                {
                    var yBase = y * w;
                    var yout  = y * width;
                    for (int x = 0; x < width; x++)
                    {
                        var r = 0;
                        var g = 0;
                        var b = 0;
                        // ReSharper disable JoinDeclarationAndInitializer
                        int tops, ins, left, right;
                        // ReSharper restore JoinDeclarationAndInitializer

                        var _1 = data[yBase + x * 3];
                        var _2 = data[yBase + x * 3 + 1];
                        var _3 = data[yBase + x * 3 + 2];

                        // first try the simple case of all pixels in:
                        if (
                            (_1 & BresenhamEdgeRasteriser.Inside) > 0 &&
                            (_2 & BresenhamEdgeRasteriser.Inside) > 0 &&
                            (_3 & BresenhamEdgeRasteriser.Inside) > 0
                            )
                        {
                            table[yout + x] = 0xffffff;
                            continue;
                        }
                        var topS  = 3;
                        var insS  = 5;
                        var sideS = 3;

                        var flag = _1;
                        tops  = (flag & topsFlag) > 0 ? topS : 0;
                        ins   = (flag & BresenhamEdgeRasteriser.Inside) > 0 ? insS : 0;
                        left  = (flag & BresenhamEdgeRasteriser.DirUp) > 0 ? sideS : 0;
                        right = (flag & BresenhamEdgeRasteriser.DirDown) > 0 ? sideS : 0;
                        if (ins > 0 || left > 0 || right > 0)
                        {
                            tops = 0;
                        }

                        b += tops + ins + (left * 2);
                        g += tops + ins + (left) + (right);
                        r += tops + ins + (right * 2);

                        flag  = _2;
                        tops  = (flag & topsFlag) > 0 ? topS : 0;
                        ins   = (flag & BresenhamEdgeRasteriser.Inside) > 0 ? insS : 0;
                        left  = (flag & BresenhamEdgeRasteriser.DirUp) > 0 ? sideS : 0;
                        right = (flag & BresenhamEdgeRasteriser.DirDown) > 0 ? sideS : 0;
                        if (ins > 0 || left > 0 || right > 0)
                        {
                            tops = 0;
                        }

                        b += tops + ins + (left * 2);
                        g += tops + ins + (left) + (right);
                        r += tops + ins + (right * 2);

                        flag  = _3;
                        tops  = (flag & topsFlag) > 0 ? topS : 0;
                        ins   = (flag & BresenhamEdgeRasteriser.Inside) > 0 ? insS : 0;
                        left  = (flag & BresenhamEdgeRasteriser.DirUp) > 0 ? sideS : 0;
                        right = (flag & BresenhamEdgeRasteriser.DirDown) > 0 ? sideS : 0;
                        if (ins > 0 || left > 0 || right > 0)
                        {
                            tops = 0;
                        }

                        b += tops + ins + (left * 2);
                        g += tops + ins + left + right;
                        r += tops + ins + (right * 2);

                        r *= bright;
                        g *= bright;
                        b *= bright;

                        Saturate(ref r, ref g, ref b);

                        table[yout + x] = (r << 16) + (g << 8) + b;
                    }
                }

                // add to cache
                var entry = new RenderCacheEntry {
                    Width     = width,
                    Height    = height,
                    Baseline  = baseline,
                    LeftShift = leftShift,
                    Table     = table
                };
                if (RenderCache.ContainsKey(cacheKey))
                {
                    RenderCache[cacheKey] = entry;
                }
                else
                {
                    RenderCache.Add(cacheKey, entry);
                }
            }

            // Stupid way to keep the cache smallish:
            if (RenderCache.Count > 100)
            {
                RenderCache.Clear();
            }

            // now render the table to an image
            for (int y = 0; y < height; y++)
            {
                var yBase = y * width;
                for (int x = 0; x < width; x++)
                {
                    int c = table[yBase + x];

                    if (c == 0)
                    {
                        continue;
                    }

                    int r = (c & 0xff0000) >> 16;
                    int g = (c & 0x00ff00) >> 8;
                    int b = (c & 0x0000ff);

                    if (inverted)
                    {
                        r = 255 - r;
                        g = 255 - g;
                        b = 255 - b;
                    }

                    img.SetPixel((int)(dx + x - leftShift), (int)(dy - y - baseline), r, g, b);
                }
            }
        }