Skewed Images in PDF

The PDF Creator .NET Library enables you to create secure PDF documents on the fly and to view, print and process existing PDF documents. If you have any questions about PDF Creator .Net, please post them here.
Post Reply
airmischer
Posts: 2
Joined: Wed Sep 07 2011

Skewed Images in PDF

Post by airmischer »

Hi, I'm currently using latest trial version of PDF Creator for .NET (4.5.1.0) and I'm having some issues with image being displayed wrong in the PDF.

Most of the bitmaps I add display correctly, however, there seems to be a certain dot height that leaves the images looking skewed.

For Example: (All Images heights are in Screen Pixels (96 DPI) and the DPIs represent the DPI the Bitmap is created with)
- 43 Height at 120DPI (53.75 dots)
- 17 Height at 300DPI (53.125 dots)
- 08 Height at 600DPI (50 dots)
All display incorrectly, while
- 44 Height at 120DPI (55 dots)
- 18 Height at 300DPI (56.25 dots)
- 09 Height at 600DPI (56.25 dots)
All display correctly.

I am creating bitmaps at runtime and are adding them to the pdf afterwards.
Here's the code I'm using to add the Bitmaps to the PDF. When I save them to an external file right before the memory stream, the bitmaps are correct

Code: Select all

        private bool AddImageToPage(Bitmap bmp, ref IacPage page, string sImageName, int iLeftTwips, int iTopTwips, int iRightTwips, int iBottomTwips, bool bMakeTransparent, bool bMakeGray)
        {
                Bitmap bmpToDraw = bmp;
                if (bmp.PixelFormat != PixelFormat.Format24bppRgb)
                    bmpToDraw = ConvertToFormat24bppRgb(bmp);

                using (IacObject imageObject = page.CreateObject(IacObjectType.acObjectTypePicture, sImageName))
                {
                    imageObject.AttributeByName(AmyuniHelpers.DrawingObjects.CommonAttributes.TOP).Value = iTopTwips;
                    imageObject.AttributeByName(AmyuniHelpers.DrawingObjects.CommonAttributes.LEFT).Value = iLeftTwips;
                    imageObject.AttributeByName(AmyuniHelpers.DrawingObjects.CommonAttributes.RIGHT).Value = iRightTwips;
                    imageObject.AttributeByName(AmyuniHelpers.DrawingObjects.CommonAttributes.BOTTOM).Value = iBottomTwips;

                    if (bMakeTransparent) 
                        imageObject.AttributeByName(AmyuniHelpers.DrawingObjects.PictureAttributes.RGB_MASK).Value = 0x00ffffff; //White

                    using (MemoryStream stream = new MemoryStream())
                    {
                        bmpToDraw.Save(stream, ImageFormat.Bmp);

                        imageObject.AttributeByName(AmyuniHelpers.DrawingObjects.PictureAttributes.BITMAP_WIDTH).Value = bmpToDraw.Width;
                        imageObject.AttributeByName(AmyuniHelpers.DrawingObjects.PictureAttributes.BITMAP_HEIGHT).Value = bmpToDraw.Height;
                        imageObject.AttributeByName(AmyuniHelpers.DrawingObjects.PictureAttributes.BITS_PER_COMPONENT).Value = 24;
                        imageObject.AttributeByName(AmyuniHelpers.DrawingObjects.PictureAttributes.BITS_PER_COLOR).Value = 8;
                        imageObject.AttributeByName(AmyuniHelpers.DrawingObjects.PictureAttributes.BITMAP_DATA).Value = stream.GetBuffer();
                        
                        stream.Close();
                    }

                    if (bMakeGray) 
                        imageObject.AttributeByName(AmyuniHelpers.DrawingObjects.PictureAttributes.GRAY_SCALE).Value = bGrayScale;

                    imageObject.AttributeByName(AmyuniHelpers.DrawingObjects.CommonAttributes.LOCKED).Value = true;
                }
      }
And one side question, Do you support 32bppARGB Bitmaps? I've tried to add them to pdfs and I have had no luck getting them to work correctly.

Thanks for your help
Rich
Posts: 76
Joined: Thu Jun 16 2011

Re: Skewed Images in PDF

Post by Rich »

Your code for the most part is fine. However, the only problem is that you are trying to set the the attribute "BitmapData" from the stream that contains all of the bitmap as if it were saved to a file.

This includes the bitmap header as well as the actual RGB values for the pixels in the image. This will not work because the "BitmapData" attribute is expected to be an array of bytes that holds the RGB values of the image's data only without any file header data.

imageObject.AttributeByName(AmyuniHelpers.DrawingObjects.PictureAttributes.BITMAP_DATA).Value = stream.GetBuffer();

Please find below one method that will solve your problem:

Code: Select all

private bool AddImageToPage(Bitmap bmp, ref IacPage page, string sImageName, int iLeftTwips, int iTopTwips, int iRightTwips, int iBottomTwips, bool bMakeTransparent, bool bMakeGray)
{
    Bitmap bmpToDraw = bmp;
    if (bmp.PixelFormat != PixelFormat.Format24bppRgb)
        bmpToDraw = ConvertToFormat24bppRgb(bmp);

    using (IacObject imageObject = page.CreateObject(IacObjectType.acObjectTypePicture, sImageName))
    {
        imageObject.AttributeByName(AmyuniHelpers.DrawingObjects.CommonAttributes.TOP).Value = iTopTwips;
        imageObject.AttributeByName(AmyuniHelpers.DrawingObjects.CommonAttributes.LEFT).Value = iLeftTwips;
        imageObject.AttributeByName(AmyuniHelpers.DrawingObjects.CommonAttributes.RIGHT).Value = iRightTwips;
//      imageObject.AttributeByName(AmyuniHelpers.DrawingObjects.CommonAttributes.BOTTOM).Value = iBottomTwips;
        imageObject.AttributeByName(AmyuniHelpers.DrawingObjects.CommonAttributes.BOTTOM).Value = iTopTwips+ ((bmpToDraw.Height * (iRightTwips- iLeftTwips)) / bmpToDraw.Width);        

        if (bMakeTransparent) 
            imageObject.AttributeByName(AmyuniHelpers.DrawingObjects.PictureAttributes.RGB_MASK).Value = 0x00ffffff; //White

        imageObject.AttributeByName(AmyuniHelpers.DrawingObjects.PictureAttributes.BITMAP_WIDTH).Value = bmpToDraw.Width;
        imageObject.AttributeByName(AmyuniHelpers.DrawingObjects.PictureAttributes.BITMAP_HEIGHT).Value = bmpToDraw.Height;
        imageObject.AttributeByName(AmyuniHelpers.DrawingObjects.PictureAttributes.BITS_PER_COMPONENT).Value = 24;
        imageObject.AttributeByName(AmyuniHelpers.DrawingObjects.PictureAttributes.BITS_PER_COLOR).Value = 8;
        imageObject.AttributeByName(AmyuniHelpers.DrawingObjects.PictureAttributes.BITMAP_DATA).Value = GetRGBValues(bmp);

        if (bMakeGray) 
            imageObject.AttributeByName(AmyuniHelpers.DrawingObjects.PictureAttributes.GRAY_SCALE).Value = bGrayScale;

        imageObject.AttributeByName(AmyuniHelpers.DrawingObjects.CommonAttributes.LOCKED).Value = true;
    }
}

        private byte[] GetRGBValues(Bitmap bmp)
        {
            //returns an array of bytes containing the actual RGB values for each pixel in the image
 
            // Lock the bitmap's bits.  
            Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
            System.Drawing.Imaging.BitmapData bmpData =
                bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
                bmp.PixelFormat);
 
            // Get the address of the first line.
            IntPtr ptr = bmpData.Scan0;
 
            // Declare an array to hold the bytes of the bitmap.
            int totalBytes  = Math.Abs(bmpData.Stride) * bmp.Height;
            byte[] rgbValues = new byte[totalBytes];
 
            // Copy the RGB values into the array.
 
            if (false)
            {
                //this case will generate a mirrored image
                System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, totalBytes);
            }
            else
            {
                //The scan lines in the bitmap data are inverted.
                //Copy from bottom to top to obtain correct result
 
                int scanLineBytes = Math.Abs(bmpData.Stride);
                byte[] scanLineData = new byte[scanLineBytes];
 
                totalBytes = 0;
                for (int scanLine = bmp.Height - 1; scanLine >= 0; scanLine--)
                {
                    IntPtr start = new IntPtr(ptr.ToInt32() + (scanLine * scanLineBytes));
                    System.Runtime.InteropServices.Marshal.Copy(start, scanLineData, 0, scanLineBytes);
                    scanLineData.CopyTo(rgbValues, totalBytes);
                    totalBytes += scanLineBytes;
                }
            }
 
            // Unlock the bits.
            bmp.UnlockBits(bmpData);
 
            return rgbValues;
        }
Efficient and accurate conversion to PDF, XPS, PDF/A and more. Free trials at - http://www.amyuni.com
airmischer
Posts: 2
Joined: Wed Sep 07 2011

Re: Skewed Images in PDF

Post by airmischer »

That works perfect. Thanks for your help
Post Reply