Overridding a Property With Reflection.Emit

This isn't a bit discussion on Reflection.Emit or a how to when it comes to defining a property. To be honest, you can look that up rather easily. My issue was the fact that I could not for the life of me figure out how to override a virtual property within a base class. For example, let's assume I have this class:

public class ExampleBaseClass
{
      public ExampleBaseClass()
      {
      }

      public virtual string Value { get; set; }

}

and all we want to do is dynamically create a class that takes that as a base class and overrides Value. You'd think that would be easy (and actually it is), but no one ever shows you how... Because normally you'd do something like this:

            FieldBuilder ValueField = TypeBuilder.DefineField("_Value", typeof(string), FieldAttributes.Private);

            PropertyBuilder Property = TypeBuilder.DefineProperty("Value", PropertyAttributes.None, typeof(string), null);

            MethodAttributes GetSetAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual;

            MethodBuilder ValuePropertyGet = TypeBuilder.DefineMethod("get_Value", GetSetAttributes, typeof(string), Type.EmptyTypes);
            ILGenerator Generator = ValuePropertyGet.GetILGenerator();
            Generator.Emit(OpCodes.Ldarg_0);
            Generator.Emit(OpCodes.Ldfld, ValueField);
            Generator.Emit(OpCodes.Ret);


            MethodBuilder ValuePropertySet = TypeBuilder.DefineMethod("set_Value", GetSetAttributes, null, new Type[] { typeof(string) });

            Generator = ValuePropertySet.GetILGenerator();

            Generator.Emit(OpCodes.Ldarg_0);
            Generator.Emit(OpCodes.Ldarg_1);
            Generator.Emit(OpCodes.Stfld, ValueField);
            Generator.Emit(OpCodes.Ret);

            Property.SetGetMethod(ValuePropertyGet);
            Property.SetSetMethod(ValuePropertySet);

With TypeBuilder being the TypeBuilder for the class... This seems perfectly logical with the exception that when you try to call Value, the CLR complains that it's ambiguous... After bashing my head against a wall for a while I figured out that there were two Value properties that were defined for the object. One being the virtual, one being this new one that I created. The key to fixing this is to not define the property but only the get and set functions. As such our code above would look like this:

            FieldBuilder ValueField = TypeBuilder.DefineField("_Value", typeof(string), FieldAttributes.Private);

            MethodAttributes GetSetAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual;

            MethodBuilder ValuePropertyGet = TypeBuilder.DefineMethod("get_Value", GetSetAttributes, typeof(string), Type.EmptyTypes);
            ILGenerator Generator = ValuePropertyGet.GetILGenerator();
            Generator.Emit(OpCodes.Ldarg_0);
            Generator.Emit(OpCodes.Ldfld, ValueField);
            Generator.Emit(OpCodes.Ret);


            MethodBuilder ValuePropertySet = TypeBuilder.DefineMethod("set_Value", GetSetAttributes, null, new Type[] { typeof(string) });

            Generator = ValuePropertySet.GetILGenerator();

            Generator.Emit(OpCodes.Ldarg_0);
            Generator.Emit(OpCodes.Ldarg_1);
            Generator.Emit(OpCodes.Stfld, ValueField);
            Generator.Emit(OpCodes.Ret);

And sadly it took me searching through about 30 blog posts to find one that led me to this fix. Here's hoping this will help you before you reach the fourth page on Google. So try it out, leave feedback, and happy coding.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 4/29/2009 at 1:11 PM
Tags: , ,
Categories: C#
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Doing Image Manipulation without Losing Quality in C#

Most of the posts that I have here either do image manipulation using classes or functions that I've created myself to show how those operations occur or I use built in functions from GDI+. Now the functions that I created are not the fastest way to do something (the fastest way uses unsafe code and since the posts are suppose to be learning tools, I try to avoid going down that road) but the functions usually do a decent job when it comes to the quality of the resultant image. With GDI+ calls, you may notice that there can sometimes be a loss of resolution and overall quality. A good example is when you resize an image.

Now why is there a lose of quality? It's actually fairly simple. The default settings for GDI+ are set more for speed than quality. Specifically the smoothing, interpolation, and compositing settings.  Smoothing determines whether antialiasing is used on curves and lines to make them not seem so jagged. Interpolation determines the algorithm that is used when an image is resized, rotated, etc. And lastly compositing determines the quality/algorithm used when source pixels and destination pixels are combined (think watermarks).

Now for most people, you'll never need to touch these settings but for sake of argument, we'll say that you need to change them. Perhaps you want to make some high quality thumb nails or something... So let's see how we would do that:

        public static Bitmap HighQualityResize(Bitmap Image, int Width, int Height)
        {
            System.Drawing.Bitmap TempBitmap = Image;
            System.Drawing.Bitmap NewBitmap = new System.Drawing.Bitmap(Width,Height);
            System.Drawing.Graphics NewGraphics = System.Drawing.Graphics.FromImage(NewBitmap);
            NewGraphics.CompositingQuality=CompositingQuality.HighQuality;
            NewGraphics.SmoothingMode=SmoothingMode.HighQuality;
            NewGraphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
            NewGraphics.DrawImage(TempBitmap, new System.Drawing.Rectangle(0, 0, Width,Height));
            NewGraphics.Dispose();
            return NewBitmap;
        }

As you can see I switch the Graphics objects settings for compositing, smoothing, and interpolation to high quality. If I wanted I could set these to a number of different settings (have GDI+ do Gamma correction, bilinear filtering, etc.). But that's all there is to it. So definitely play with it a bit, leave feedback, and happy coding.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 4/28/2009 at 10:28 AM
Tags: , ,
Categories: C#
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Adjusting the Gamma of an Image Using C#

I covered how to adjust the brightness of an image last week. Today I'm going to talk about a subject that is very similar but at the same time fairly different: Gamma. Gamma determines the intensity of the light produced by a CRT... You see back in the day of CRT TVs (early portion of it anyway as this was discovered fairly early), it was thought that the intenisty of the color produced was proportional to the input voltage. However that wasn't the case. Instead they found that TVs that used same voltage showed colors in completely different intensities. What it turned out is that the intensity was dictated by the input voltage raised to the power of gamma. Gamma being pretty much being a random (as far as your concerned) number between .2 and 5, and usually centering around 2.5. What that means is your green, while a nice shade of green, may not be as green as my green, which is totally greener...

In order to combat this, most devices use gamma correction. This is done by creating an array of values that have the "corrected" colors as they should be displayed. So for instance if you have a pixel with a green value of 3, you'd look in the array in the third slot to see what value it should really be. Right about now you're wishing I'd shut up and show you how to implement it already, so here you go:

         public static Bitmap AdjustGamma(Bitmap Image, float Value)
        {
            System.Drawing.Bitmap TempBitmap = Image;
            System.Drawing.Bitmap NewBitmap = new System.Drawing.Bitmap(TempBitmap.Width, TempBitmap.Height);
            System.Drawing.Graphics NewGraphics = System.Drawing.Graphics.FromImage(NewBitmap);
            NewGraphics.DrawImage(TempBitmap, new System.Drawing.Rectangle(0, 0, TempBitmap.Width, TempBitmap.Height), new System.Drawing.Rectangle(0, 0, TempBitmap.Width, TempBitmap.Height), System.Drawing.GraphicsUnit.Pixel);
            NewGraphics.Dispose();

            int[] RedRamp = new int[256];
            int[] GreenRamp = new int[256];
            int[] BlueRamp = new int[256];
            for (int x = 0; x < 256; ++x)
            {
                RedRamp[x] = Clamp((int)((255.0 * System.Math.Pow(x / 255.0, 1.0 / Value)) + 0.5), 255, 0);
                GreenRamp[x] = Clamp((int)((255.0 * System.Math.Pow(x / 255.0, 1.0 / Value)) + 0.5), 255, 0);
                BlueRamp[x] = Clamp((int)((255.0 * System.Math.Pow(x / 255.0, 1.0 / Value)) + 0.5), 255, 0);
            }

            for (int x = 0; x < NewBitmap.Width; ++x)
            {
                for (int y = 0; y < NewBitmap.Height; ++y)
                {
                    Color Pixel = NewBitmap.GetPixel(x, y);
                    int Red = RedRamp[Pixel.R];
                    int Green = GreenRamp[Pixel.G];
                    int Blue = BlueRamp[Pixel.B];
                    NewBitmap.SetPixel(x, y, Color.FromArgb(Red, Green, Blue));
                }
            }

            return NewBitmap;
        }

The formula is fairly simple that it's using to determine the value in the arrays:

Value=((x/255)^(1/InputValue))+0.5

Where x/255 simulates the voltage (if we were talking about CRTs) and1/InputValue being the gamma. You may also notice that it calls a function called Clamp:

        private static int Clamp(int Value, int Max, int Min)
        {
            Value = Value > Max ? Max : Value;
            Value = Value < Min ? Min : Value;
            return Value;
        }

The clamp function just makes sure that we're between 0 and 255 (inclusive). Anyway, that's all there is to implementing it. Just call it, sending in your image and the gamma value (once again, your best results will be between .2 and 5). The function will in turn send back a new, gamma corrected image. So try it out, leave feedback, and happy coding.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 4/23/2009 at 9:19 AM
Tags: , ,
Categories: C#
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed