Microsoft Developer Network > Forums Home > Visual Studio Express Editions Forums > Visual C# Express Edition > Merge Multiple Image Documents Into One Multi Page Document
Ask a questionAsk a question
 

AnswerMerge Multiple Image Documents Into One Multi Page Document

  • Tuesday, November 03, 2009 9:34 PMNuNn DaDdY Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    I would like to be able to take multiple image documents and put them together into one multi page document.  I found some source code online to merge them all into one image but I would like to have just one image per page.  How would I go about doing this?  Thank you very much!

Answers

  • Wednesday, November 04, 2009 6:40 PMJohnWein Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    If you search on "multipage tiff johnwein" or "saveadd johnwein" you should find applicable code.  I might have gotten the code originally from the C++ example.  Here is probably the simplest example:  Multipage Tiff from Bitmaps

    And here's a complete weather radar app, the splits a multipage gif and save the frames to a multipage tif:  MultiPage FAX TIFF image in Picture Box rendering unreadable images
  • Friday, November 06, 2009 6:43 PMJohnWein Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    If you have your multipage tiff, then I think your question has been answered.  Start a new thread for your new question if you have problems.

All Replies

  • Tuesday, November 03, 2009 11:04 PMJohnWein Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Use the Tiff container and SaveAdd.  Appropriate code in the help files.
  • Wednesday, November 04, 2009 3:41 PMNuNn DaDdY Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Has Code
    Hello,

    Thank you for your reply.  I located a helper class for this and have been going through it.  When I try to run it with multiple tiff documents and merge them I am receiving an Out Of Memory Exception.  Here is the code used:

            public bool mergeTiffPages(string[] sourceFiles, string targetFile)
            {
                bool response = false;
    
                try
                {
                    assignEncoder();
    
                    // If only 1 page was passed, copy directly to output
                    if (sourceFiles.Length == 1)
                    {
                        File.Copy(sourceFiles[0], targetFile, true);
                        return true;
                    }
    
                    int pageCount = sourceFiles.Length;
    
                    // First page
                    Image finalImage = Image.FromFile(sourceFiles[0]);
                    finalImage.Save(targetFile, tifImageCodecInfo, tifEncoderParametersPage1);
    
                    // All other pages
                    for (int i = 1; i < pageCount; i++)
                    {
                        Image img = Image.FromFile(sourceFiles[i]);
                        finalImage.SaveAdd(img, tifEncoderParametersPageX);
                        img.Dispose();
                    }
    
                    // Last page
                    finalImage.SaveAdd(tifEncoderParametersPageLast);
                    finalImage.Dispose();
                    response = true;
                }
                catch (OutOfMemoryException ex)
                {
                    Console.WriteLine(ex.Message);
                    response = false;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    response = false;
                }
    
                return response;
            }
    
  • Wednesday, November 04, 2009 3:46 PMJohnWein Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    You'll have to contact the author of that code for assistance.  It doesn't look like any Multiframe tiff code I've seen.  I've used the code in the help file example without problems.
  • Wednesday, November 04, 2009 4:12 PMNuNn DaDdY Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hello again,

    I will use what is in the help file then as I would prefer to do that anyways instead of using someone else's class.  I did a search on Image.SaveAdd example but I can only seem to find something in c++.  Am I looking in the place?
  • Wednesday, November 04, 2009 6:40 PMJohnWein Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    If you search on "multipage tiff johnwein" or "saveadd johnwein" you should find applicable code.  I might have gotten the code originally from the C++ example.  Here is probably the simplest example:  Multipage Tiff from Bitmaps

    And here's a complete weather radar app, the splits a multipage gif and save the frames to a multipage tif:  MultiPage FAX TIFF image in Picture Box rendering unreadable images
  • Friday, November 06, 2009 3:45 PMNuNn DaDdY Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Has Code
    Sorry for the delay John with getting back to you, I got side tracked on another project at work.  I am taking a look at those documents currently thank you for providing them.  I am now able to create the documents as I needed but it appears I may be having an issue similar to the  "MultiPage FAX TIFF Image in Picture Box rendering unreadable images"  as I am able to open and view the multi page tiff in Microsoft Image Document Viewer, but if I try to open them in Imaging For Windows I receive an error stating "The document's format is invalid or not supported".  I'm not sure why this is but I find some code to compress the image and convert it to bitonal and then it is able to work.  That wouldn't be an issue as the documents we will be receiving are simple text documents and therefore there is no need for color.  But it appears the clarity of the images is skewed and I find that some parts of the document are now harder to read. 

    Here is the code which I am using to achieve the multi-page tiff document, the items which are commented out are what is used when I compress and convert it to bitonal.  Currently the code is set up to just convert the images as is to a multi page document which produces the error described above.  Thank you again John.


            /// <summary>
            /// This function will return the source image to a tiff format.  If the format is .tiff, then the function just returns with success.
            /// </summary>
            /// <param name="str_SourceFile">The file that is to be converted into .tiff format</param>
            /// <returns>True on success, False on error</returns>
            private bool Convert_Image_To_Tiff(string str_SourceFile)
            {
                string str_FileName = Path.GetFileNameWithoutExtension(str_SourceFile);       //Get the filename
                string str_DestinationPath = Server.MapPath("Temp") + @"\" + str_FileName + ".tiff";              //Set up the location we are going to convert the target file to
    
                if (!Directory.Exists(Server.MapPath("Temp")))
                {
                    Directory.CreateDirectory(Server.MapPath("Temp"));
                }
    
                if (Path.GetExtension(str_SourceFile).ToUpper() == ".Tiff")                       //The file is already in the format we want
                {
                    File.Copy(str_SourceFile, str_DestinationPath);
                    return true;
                }
                else
                {
                    try
                    {
                        System.Drawing.Bitmap bitmap_Image = new System.Drawing.Bitmap(str_SourceFile);     //Convert a bitmap instance based on the source file
    
                        bitmap_Image.Save(str_DestinationPath, System.Drawing.Imaging.ImageFormat.Tiff);    //Save this instance to the destination location and convert the format to that of a tiff
                        bitmap_Image.Dispose();
    
                        return true;
                    }
                    catch (Exception ex)
                    {
                        RegisterAlertMessage("Error In Convert_Image_To_Tiff:  " + ex.Message);
                        return false;
                    }    
                }           
            }
    
    
            /// <summary>
            /// This will take all of the image files the user has uploaded that have been converted into .tiff format and merge them together into a multi-page document
            /// </summary>
            /// <param name="str_DestinationPath">The destination path and file name of where this document is going to be stored</param>
            /// <param name="arrLst">Array list of file paths to the list of images that are to be merged</param>
            /// <returns>True on Success, False on Error</returns>
            private bool Create_Multi_Frame_Tiff(string str_DestinationPath, ArrayList arrLst)
            {
                ImageCodecInfo codec = null;
                
                foreach (ImageCodecInfo cCodec in ImageCodecInfo.GetImageEncoders())
                {
                    if (cCodec.CodecName == "Built-in TIFF Codec")
                        codec = cCodec;
                }
    
                try
                {
                    //EncoderParameters imagePararms = new EncoderParameters(2);
    
                    EncoderParameters imagePararms = new EncoderParameters(1);
                    imagePararms.Param[0] = new EncoderParameter(Encoder.SaveFlag, (long)EncoderValue.MultiFrame);
                    //imagePararms.Param[1] = new EncoderParameter(Encoder.Compression, (long)EncoderValue.CompressionCCITT4);
    
                    if (arrLst.Count == 1)
                    {
                        System.IO.File.Copy((string)arrLst[0], str_DestinationPath, true);
                        return true;
                    }
                    else if (arrLst.Count > 1)
                    {
                        System.Drawing.Image DestinationImage = (System.Drawing.Image) (new System.Drawing.Bitmap((string)arrLst[0]));
                        //System.Drawing.Image DestinationImage = (System.Drawing.Image) ConvertToBitonal(new System.Drawing.Bitmap((string)arrLst[0]));
                        DestinationImage.Save(str_DestinationPath, codec, imagePararms);
    
                        imagePararms.Param[0] = new EncoderParameter(Encoder.SaveFlag, (long)EncoderValue.FrameDimensionPage);
    
    
                        for (int i = 1; i < arrLst.Count; i++)
                        {
                            System.Drawing.Image img = (System.Drawing.Image)(new System.Drawing.Bitmap((string)arrLst[i]));
                            //System.Drawing.Image img = (System.Drawing.Image)ConvertToBitonal(new System.Drawing.Bitmap((string)arrLst[i]));
                            DestinationImage.SaveAdd(img, imagePararms);
                            img.Dispose();
                        }
    
                        imagePararms.Param[0] = new EncoderParameter(Encoder.SaveFlag, (long)EncoderValue.Flush);
                        DestinationImage.SaveAdd(imagePararms);
                        imagePararms.Dispose();
                        DestinationImage.Dispose();
    
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
                catch (Exception ex)
                {
                    RegisterAlertMessage(ex.Message);
                    return false;
                }
            }
    




    And below is the code for Converting the image to bitonal



            public Bitmap ConvertToBitonal(Bitmap original)
            {
                Bitmap source = null;
    
                // If original bitmap is not already in 32 BPP, ARGB format, then convert
                if (original.PixelFormat != PixelFormat.Format32bppArgb)
                {
                    source = new Bitmap(original.Width, original.Height, PixelFormat.Format32bppArgb);
                    source.SetResolution(original.HorizontalResolution, original.VerticalResolution);
                    using (Graphics g = Graphics.FromImage(source))
                    {
                        g.DrawImageUnscaled(original, 0, 0);
                    }
                }
                else
                {
                    source = original;
                }
    
                // Lock source bitmap in memory
                BitmapData sourceData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
    
                // Copy image data to binary array
                int imageSize = sourceData.Stride * sourceData.Height;
                byte[] sourceBuffer = new byte[imageSize];
                Marshal.Copy(sourceData.Scan0, sourceBuffer, 0, imageSize);
    
                // Unlock source bitmap
                source.UnlockBits(sourceData);
    
                // Create destination bitmap
                Bitmap destination = new Bitmap(source.Width, source.Height, PixelFormat.Format1bppIndexed);
    
                // Lock destination bitmap in memory
                BitmapData destinationData = destination.LockBits(new Rectangle(0, 0, destination.Width, destination.Height), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed);
    
                // Create destination buffer
                imageSize = destinationData.Stride * destinationData.Height;
                byte[] destinationBuffer = new byte[imageSize];
    
                int sourceIndex = 0;
                int destinationIndex = 0;
                int pixelTotal = 0;
                byte destinationValue = 0;
                int pixelValue = 128;
                int height = source.Height;
                int width = source.Width;
                int threshold = 500;
    
                // Iterate lines
                for (int y = 0; y < height; y++)
                {
                    sourceIndex = y * sourceData.Stride;
                    destinationIndex = y * destinationData.Stride;
                    destinationValue = 0;
                    pixelValue = 128;
    
                    // Iterate pixels
                    for (int x = 0; x < width; x++)
                    {
                        // Compute pixel brightness (i.e. total of Red, Green, and Blue values)
                        pixelTotal = sourceBuffer[sourceIndex + 1] + sourceBuffer[sourceIndex + 2] + sourceBuffer[sourceIndex + 3];
                        if (pixelTotal > threshold)
                        {
                            destinationValue += (byte)pixelValue;
                        }
                        if (pixelValue == 1)
                        {
                            destinationBuffer[destinationIndex] = destinationValue;
                            destinationIndex++;
                            destinationValue = 0;
                            pixelValue = 128;
                        }
                        else
                        {
                            pixelValue >>= 1;
                        }
                        sourceIndex += 4;
                    }
                    if (pixelValue != 128)
                    {
                        destinationBuffer[destinationIndex] = destinationValue;
                    }
                }
    
                // Copy binary image data to destination bitmap
                Marshal.Copy(destinationBuffer, 0, destinationData.Scan0, imageSize);
    
                // Unlock destination bitmap
                destination.UnlockBits(destinationData);
    
                // Return
                return destination;
            }
    
  • Friday, November 06, 2009 4:00 PMJohnWein Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    I can't help you with pre W2K programs.  The TIFF standard has changed to include many formats that weren't available in 1995.
  • Friday, November 06, 2009 4:17 PMNuNn DaDdY Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Is the imaging for windows what you are refering to?  Should this code work for something that is more up to date then?


    Also, could you refer me to some documention on the compression items and image documentation as what I have found in the msdn documention thus far has been limited.  Thank you much!

  • Friday, November 06, 2009 4:31 PMJohnWein Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Is the imaging for windows what you are refering to?

    Should this code work for something that is more up to date then?


    That's what you said.  You viewed them in Document Viewer and you had a multipage tiff.
  • Friday, November 06, 2009 5:18 PMNuNn DaDdY Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Has Code
    Alrighty, I didn't even realize that I was attempting an older program.  Newer ones seem to open it fine so all is well there.  However, is there a better way to convert this image to Bitonal?  I found a post from you in September where you use:

          image1.Source = new FormatConvertedBitmap(new BitmapImage(new Uri(ofd.FileName)),
                                                    PixelFormats.BlackWhite,
                                                    BitmapPalettes.BlackAndWhite,
                                                    1.0);
    
    


    But I am having trouble including this namespace in my project as it is actually online and finding the dll used for System.Windows.Media.Imaging namespace or is this not possible for that.


    EDIT:  I was able to find it, nevermind on the .dll
  • Friday, November 06, 2009 6:43 PMJohnWein Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    If you have your multipage tiff, then I think your question has been answered.  Start a new thread for your new question if you have problems.