tags:

views:

176

answers:

4

I am working on a .NET application to reduce image file sizes using ImageMagick. My application stores some "settings" in a Hashtable for use in various areas of the application. I am now adding a feature to reduce image size based on desired DPI in the transformed image. Basically, I am looking up the DPI in the unaltered image, calculating the percentage of the desired DPI in relation to the current DPI, and then I will resize the image dimensions by this proportion.

ImageMagick reports image DPI as floating point values. So 200x200 DPI is really 199.975x199.975. Thus I use Math.Ceiling() to get the values into my application. When I try to use the desired DPI from my settings Hashtable to do the percentage calculation I get an invalid cast exception. I don't know why this is happening.

Here is a test case that fails in the same manner as my actual code:


using System;
using System.Collections;

namespace typetest
{
    class Program
    {
        private struct DPI {
            public double x;
            public double y;
        }

        public static void Main(string[] args)
        {
            Hashtable vars = new Hashtable();
            DPI dpi;
            string dpiString = "199.547:199.547";
            string[] ret;

            vars["newDpiX"] = 150;
            vars["newDpiY"] = 150;
            ret = dpiString.Split(':');

            dpi.x = ( (double)vars["newDpiX"] / Math.Ceiling(double.Parse(ret[0])) ) * 100;
            dpi.y = ( (double)vars["newDpiY"] / Math.Ceiling(double.Parse(ret[1])) ) * 100;

            Console.WriteLine("New DPI percentage = " + dpi.x + "%x" + dpi.y +"%");
        }
    }
}

If I change the division to


double newDpiX = 150.0;
dpi.x = ( newDpiX / Math.Ceiling(double.Parse(ret[0])) ) * 100;

it will work as expected. What is going on here?

+3  A: 

Try

vars["newDpiX"] = 150d;
Alex Reitbort
Wouldn't 150d treat 150 as a decimal instead of as a double?
Sonny Boy
150m would be decimal.
MikeB
+1  A: 

Use:

dpi.y = ( Convert.ToDouble(vars["newDpiY"]) / Math.Ceiling(double.Parse(ret[1])) ) * 100;

I think your problem is that vars["newDpiY"] = 150; stores an int, not a double.

Nestor
Okay, so it works if I explicitly store 150 as a double in the hashtable. But why can't I specify the cast at the time of division (without using Convert)?
jsumners
with the cast you would have to do (double)(int).. to convert first to what it actually is, and then to double.
Nestor
A: 

Hashtable hold objects, you assign 150 to it, so it's stored as an int. Try assigning 150.0 or (double)150, or anything to that effect.

gmagana
+4  A: 

The Hashtable stores Objects. When you put an int in an object, you "box" it. Unboxing requires the same type, you can't convert directly from a boxed int to a double.

This will fail:

object obj = 10;
double dbl = (double)obj;

This will succeed:

object obj = 10d; // a double value, could also have been 10.0
double dbl = (double)obj;

And this will also work:

object obj = 10; // an int
double dbl = (double)(int)obj;

by first unboxing to an int and only then casting to double.

EDIT:

See also http://blogs.msdn.com/ericlippert/archive/2009/03/19/representation-and-identity.aspx

Hans Kesting
That actually explains what I was missing. Thank you.
jsumners