views:

86

answers:

3

I'm trying to set dpi value of a TIFF Image in C# through code but somehow the values are not persisted after saving the Image.

using (var image = new Bitmap(@"c:\newimage.tif"))
{
    uint[] uintArray = { 300, 1}; //Setting DPI as 300
    byte[] bothArray = ConvertUintArrayToByteArray(uintArray);
    PropertyItem item = image.PropertyItems.Where(p => p.Id == 0x11A).Single();
    var val = BitConverter.ToUInt32(item.Value, 0);
    Console.WriteLine(val);
    item.Id = 0x11A;
    item.Value = bothArray;
    item.Type = 5;
    item.Len = item.Value.Length;
    image.SetPropertyItem(item);
    image.Save(@"c:\newimage1.tif"); //Save image to new File
}

What is wrong with this code? Any kind of help would be appreciated. TIFF file tag definitions

+2  A: 

I suspect that the Bitmap resolution will override the property. Use Bitmap.SetResolution().

Hans Passant
@Hans I tried using `SetResolution()` but still no joy :(
Prashant
A: 

disclaimer: I work for Atalasoft, which makes products for working with images through .NET.

You can do this is dotImage using the TiffDocument class with code like this:

private void RemoveIfContains(TiffTagCollection tags, int tagID)
{
    TiffTag tag = tags.LookupTag(tagID);
    if (tag != null)
       tags.Remove(tag);
}

public void SetTiffResolution(string tiffin, string tiffout, int page, double resolution ) {
    if (tiffin == tiffout)
       throw new ArgumentException(tiffout, "output path must be different from input path");
    TiffFile tf = new TiffFile();
    using (FileStream stm = new FileStream(tiffin, FileMode.Open, FileAccess.Read, FileShare.Read)) {
        tf.Read(stm);
        TiffDirectory image = tf.Images[page];
        RemoveIfContains(image.Tags, TiffTagID.ResolutionX);
        RemoveIfContains(image.Tags, TiffTagID.ResolutionY);
        RemoveIfContains(image.Tags, TiffTagID.ResolutionUnit);
        image.Tags.Add(new TiffTag(TiffTagID.ResolutionX, resolution);
        image.Tags.Add(new TiffTag(TiffTagID.ResolutionY, resolution);
        image.Tags.Add(new TiffTag(TiffTagID.ResolutionUnit, 2)); // 2 == dots per INCH
        tf.Save(tiffout);
    }
}           

The advantages are several - direct access to the tags lets you set things the way you want without re-encoding the image. If your initial image was compressed with JPEG inside the TIFF, you don't have to worry about issues with re-encoding JPEG data and losing information. Further, you don't have to worry about losing TIFF tag information that was already there. This code also works on multipage TIFFs. Finally, this is probably going to be a faster approach than decoding the entire image just to change a tag.

The disadvantage to this approach is that you really, really, need to understand the TIFF spec. Without that understanding, you risk creating files that may not always be parseable. DotImage and IrfanView, for example, are very lenient in consuming all manner of broken TIFFs. Adobe PhotoShop is notoriously strict.

plinth
I'm getting sick of Atalasofts blatant advertising through answering posts on StackOverflow (Both you and Lou Franco). If you must advertise here purchase an actual advertisement.
+1  A: 

Setting both the property value and the bitmap resolution and then resaving the image should change the resolution (It worked on my sample image). I believe the original file has to have the tags for X and Y resolution present, not sure if .NET will add those tags if not present (would have to test).

Here's an example of reading and writing the X and Y resolution a TIFF image using .NET:

int numerator, denominator;

using (Bitmap bmp = (Bitmap)Bitmap.FromFile(@"C:\input.tif"))
{
    // obtain the XResolution and YResolution TIFFTAG values
    PropertyItem piXRes = bmp.GetPropertyItem(282);
    PropertyItem piYRes = bmp.GetPropertyItem(283);

    // values are stored as a rational number - numerator/denominator pair
    numerator = BitConverter.ToInt32(piXRes.Value, 0);
    denominator = BitConverter.ToInt32(piXRes.Value, 4);
    float xRes = numerator / denominator;

    numerator = BitConverter.ToInt32(piYRes.Value, 0);
    denominator = BitConverter.ToInt32(piYRes.Value, 4);
    float yRes = numerator / denominator;

    // now set the values
    byte[] numeratorBytes = new byte[4];
    byte[] denominatorBytes = new byte[4];

    numeratorBytes = BitConverter.GetBytes(600); // specify resolution in numerator
    denominatorBytes = BitConverter.GetBytes(1);

    Array.Copy(numeratorBytes, 0, piXRes.Value, 0, 4); // set the XResolution value
    Array.Copy(denominatorBytes, 0, piXRes.Value, 4, 4);

    Array.Copy(numeratorBytes, 0, piYRes.Value, 0, 4); // set the YResolution value
    Array.Copy(denominatorBytes, 0, piYRes.Value, 4, 4);

    bmp.SetPropertyItem(piXRes); // finally set the image property resolution
    bmp.SetPropertyItem(piYRes);

    bmp.SetResolution(600, 600); // now set the bitmap resolution

    bmp.Save(@"C:\output.tif"); // save the image
}