1

I am trying to understand and implement a piece of code for Tiff compression.

I have already used 2 separate techniques - Using 3rd party dll's LibTiff.NEt (1st method is bulky) and the Image save method, http://msdn.microsoft.com/en-us/library/ytz20d80%28v=vs.110%29.aspx (2nd method works only on windows 7 machine but not on windows 2003 or 2008 server).

Now I am looking to explore this 3rd method.

using System.Windows.Forms;
using System.Windows.Media.Imaging;
using System.Drawing.Imaging;

        int width = 800;
        int height = 1000;
        int stride = width/8;
        byte[] pixels = new byte[height*stride];

        // Try creating a new image with a custom palette.
        List<System.Windows.Media.Color> colors = new List<System.Windows.Media.Color>();
        colors.Add(System.Windows.Media.Colors.Red);
        colors.Add(System.Windows.Media.Colors.Blue);
        colors.Add(System.Windows.Media.Colors.Green);
        BitmapPalette myPalette = new BitmapPalette(colors);

        // Creates a new empty image with the pre-defined palette

        BitmapSource image = BitmapSource.Create(
            width,
            height,
            96,
            96,
            System.Windows.Media.PixelFormats.BlackWhite,
            myPalette, 
            pixels, 
            stride);


FileStream stream = new FileStream(Original_File, FileMode.Create);
TiffBitmapEncoder encoder = new TiffBitmapEncoder();
encoder.Compression = TiffCompressOption.Ccitt4;
encoder.Frames.Add(BitmapFrame.Create(image));
encoder.Save(stream);

But I don't have a full understanding of what is happening here.

There is obviously some kind of a memory stream that the compression technique is being applied to. But I am a bit confused how to apply this to my specific case. I have an original tiff file, I want to use this method to set its compression to CCITT and save it back. Can anyone help?

I copied the above code and the code runs. But my end output file is a solid black background image. Although on the positive side it is of the correct compression type.

http://msdn.microsoft.com/en-us/library/ms616002%28v=vs.110%29.aspx

http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.tiffcompressoption%28v=vs.100%29.aspx

http://social.msdn.microsoft.com/Forums/vstudio/en-US/1585c562-f7a9-4cfd-9674-6855ffaa8653/parameter-is-not-valid-for-compressionccitt4-on-windows-server-2003-and-2008?forum=netfxbcl

Philo
  • 1,931
  • 12
  • 39
  • 77
  • Why did you add the asp.net tag? Are you doing this is an asp.net project? – mbeckish Jan 27 '14 at 18:33
  • yes. I have a web page, that allows user input, which is then converted into a tiff file. This tiff file's original compression type is LZW. I need it in CCITT compression format. – Philo Jan 27 '14 at 18:41
  • You might be having issues because [the Drawing namespace is not supported in ASP.NET services](http://stackoverflow.com/q/390532/21727) – mbeckish Jan 27 '14 at 18:50
  • `PixelFormats` is in `System.Windows.Media`, not `System.Windows.Media.Imaging`. – mbeckish Jan 27 '14 at 18:53
  • thanks, now my code runs, but the output file I get doesn't have any image or properties...when I open the file I get the message windows photo editor cannot open the file, because it is being used in another application. – Philo Jan 27 '14 at 19:00
  • I disposed the image, and my end result is an image with the correct compression type but unfortunately its solid black instead of black and white. – Philo Jan 27 '14 at 19:11

1 Answers1

0

LibTiff.net is a little bulky because it's based off LibTiff, which has its own set of problems.

My company (Atalasoft) has the ability to do that fairly easily, and the free version of the SDK will do the task you want with a few restrictions. The code for re-encoding a file would look like this:

public bool ReencodeFile(string path)
{
    AtalaImage image = new AtalaImage(path);
    if (image.PixelFormat == PixelFormat.Pixel1bppIndexed)
    {
        TiffEncoder encoder = new TiffEncoder();
        encoder.Compression = TiffCompression.Group4FaxEncoding;
        image.Save(path, encoder, null); // destroys the original - use carefully
        return true;
    }
    return false;
}

Things you should be aware of:

  • this code will only work properly on 1bpp images
  • this code will NOT work properly on multi-page TIFFs
  • this code does NOT preserve metadata within the original file

and I would want the code to at least check for that. If you are inclined to have a solution that better preserves what's in the content of the file, you would want to do this:

public bool ReencodeFile(string origPath, string outputPath)
{
    if (origPath == outputPath) throw new ArgumentException("outputPath needs to be different from input path.");
    TiffDocument doc = new TiffDocuemnt(origPath);

    bool needsReencoding = false;
    for (int i=0; i < doc.Pages; i++) {
        if (doc.Pages[i].PixelFormat == PixelFormat.Pixel1bppIndexed) {
            doc.Pages[i] = new TiffPage(new AtalaImage(origPath, i, null), TiffCompression.Group4FaxEncoding);
            needsReencoding = true;
        }
    }
    if (needsReendcoding)
        doc.Save(outputPath);
    return needsReencoding;
}

This solution will respect all pages within the document as well as document metadata.

plinth
  • 48,267
  • 11
  • 78
  • 120
  • thanks. I m still trying to use the above methodology to solve my case. If you can help with that. Please let me know. – Philo Jan 27 '14 at 19:01
  • Also, what if the image is not originally 1bpp ? – Philo Jan 27 '14 at 21:51
  • You cannot encode anything but 1bpp in CCITT. For other bit depths, you have to select a different codec (flate or jpeg typically). I would advise that you spend a little time reading up on image compression and codecs. Also, if you look at the TIFF spec and think "I can totally write this format myself" - think again, it's subtle and sloppy (an unusual combination). – plinth Jan 28 '14 at 15:31
  • for the very first statement :- Atalasoft.Imaging.AtalaImage image = new Atalasoft.Imaging.AtalaImage(fileName); I get the error Unable to retrieve security descriptor for this frame. – Philo Jan 29 '14 at 22:05
  • Philo - I would call in to our support line - they're good people (and engineers like you) – plinth Jan 30 '14 at 14:17
  • haha, I called and the lady said "We don't provide phone support for the free sdk version" haha – Philo Jan 30 '14 at 17:48
  • OK - the problem might be the environment - are you running in full trust? If so the assembly needs partial, IIRC. – plinth Jan 30 '14 at 18:08
  • elaborate? How do I give partial IIRC to my Visual Studio's 2010 environment. – Philo Jan 30 '14 at 21:19
  • https://www.atalasoft.com/KB/article.aspx?id=10340 (had it backwards - needs full trust, likely). – plinth Jan 30 '14 at 21:36
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/46465/discussion-between-plinth-and-philo) – plinth Jan 30 '14 at 22:03
  • Worked, I was using the anyCPU dlls, instead the x86 worked. However the compression method threw an exception because my image is LZW (original compression) and not 1bpp. – Philo Jan 31 '14 at 23:18