开发者

How to display TIFF (in form of Byte[]) on Silverlight Image control

I created a window service to put all of my TIFF files into database and stored them as Byte[].

Now I want to be able to display them through Silverlight Image control

So i use the Converter during binding XAML in order to convert the Byte[] to Bitmap because the Image.Source only accept eitheir URI (I don't have the file stored on server so can't use this method) or Bitmap.

BitmapImage bmi = new BitmapImage();
if (value != null)
{
    ImageGallery imageGallery = value as ImageGallery;
    byte[] imageContent = imageGallery.ImageContent;
    string imageType = imageGallery.ImageType;
    using (MemoryStream ms = new MemoryStream(imageContent))
    {
        bmi.SetSource(ms);
    }
}
return bmi;

However, I get the exception at bmi.SetSource(ms) because Silverlight only supports JPEG and PNG images.

So I did more research and knew that i should convert the bytes of TIFF to bytes of JPEG or PNG then it will work.

To do that I tried two methods:

  • Doing the conversion on server: in my RIA service call, after retrieving the ImageGallery, I loop through the available image to convert the bytes of TIFF to the bytes of JPEG.

BUT IT DOESN'T WORK.... Can you tell me where I did wrong?

public IQueryable<ImageGallery> GetImageGalleries()
{
    var imageGalleries = this.ObjectContext.ImageGalleries.OrderBy(i=>i.ImageName);
    foreach (ImageGallery imageGallery in imageGalleries)
    {
        if (imageGallery.ImageType == ".tif" || imageGallery.ImageType == ".tiff")
        {
            //Convert the Tiff byte array format into JPEG stream format
            System.Drawing.Bitmap dImg = new System.Drawing.Bitmap(new MemoryStream(imageGallery.ImageContent));
            MemoryStream ms = new MemoryStream();
            dImg.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);

            //then convert the JPEG stream format into JPEG byte array format
            byte[] buf = new byte[ms.Length];  
            ms.Read(buf, 0, buf.Length);

            //Changing the format tiff byte[] of ImageGallery to jpeg byte[] 
            imageGallery.ImageContent = buf;
        }
    }
    return imageGalleries;
}
  • The other solution is to use LibTiff.Net library to convert directly the Byte[] of TIFF to WritableBitmap directly on Silverlight.

However, after digging through their sample application or using Reflector to see the source code functions, I still can't figure out how to use their library to convert the bytes of TIFF to WritableBitmap JPEG (or PNG) because their sample only show the API for using the search the TIFF in a file directory. In my case, I don't have an existing file on server.

Can someone help me how to show the TIFF file on Image control of Silverlight?

I se开发者_如何学运维arched the forum but didn't find any solid answer for this.

thanks


I think the LibTiff will be the way to go. Ulitmately the Tiff.ClientData accepts a Stream that is the tiff data. If your tiff data really is a byte[] then you just need a MemoryStream around it. More likely at some point the byte[] is pulled from a stream so you probably don't even need this intermedatory byte[] / MemoryStream.


  1. Reference LibTiff.net

  2. Add this class:

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Windows.Media.Imaging;
    using BitMiracle.LibTiff.Classic;
    
    namespace CoreTechs.X9
    {
        public static class TiffUtility
        {
            public static Tiff CreateTiff(this byte[] bytes)
            {
                MemoryStream ms = new MemoryStream(bytes);
                Tiff tiff = Tiff.ClientOpen("in-memory", "r", ms, new TiffStream());
                return tiff;
            }
    
            public static IEnumerable<WriteableBitmap> ConvertToWriteableBitmaps(this Tiff tiff)
            {
                if (tiff == null)
                    throw new ArgumentNullException("tiff", "tiff is null.");
    
                short dirs = tiff.NumberOfDirectories();
    
                for (int i = 0; i < dirs; i++)
                {
                    if (tiff.SetDirectory((short)i))
                    {
                        int tileCount = tiff.NumberOfTiles();
                        int stripCount = tiff.NumberOfStrips();
    
                        var frameWidthField = tiff.GetField(TiffTag.IMAGEWIDTH);
                        var frameHeightField = tiff.GetField(TiffTag.IMAGELENGTH);
                        var compressionField = tiff.GetField(TiffTag.COMPRESSION);
                        var xResolutionField = tiff.GetField(TiffTag.XRESOLUTION);
                        var yResolutionField = tiff.GetField(TiffTag.YRESOLUTION);
                        var samplesPerPixelField = tiff.GetField(TiffTag.SAMPLESPERPIXEL);
    
                        int frameWidth = frameWidthField != null && frameWidthField.Length > 0 ? frameWidthField[0].ToInt() : 0;
                        int frameHeight = frameHeightField != null && frameHeightField.Length > 0 ? frameHeightField[0].ToInt() : 0;
                        var compression = compressionField != null && compressionField.Length > 0 ? (Compression)compressionField[0].Value : Compression.NONE;
                        var xResolution = xResolutionField != null && xResolutionField.Length > 0 ? new double?(xResolutionField[0].ToDouble()) : null;
                        var yResolution = yResolutionField != null && yResolutionField.Length > 0 ? new double?(yResolutionField[0].ToDouble()) : null;
                        var samplesPerPixel = samplesPerPixelField != null && samplesPerPixelField.Length > 0 ? samplesPerPixelField[0].ToString() : String.Empty;
    
                        if (xResolution != null && yResolution == null)
                        {
                            yResolution = xResolution;
                        }
    
                        var buffer = new int[frameWidth * frameHeight];
                        tiff.ReadRGBAImage(frameWidth, frameHeight, buffer);
    
                        var bmp = new WriteableBitmap(frameWidth, frameHeight);
                        for (int y = 0; y < frameHeight; y++)
                        {
                            var ytif = y * frameWidth;
                            var ybmp = (frameHeight - y - 1) * frameWidth;
    
                            for (int x = 0; x < frameWidth; x++)
                            {
                                var currentValue = buffer[ytif + x];
    
                                // Shift the Tiff's RGBA format to the Silverlight WriteableBitmap's ARGB format
                                bmp.Pixels[ybmp + x] = Tiff.GetB(currentValue) | Tiff.GetG(currentValue) << 8 | Tiff.GetR(currentValue) << 16 | Tiff.GetA(currentValue) << 24;
                            }
                        }
    
                        yield return bmp;
                    }
                }
            }
        }
    }
    
  3. Use the exension methods like this:

    byte[] myHappyTiffData = GetMyTiffBytesFromSomewhere();
    WriteableBitmap bmp = myHappyTiffData.CreateTiff().ConvertToWriteableBitmaps().FirstOrDefault();
    myImageControl.Source = bmp;
    


We began with LibTiff as a solution for our media manager. I wouldn't recommend it.

As you can see it creates a WriteableBitmap for each page. WB is the most performance hampering, leaking object you can use in Silverlight, so if you got more then 1 single page tiff your app will run out of memory faster then you can say Avada Kedavra.

There are viewers that appearently can load a large multipage tiff without killing your app (and browser and computer), for a decent license fee, but at this point I got nothing that allows you to decode a tiff an extract the pages.

Runner ups:

  • http://www.accusoft.com/
  • http://www.atalasoft.com/products/dotimage
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜