Spire.PDF is a professional PDF library applied to creating, writing, editing, handling and reading PDF files without any external dependencies. Get free and professional technical support for Spire.PDF for .NET, Java, Android, C++, Python.

Wed Jul 12, 2017 8:41 am

Hi,

We have a few image PDFs coming from scanned documents (not textual PDFs) and we would like to convert them to multi-page tiff files. We tried the PDFDocument.SaveAsImage method but we want to ask the following:

Since some of the PDFs come from Black&White scanning, how do we create 1-bit (black&white) multi-page tiff files using Group4 compression?

Some of them come from grayscale scanning, how do we convert the PDFs to 8-bit (grayscale) multi-page tiff files using jpeg compression for each page? And how do we set the quality/compression ratio?

Regards,
Sotiris

spanos@kat.forthnet.gr
 
Posts: 1
Joined: Mon Jul 10, 2017 10:46 am

Wed Jul 12, 2017 10:08 am

Hello,

Thanks for your inquiry.
I will look into it and give you the reply ASAP.

Sincerely,
Jane
E-iceblue support team
User avatar

Jane.Bai
 
Posts: 1156
Joined: Tue Nov 29, 2016 1:47 am

Thu Jul 13, 2017 7:09 am

Hello,

Sorry for the late reply.
In regards to your two requirements, the first one (1-bit with Group4 compression) can be achieved, but for the second one, there's seems no way to set the jpeg compression at present, however, the 8-bit tiff is available. Moreover, the third parameter in the method "JoinTiffImages", that is the enumeration "EncoderValue", is used to set the compression ratio. Under the enumeration, there are a lot of choices, you could choose accordingly. Below is my code for your reference.
Code: Select all
private void test_Click(object sender, EventArgs e)
        {
            PdfDocument document = new PdfDocument();
            document.LoadFromFile("test.pdf");
            //1. 1-bit (black&white) multi-page tiff with Group4 compression
            JoinTiffImages(SaveAs1bitBitmap(document), @"11077BW.tiff", EncoderValue.CompressionCCITT4);

            //2. 8-bit (grayscale) multi-page tiff
            //JoinTiffImages(ToGrayBitmap(document), @"11077GREY.tiff", EncoderValue.CompressionNone);
        }

        private System.Drawing.Image[] SaveAs1bitBitmap(PdfDocument document)
        {
            System.Drawing.Image[] images = new System.Drawing.Image[document.Pages.Count];
            for (int i = 0; i < document.Pages.Count; i++)
            {
                images[i] = document.SaveAsImage(i, PdfImageType.Metafile, 400, 400);
                Bitmap image = images[i] as Bitmap;
                int width = image.Width;
                int height = image.Height;
                for (int x = 0; x < width; x++)
                {
                    for (int y = 0; y < height; y++)
                    {
                        //get (x,y) color
                        Color color = image.GetPixel(x, y);
                        //get the corresponding b\w color about the color
                        int value = (color.R + color.G + color.B) / 3;
                        //set the new color
                        image.SetPixel(x, y, Color.FromArgb(value, value, value));
                    }
                }
            }
                return images;
        }

        private System.Drawing.Image[] ToGrayBitmap(PdfDocument document)
        {
            System.Drawing.Image[] images = new System.Drawing.Image[document.Pages.Count];
            System.Drawing.Image CrtImg;
            for (int i = 0; i < document.Pages.Count; i++)
            {
                CrtImg = document.SaveAsImage(i, PdfImageType.Metafile, 400, 400);
                Bitmap image = CrtImg as Bitmap;
                if (image != null)
                {
                    // lock the original memory area 
                    Rectangle rect = new Rectangle(0, 0, image.Width, image.Height);
                    BitmapData bmpData = image.LockBits(rect, ImageLockMode.ReadOnly,
                    image.PixelFormat);

                    // obtain the parameter for images 
                    int width = bmpData.Width;
                    int height = bmpData.Height;
                    int stride = bmpData.Stride;  // scan the stride
                    int offset = stride - width * 3;  // display the gap between the stride and scan line
                    IntPtr ptr = bmpData.Scan0;   // obtain the memory start position   
                    int scanBytes = stride * height;  // use stride to demonstrate the memory size
                    // two pointers pointing to originial arry and target array
                    int posScan = 0, posDst = 0;
                    byte[] rgbValues = new byte[scanBytes];  // distrubute the memory area for target array 
                    Marshal.Copy(ptr, rgbValues, 0, scanBytes);  // copy the image data into rgbValues
                    byte[] grayValues = new byte[width * height];           
                    // calculate the grayValues
                    for (int j = 0; j < height; j++)
                    {
                        for (int k = 0; k < width; k++)
                        {
                            double temp = rgbValues[posScan++] * 0.11 +
                            rgbValues[posScan++] * 0.59 + rgbValues[posScan++] * 0.3;
                            grayValues[posDst++] = (byte)temp;
                        }
                        // skip the unused byte at the end of every image data line, length = stride - width * bytePerPixel 
                        posScan += offset;
                    }

                    // unlock the memory 
                    Marshal.Copy(rgbValues, 0, ptr, scanBytes);
                    image.UnlockBits(bmpData);   

                    // build the 8 bit bitmap
                    images[i] = BuiltGrayBitmap(grayValues, width, height);
                }
                else
                {
                    return null;
                }

            }
            return images;
        }

        private static Bitmap BuiltGrayBitmap(byte[] rawValues, int width, int height)
        {
            // create a 8 bit gery bitmap and lock the momory area for manipulation 
            Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
            BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, width, height),
            ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);

            // calculate the image parameters
            int offset = bmpData.Stride - bmpData.Width;       
            IntPtr ptr = bmpData.Scan0;                         
            int scanBytes = bmpData.Stride * bmpData.Height;     
            byte[] grayValues = new byte[scanBytes];           

            // assign the image data
            int posSrc = 0, posScan = 0;                        // Index for rawValues and grayValues
            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    grayValues[posScan++] = rawValues[posSrc++];
                }
                posScan += offset;
            }

            // unlock the memory 
            Marshal.Copy(grayValues, 0, ptr, scanBytes);
            bitmap.UnlockBits(bmpData);   

            // change the index table of the generated bitmap to grey
            ColorPalette palette;
            // get an Palette object of the Format8bppIndexed image format
            using (Bitmap bmp = new Bitmap(1, 1, PixelFormat.Format8bppIndexed))
            {
                palette = bmp.Palette;
            }
            for (int i = 0; i < 256; i++)
            {
                palette.Entries[i] = Color.FromArgb(i, i, i);
            }
            // change the index teable
            bitmap.Palette = palette;

            return bitmap;
        }


        public static void JoinTiffImages(System.Drawing.Image[] images, string outFile, EncoderValue compressEncoder)
        {
            //use the save encoder
            System.Drawing.Imaging.Encoder enc = System.Drawing.Imaging.Encoder.SaveFlag;
            EncoderParameters ep = new EncoderParameters(2);
            ep.Param[0] = new EncoderParameter(enc, (long)EncoderValue.MultiFrame);
            ep.Param[1] = new EncoderParameter(System.Drawing.Imaging.Encoder.Compression, (long)compressEncoder);
            System.Drawing.Image pages = images[0];
            int frame = 0;
            ImageCodecInfo info = GetEncoderInfo("image/tiff");
            foreach (System.Drawing.Image img in images)
            {
                if (frame == 0)
                {
                    pages = img;
                    //save the first frame
                    pages.Save(outFile, info, ep);
                }
                else
                {
                    //save the intermediate frames
                    ep.Param[0] = new EncoderParameter(enc, (long)EncoderValue.FrameDimensionPage);
                    pages.SaveAdd(img, ep);
                }
                if (frame == images.Length - 1)
                {
                    //flush and close.
                    ep.Param[0] = new EncoderParameter(enc, (long)EncoderValue.Flush);
                    pages.SaveAdd(ep);
                }
                frame++;
            }
        }
        private static ImageCodecInfo GetEncoderInfo(string mimeType)
        {
            ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();
            for (int j = 0; j < encoders.Length; j++)
            {
                if (encoders[j].MimeType == mimeType)
                    return encoders[j];
            }
            throw new Exception(mimeType + " mime type not found in ImageCodecInfo");
        }


Please do not hesitate to contact us if you need any help.

Sincerely,
Jane
E-iceblue support team
User avatar

Jane.Bai
 
Posts: 1156
Joined: Tue Nov 29, 2016 1:47 am

Fri Jul 14, 2017 10:16 am

Hello,

How is your issue now? Did the solution I provided help?
Your feedback information will be greatly appreciated.

Sincerely,
Jane
E-iceblue support team
User avatar

Jane.Bai
 
Posts: 1156
Joined: Tue Nov 29, 2016 1:47 am

Return to Spire.PDF