Click here to Skip to main content
15,885,032 members
Please Sign up or sign in to vote.
3.00/5 (1 vote)
See more:
Hello to everyone i am new here, but i hope somebody will help me with this pain. I am developing one program for personal use, and now i have some problems with reading and displying big TIFF and JPEG files.

The Idea is to create the stream reader and read pixel data for
C#
pixelCountToRead = ScreenResolutionWidth*ScreenResolutionHeight;
from file and display it like an image in pictureBox.The main problem is - I need very fast way of reading pixel data from realy big files, without loading into memory.

Could somebody help me with reading pixel data from TIFF and JPEG files using streams.

I know that tiff`s :

C#
BitDepth  = 8;
BitDepth1 =16;// and i am not always know this depth for readed file
Compression = "NONE";
AlplhaChannel = "NormalAssociated";


I know for JPEGs : saved always with quality 100%(but i think it`s dosen`t metter for this task.)

So i need your help my friends, with this course i allready spend a week trying solve it myself.
Posted
Comments
Sergey Alexandrovich Kryukov 3-May-13 16:37pm    
Real time?! Do you know what "real-rime" means?.. :-)
—SA
Alexey Gapon 3-May-13 16:42pm    
I mean without waiting couple of seconds or even minutes for redrawing image in viewport.
Sergey Alexandrovich Kryukov 3-May-13 17:12pm    
It does not mean "real-time". Real time is a very different thing, not even directly related to some particular timing. It's more about the guarantees on events, order of execution and, in hard real-time, the guarantee for the latency. It's architecture, not performance. Actually, if you can migrate some non-real-time system into real-time, it would generally became only slower, often much slower, but with more predicable (or even guaranteed) timing. Compare token ring and Ethernet, for example.

Now about your timing? What minutes, for goodness sake? With the technique I described, everything will show up extremely fast, and an average present-day machine...

—SA
CPallini 3-May-13 16:43pm    
No, I don't know what 'real-rime' means (and now I'm curious). :-D
Sergey Alexandrovich Kryukov 3-May-13 16:58pm    
I just suggested a simple technique of using a set of smaller images to represent a big one smoothly. Please see my answer.
—SA

I'm afraid, there is no a way to read a TIFF file "not into memory". However, I would more or less easily implement the functionality when you have a collections of smaller file, with different resolutions and smaller fragments of the same image, which you could show on screen in any available resolution. This is even pretty simple.

For a simple example, let's consider the following case: you break a big image in M×N fragments, each fragment having number of pixels approximately matching the typical and quite manageable screen size or somewhat more, say 2-6 MPixels. You can easily load 4-5 images at a time. Actually, you will never need to load more than 5 at a time. Let's see: you actually will need M×N + 1 fragments, one more would be about the same size, representing the full image re-sampled down to the same pixel size as all the fragments. You could use it for navigation. Now, if you navigate to some fragment of the source image in maximum resolution, it will be, generally, on the intersection of 4 fragments; therefore, you would newer need to show more than 5 images at a time. You can unload and load images dynamically, never demanding too much memory. In my simple schema, you will have only two levels of resolution: "actual pixels" and "full image".

If you think at this idea, you will see that you can actually show any resolution in between in full screen size on each step, if you take several sets of tiled image fragments of 2-3 intermediate resolutions; and you don't have to have only, say, 5 different resolution levels: you can have any resolution between "actual pixels" and "full image", because when you present fragments on screen, you can also additionally re-sample images on the fly.

The main idea is: you never need to use more bitmap memory then the memory size of one full-resolution screen buffer multiplied by 5, because that no one can see more then one full screen at a time. When you zoom/pan, you load additional bitmaps on the fly and dispose unused ones. Note that the class System.Drawing.Image, the base class of System.Drawing.Bitmap is IDisposable:
http://msdn.microsoft.com/en-us/library/system.drawing.image.aspx[^].

I hope the technique is clear. You are welcome to develop all the detail. It's not even difficult. If you doubt that it can be fast enough, look at Google maps. With .NET, it actually should be even faster, because you don't require to spend time on network traffic.

Good luck,
—SA
 
Share this answer
 
v3
Comments
CPallini 3-May-13 17:16pm    
Nice, my 5.
Sergey Alexandrovich Kryukov 3-May-13 17:17pm    
Thank you, Carlo.
—SA
Yvar Birx 3-May-13 20:40pm    
Once again, lovely solution. :)
Sergey Alexandrovich Kryukov 3-May-13 23:29pm    
Thank you, Yvar.
—SA
I don't know about JPEGs, but TIFFs have no requirement that the data be stored in any order resembling the actual image (I'm working on a library for rendering TIFFs right now, so I've become fairly familiar with the format), so you'd need to make sure your reader can load chunks of the file out of order if you need to do that. I don't know how feasible this is to do in C#, you may need something lower level like C++.

I think your best bet is to break the images up into smaller pieces instead (for example, 1000x1000 pieces), and only load the currently visible pieces, this is how most large-image viewers work.

EDIT:
A useful tool for manipulating images (including breaking them into tiles) is Imagemagick[^]. It has C# bindings, but for a one time task you might not want to go that far. Here[^] is an example of how you can use it to do this.
 
Share this answer
 
v2
Comments
Alexey Gapon 3-May-13 17:37pm    
Very Nice Solution! Well it is helped. But now there is a quastion how to breake the image into smaller parts? Without loading whole image into memory?
Alexey Gapon 3-May-13 18:06pm    
I will try BitMiracle for it... will post a code here if it will work!
Nitheesh George 10-Jun-18 14:45pm    
I am working on a hobby project to display TIFF images. And I am facing a problem with multi strips images. I am able to read the strip data using the StripOffsets and StripByteCounts. But when the image is rendered some images works correct and some are not. So I also doubt the same as you mentioned in your solution.

"TIFFs have no requirement that the data be stored in any order resembling the actual image".

So my question is how to get Strip data in correct order.

Thanks & Regards,
Nitheesh
C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.IO;
using BitMiracle.LibTiff.Classic;



namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            Rectangle rect = new Rectangle(new Point(4200, 2450), new Size(this.pictureBox1.Width, this.pictureBox1.Height));
            //Rectangle rect = new Rectangle(new Point(0, 0), new Size(200, 200));

            Stopwatch stopWatch = new Stopwatch();
            stopWatch.Start();
            this.pictureBox1.Image = funcCropImage(@"IMG 382 Panorama.tif", rect);
            stopWatch.Stop();
            this.label1.Text = stopWatch.ElapsedMilliseconds.ToString();
        }
       

        private  Bitmap funcCropImage(string filepath, Rectangle rect)
        {

            int x = 0;// For new created image
            int y = 0;// For new created image
          
            byte red ;  
            byte green;   
            byte blue;
            //byte alpha;
                     

            Color color;

            Bitmap  cropedImage =  new Bitmap (rect.Width, rect.Height);

            using (Tiff image = Tiff.Open(filepath, "r"))
            {
                int stride = image.ScanlineSize();  
                byte[] scanline = new byte[stride]; 

                Compression compression = (Compression)image.GetField(TiffTag.COMPRESSION)[0].ToInt();

                if (compression == Compression.NONE)
                {
                    // Uncomressed images are much faster to crop so it is better to use uncompressed
                    for (int j = rect.Top; j < rect.Bottom; j++)
                    {
                        image.ReadScanline(scanline, j);
                        x = 0;
                        for (int i = rect.Left; i < rect.Right; i++)
                        {
                            red = scanline[i * 3];
                            green = scanline[i * 3 + 1];
                            blue = scanline[i * 3 + 2];
                            //alpha = scanline [i * 3 + 3];                        

                            color = Color.FromArgb(red, green, blue);

                            //color = Color.FromArgb(alpah, red, green, blue);

                            cropedImage.SetPixel(x, y, color);

                            x++;
                        }
                        y++;
                    }
                }//If               
                

            }
            
            return cropedImage;
        }////


    }
}


Well this part of the code will crop the image and display it in picture box. Works only for uncompressed tiff images without alpha channel. I always will use uncompressed TIFFs so it is fine for me. And i will use the way Sergey Alexandrovich suggested. Do display big images.
 
Share this answer
 
v3

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900