简体   繁体   中英

C#: How do I convert a multi-page TIFF via MemoryStream into one long image?

So I have been able to take a multi-page TIFF file and convert it to a single jpeg image but it flattens the TIFF. By flatten it, I mean it only returns the first page. The goal is to retrieve the TIFF (via memory stream), open each page of the TIFF and append it to a new jpeg (or any web image). Thus creating one long image to view on the web without the aid of a plugin. I do have the MODI.dll installed but I am not sure how to use it in this instance but it is an option.

  • Source Code (using a FileHandler):

     #region multi-page tiff to single page jpeg var byteFiles = dfSelectedDocument.File.FileBytes; // <-- FileBytes is a byte[] or byte array source. byte[] jpegBytes; using( var inStream = new MemoryStream( byteFiles ) ) using( var outStream = new MemoryStream() ) { System.Drawing.Image.FromStream( inStream ).Save( outStream, ImageFormat.Jpeg ); jpegBytes = outStream.ToArray(); } context.Response.ContentType = "image/JPEG"; context.Response.AddHeader( "content-disposition", string.Format( "attachment;filename=\\"{0}\\"", dfSelectedDocument.File.FileName.Replace( ".tiff", ".jpg" ) ) ); context.Response.Buffer = true; context.Response.BinaryWrite( jpegBytes ); #endregion 

I'm guessing that you'll have to loop over each frame in the TIFF.

Here's an excerpt from Split multi page tiff file :

private void Split(string pstrInputFilePath, string pstrOutputPath) 
    { 
        //Get the frame dimension list from the image of the file and 
        Image tiffImage = Image.FromFile(pstrInputFilePath); 
        //get the globally unique identifier (GUID) 
        Guid objGuid = tiffImage.FrameDimensionsList[0]; 
        //create the frame dimension 
        FrameDimension dimension = new FrameDimension(objGuid); 
        //Gets the total number of frames in the .tiff file 
        int noOfPages = tiffImage.GetFrameCount(dimension); 

        ImageCodecInfo encodeInfo = null; 
        ImageCodecInfo[] imageEncoders = ImageCodecInfo.GetImageEncoders(); 
        for (int j = 0; j < imageEncoders.Length; j++) 
        { 
            if (imageEncoders[j].MimeType == "image/tiff") 
            { 
                encodeInfo = imageEncoders[j]; 
                break; 
            } 
        } 

        // Save the tiff file in the output directory. 
        if (!Directory.Exists(pstrOutputPath)) 
            Directory.CreateDirectory(pstrOutputPath); 

        foreach (Guid guid in tiffImage.FrameDimensionsList) 
        { 
            for (int index = 0; index < noOfPages; index++) 
            { 
                FrameDimension currentFrame = new FrameDimension(guid); 
                tiffImage.SelectActiveFrame(currentFrame, index); 
                tiffImage.Save(string.Concat(pstrOutputPath, @"\", index, ".TIF"), encodeInfo, null); 
            } 
        } 
    } 

You should be able to adapt the logic above to append onto your JPG rather than create separate files.

In case you get the dreadful "A generic error occurred in GDI+" error (which is arguably the Rickroll of all errors) when using the SelectActiveFrame method suggested in the other answers, I strongly suggest to use the System.Windows.Media.Imaging.TiffBitmapDecoder class instead (you will need to add a Reference to the PresentationCore.dll framework library).

Here's an example code that does just that (it puts all the TIFF frames into a list of standard Bitmaps):

List<System.Drawing.Bitmap> bmpLst = new List<System.Drawing.Bitmap>();

using (var msTemp = new MemoryStream(data))
{
    TiffBitmapDecoder decoder = new TiffBitmapDecoder(msTemp, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
    int totFrames = decoder.Frames.Count;

    for (int i = 0; i < totFrames; ++i)
    {
        // Create bitmap to hold the single frame
        System.Drawing.Bitmap bmpSingleFrame = BitmapFromSource(decoder.Frames[i]);
        // add the frame (as a bitmap) to the bitmap list
        bmpLst.Add(bmpSingleFrame);
    }
}

And here's the BitmapFromSource helper method:

public static Bitmap BitmapFromSource(BitmapSource bitmapsource)
{
    Bitmap bitmap;
    using (var outStream = new MemoryStream())
    {
        BitmapEncoder enc = new BmpBitmapEncoder();
        enc.Frames.Add(BitmapFrame.Create(bitmapsource));
        enc.Save(outStream);
        bitmap = new Bitmap(outStream);
    }
    return bitmap;
}

For further info regarding this workaround, I also suggest to read this blog post I wrote.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM