Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Generating Text Overlays and Compositing Images in C#

Tech 1

Dynamic image generation in C# relies on the System.Drawing namespace to handle typography rendering, bitmap scaling, and layered composition. The following implementation provides a structured approach to creating text-based bitmaps, resizing assets with high-quality interpolation, and merging foreground elements onto a background canvas.

Core Utility Implementation

The utility class encapsulates three primary operations: rendering string content to a bitmap, scaling an existing image, and overlaying a foreground image onto a background with precise positioning and optional framing.

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;

public static class ImageCompositionEngine
{
    public static Bitmap RenderTextToBitmap(string content, int pointSize, bool useBold = false)
    {
        int canvasWidth = 400;
        int canvasHeight = 200;

        FontStyle style = useBold ? FontStyle.Bold : FontStyle.Regular;
        using var typeface = new Font("Arial", pointSize, style);
        using var paintBrush = new SolidBrush(Color.Black);
        using var layoutFormat = new StringFormat(StringFormatFlags.NoClip)
        {
            Alignment = StringAlignment.Center,
            LineAlignment = StringAlignment.Center
        };

        var canvas = new Bitmap(canvasWidth, canvasHeight);
        using (var ctx = Graphics.FromImage(canvas))
        {
            ctx.Clear(Color.White);
            ctx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
            var bounds = new RectangleF(0, 0, canvasWidth, canvasHeight);
            ctx.DrawString(content, typeface, paintBrush, bounds, layoutFormat);
        }

        return canvas;
    }

    public static Bitmap ScaleBitmap(Image source, int targetWidth, int targetHeight)
    {
        var resized = new Bitmap(targetWidth, targetHeight);
        using var ctx = Graphics.FromImage(resized);
        ctx.InterpolationMode = InterpolationMode.HighQualityBicubic;
        ctx.PixelOffsetMode = PixelOffsetMode.HighQuality;
        ctx.CompositingQuality = CompositingQuality.HighQuality;

        var destRect = new Rectangle(0, 0, targetWidth, targetHeight);
        var srcRect = new Rectangle(0, 0, source.Width, source.Height);
        ctx.DrawImage(source, destRect, srcRect, GraphicsUnit.Pixel);

        return resized;
    }

    public static Bitmap OverlayImageOnBackground(Image background, Image foreground, int offsetX = 0, int offsetY = 0)
    {
        var composite = new Bitmap(background.Width, background.Height);
        using var ctx = Graphics.FromImage(composite);
        ctx.Clear(Color.Transparent);

        ctx.DrawImage(background, 0, 0, background.Width, background.Height);

        int posX = (background.Width / 2) - (foreground.Width / 2) + offsetX;
        int posY = (background.Height / 2) - (foreground.Height / 2) + offsetY;

        var borderRect = new Rectangle(posX - 1, posY - 1, foreground.Width + 2, foreground.Height + 2);
        ctx.FillRectangle(Brushes.White, borderRect);

        ctx.DrawImage(foreground, posX, posY, foreground.Width, foreground.Height);

        return composite;
    }
}

Execution Pipeline

Running the composition workflow involves initializing the base layer, optionally generating or resizing the overlay, and merging them with coordinate adjustments.

public void ExecuteCompositionPipeline()
{
    string bgPath = @"C:\assets\background.jpg";
    string fgPath = @"C:\assets\foreground.png";
    string outputPath = @"C:\output\final_composite.jpg";

    using var baseImage = Image.FromFile(bgPath);
    using var overlayImage = Image.FromFile(fgPath);

    // Alternative: Generate text layer dynamically
    // using var textLayer = ImageCompositionEngine.RenderTextToBitmap("X7K9 M2P4", 14, true);
    // using var scaledOverlay = ImageCompositionEngine.ScaleBitmap(textLayer, 200, 100);

    using var result = ImageCompositionEngine.OverlayImageOnBackground(baseImage, overlayImage, 0, -100);
    result.Save(outputPath, ImageFormat.Jpeg);
}

Technical Considerations

  • Unmanaged Resource Disposal: Graphics, Font, Brush, and Bitmap instances wrap GDI+ handles. Utilizing using declarations or explicit Dispose() calls prevents handle exhaustion in high-throughput scenarios.
  • Interpolation and Quality Flags: Scaling operations default to lower-quality algorithms for performance. Explicitly assigning InterpolationMode.HighQualityBicubic, PixelOffsetMode.HighQuality, and CompositingQuality.HighQuality eliminates jagged edges and preserves detail during resolution changes.
  • Coordinate Mathematics: Centering logic calculates the midpoint of the background and subtracts half the foreground dimensions. Applying offsets after this baseline calculasion ensures adjustments shift the element relative to the exact center rather than the origin.
  • Typography Rendering: Activating TextRenderingHint.AntiAlias smooths character edges. The StringFormat configuration with StringAlignment.Center for both horizontal and vertical axes guarantees precise text placement within the defined RectangleF bounds.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.