Image and Merge field

Hi,

We have an issue rendering an image from database into a pdf using word template. The output image on pdf comes out blurry and distorted.

On the word template the merge field is defined as <Image:Customer.CompanyLogo>.

CompanyLogo property in class Customer is defined as public byte[] CompanyLogo
{
    get;
    set;
}

We have a scaling logic in place which scales the original image (saved in the database) and assigns the scaled bytes to CompanyLogo property. Here is the code snippet

public byte[] GenerateScaledFirmLogoBytes(byte[] firmLogoBytes)
{
    byte[] scaledImageBytes = null;
    Image scaledImage = this.GenerateScaledFirmLogoImage(firmLogoBytes);

    if (scaledImage != null)
    {
        ImageConverter imageConverter = new ImageConverter();
        scaledImageBytes = (byte[]) imageConverter.ConvertTo(scaledImage, typeof(byte[]));
    }
    return scaledImageBytes;
}

public Image GenerateScaledFirmLogoImage(byte[] firmLogoBytes)
{
    Image scaledImage = null;
    try
    {
        if (firmLogoBytes != null)
        {
            using(MemoryStream ms = new MemoryStream(firmLogoBytes))
            {
                Image oldImage = Image.FromStream(ms);
                this.Scale(oldImage.Width, oldImage.Height);

                Bitmap bitmap = new Bitmap((int) this.ScaledWidth, (int) this.ScaledHeight);

                using(Graphics g = Graphics.FromImage(bitmap))
                {
                    g.CompositingQuality = CompositingQuality.HighQuality;
                    g.SmoothingMode = SmoothingMode.HighQuality;
                    g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    Rectangle rc = new Rectangle(0, 0, (int) this.ScaledWidth, (int) this.ScaledHeight);
                    g.DrawImage(oldImage, rc);
                    g.Dispose();
                }
                scaledImage = (Image) bitmap;
            }
        }
    }
    catch (Exception ex)
    {
        Otive.Log.Error("[ImageScaler][GenerateScaledFirmLogoImage] Error scaling logo");
        Otive.Log.Error(ex);
    }
    return scaledImage;
}

I am attaching the original image that is uploaded to the database and the screenshot of the output on pdf.

Thanks,
Gaurav

Hello,
Thank you for your request.
Maybe you should try to resize an image differently. Please look the following code:

class Program
{
    static void Main()
    {
        License lic = new License();
        lic.SetLicense("Aspose.Words.lic");
        Document doc = new Document();
        // Create a document builder to insert content with into document.
        DocumentBuilder builder = new DocumentBuilder(doc);
        builder.MoveToDocumentStart();
        builder.InsertImage("X:\\original.png");
        ShapeVisitor visitor = new ShapeVisitor();
        doc.Accept(visitor);
        doc.Save("X:\\out.doc", SaveFormat.Doc);
        doc.Save("X:\\out.pdf", SaveFormat.Pdf);
    }
}

public class ShapeVisitor: DocumentVisitor
{
    ///
    /// Called when a Shape node is encountered in the document.
    ///
    public override VisitorAction VisitShapeStart(Shape shape)
    {
        if (shape.HasImage)
        {
            // Reduce the size of image to 50%
            shape.Height *= .5;
            shape.Width *= .5;
        }
        // Let the visitor continue visiting other nodes.
        return VisitorAction.Continue;
    }
}

I would like to offer you another variant of code, which will reduce your image in percentage.

internal class Program
{
    private static void Main(string[] args)
    {
        var license = new License();
        license.SetLicense("Aspose.Words.lic");
        Document doc = new Document();
        doc.MailMerge.FieldMergingCallback = new HandleMergeImageFieldFromBlob();
        DocumentBuilder builder = new DocumentBuilder(doc);
        builder.InsertField("MERGEFIELD Image:ReducedImage");
        FileStream fs = new FileStream("X:\\original.png", FileMode.Open);
        byte[] imageData = new byte[fs.Length];
        fs.Read(imageData, 0, Convert.ToInt32(fs.Length));
        fs.Close();
        // Field values are inserted into the mail merge fields found in the document.
        doc.MailMerge.Execute(new string[]
        {
            "ReducedImage"
        }, new object[]
        {
            imageData
        });
        doc.UpdateFields();
        doc.Save("X:\\out.docx", SaveFormat.Docx);
        doc.Save("X:\\out.pdf", SaveFormat.Pdf);
    }
}
public class HandleMergeImageFieldFromBlob: IFieldMergingCallback
{
    void IFieldMergingCallback.FieldMerging(FieldMergingArgs args)
    {
        // Do nothing.
    }
    ///
    /// This is called when mail merge engine encounters Image:XXX merge field in the document.
    /// You have a chance to return an Image object, file name or a stream that contains the image.
    ///
    void IFieldMergingCallback.ImageFieldMerging(ImageFieldMergingArgs e)
    {
        ImageResize imageResize = new ImageResize();
        Image image = imageResize.ByteArrayToImage((byte[]) e.FieldValue);
        // Reducing image to 50%
        image = imageResize.ScaleByPercentage(image, 50);
        byte[] array = imageResize.ImageToByteArray(image);
        // The field value is a byte array, just cast it and create a stream on it.
        MemoryStream imageStream = new MemoryStream(array);
        // Now the mail merge engine will retrieve the image from the stream.
        e.ImageStream = imageStream;
    }
}
public class ImageResize
{
    public ImageResize()
    {}
    // Conver byte array to Image
    public Image ByteArrayToImage(byte[] byteArray)
    {
        MemoryStream ms = new MemoryStream(byteArray);
        Image returnImage = Image.FromStream(ms);
        return returnImage;
    }
    // Convert Image to bute array
    public byte[] ImageToByteArray(Image image)
    {
        MemoryStream ms = new MemoryStream();
        image.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
        return ms.ToArray();
    }
    // Scale the image to a percentage of its actual size.
    public Image ScaleByPercentage(Image img, double percent)
    {
        double fractionalPercentage = (percent / 100.0);
        int outputWidth = (int)(img.Width * fractionalPercentage);
        int outputHeight = (int)(img.Height * fractionalPercentage);
        return ImageResize.ScaleImage(img, outputWidth, outputHeight);
    }
    // Scale an image to a given width and height.
    private static Image ScaleImage(Image img, int outputWidth, int outputHeight)
    {
        Bitmap outputImage = new Bitmap(outputWidth, outputHeight, img.PixelFormat);
        outputImage.SetResolution(img.HorizontalResolution, img.VerticalResolution);
        Graphics graphics = Graphics.FromImage(outputImage);
        graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
        graphics.DrawImage(img, new Rectangle(0, 0, outputWidth, outputHeight),
            new Rectangle(0, 0, img.Width, img.Height), GraphicsUnit.Pixel);
        graphics.Dispose();
        return outputImage;
    }
}

Hi rumata,

I tried the code but the output image is still blurry.

Hello,
Thanks for your request.
All I wanted was to show ways to reduce the image in size. If you do not like rasterization, I can advise you only use already finished thumbnail image, instead of reducing it in the process.