I worked this week on a Console application that would allow me to resize all images in a folder to thumbnail size of 128 by 128 pixels. This small project was meant to correct a problem on a web site. My friend can upload any kind of images (bmp, jpg, gif, png) of any size to her web site. The images are then displayed in a catalogue. There are up to 20 images per page. For consistency, every image are set to be displayed in a 128x128 pixels. When the user click on the image, it is displayed in it original size in another browser:
<a href='http://www.website.com/Uploads/Catalogue/myImage001.jpg'
target="_blank" id="lnkImage">
<img id="imgItem" title="My Image"
src="../Uploads/Catalogue/myImage001.jpg"
style="height:128px;width:128px;border-width:0px;" />
</a>
The problem with this html is if the image is large, it will take time to download. On the other hand, if the image is small, the user does not get anything better when clicking on the image to look at it in another browser because it is of the same size.
To correct this, I suggested her to always upload image files in their original size, the larger the better. And I would take care of displaying images on the right size.
So I develop a class that I would add to the business logic layer of her web site and also to a console application which would run once to resize all of her images already uploaded on her web server.
Here is the class I creates;
2: ''' Resize images to 128x128px
4: ''' <param name="sourceFilename">
5: ''' Complete input file name</param>
6: ''' <param name="targetFilename">
7: ''' Complete output file name
9: ''' <remarks></remarks>
10: Public Shared Sub ResizeImageBad( _
11: ByVal sourceFilename As String, _
12: ByVal targetFilename As String)
14: Dim img As System.Drawing.Image = Nothing
15: Dim graph As Graphics = Nothing
16: Dim smallImg As System.Drawing.Image
17: Dim rectangle As Rectangle
18: Dim smlSize As Size = New Size(128, 128)
21: img = System.Drawing.Image.FromFile(_
23: smallImg = New Bitmap(_
27: rectangle = New Rectangle(_
33: graph = Graphics.FromImage(smallImg)
34: graph.CompositingQuality = CompositingQuality.HighQuality
35: graph.SmoothingMode = SmoothingMode.HighQuality
36: graph.InterpolationMode = InterpolationMode.Bicubic
37: graph.DrawImage(img, rectangle)
39: smallImg.Save(targetFilename)
41: Catch ex As Exception
42: cLogEventViewer.LogError( _
43: System.Reflection.MethodBase.
GetCurrentMethod.DeclaringType.Name & _
44: " - Exception Resize Image - " & _
48: If Not img Is Nothing Then
53: If Not graph Is Nothing Then
When I ran the console application targeting a folder containing only jpg, gif or jpg files, the console application throw exceptions for gif files. The png files were not resized and fortunately the jpg were ok.
Here is the log error from the event viewer:
"A Graphics object cannot be created from an image that has an indexed pixel format. "

After a few readings, I found out that the problem was at the pixel format level. In the code sample I provided earlier, I used the pixel format provided by the System.Drawing.Image object instance loaded from the file name as you can see on line 26.
I changed the pixel format to System.Drawing.Image.PixelFormat.Format24bppRgb which provides 24 bits per pixel, 8 bits for Red, 8 for Green and and 8 for Blue. This change stopped the errors. The GIF files were resized and their weight were lighter. Unfortunately, when I tried to view the image applications I used sent an error on opening.
I search a little further and I added another filter on the file,
graph.PixelOffsetMode = PixelOffsetMode.HighQuality
that I inserted between line 34 and 35. Also, I looked for the ".gif" extension at the end of the file name. If the file name ended with ".gif", I then specified that specific format:
smallImg.Save(targetFilename, Imaging.ImageFormat.Gif)
Also, I changed the InterpolationMode to HighQualityByCubic which provides a higher quality after resizing the GIF file.
Let's have a look at the images. On the next image, on the left, is the original GIF image and on the right is the resized GIF image.
As you can see, the image on the right, after resizing has lost some quality.
Well... I have looked for quite some time now on how I could solve the quality issue and I must admit it, I am now clueless. To complete the application, however, I decided to reformat the GIF to JPEG. doing this solves completely the quality issue but does not answer how I could resize GIF images.
If someone has an answer, I am curious to know how you did it.
But for now, here is the method I use to resize images:
1: ''' <summary>
2: ''' Resize images to 128x128px
3: ''' </summary>
4: ''' <param name="sourceFilename">Complete input file name</param>
5: ''' <param name="targetFilename">Complete output file name</param>
6: ''' <remarks></remarks>
7: Public Shared Sub ResizeImage( _
ByVal sourceFilename As String, _
ByVal targetFilename As String)
8:
9: Dim img As System.Drawing.Image = Nothing
10: Dim graph As Graphics = Nothing
11: Dim smallImg As System.Drawing.Image
12: Dim rectangle As Rectangle
13: Dim smlSize As Size = New Size(128, 128)
14:
15: Try
16: img = System.Drawing.Image.FromFile(sourceFilename)
17: smallImg = New Bitmap(smlSize.Width, smlSize.Height, PixelFormat.Format24bppRgb)
18: rectangle = New Rectangle(0, 0, smlSize.Width, smlSize.Height)
19:
20: graph = Graphics.FromImage(smallImg)
21: graph.CompositingQuality = CompositingQuality.HighQuality
22: graph.SmoothingMode = SmoothingMode.HighQuality
23: graph.PixelOffsetMode = PixelOffsetMode.HighQuality
24: graph.InterpolationMode = InterpolationMode.HighQualityBicubic
25: graph.DrawImage(img, rectangle)
26:
27:
28: If targetFilename.LastIndexOf(".gif") > 0 AndAlso targetFilename.EndsWith(".gif") Then
29: targetFilename = targetFilename.Replace(".gif", ".jpg")
30: smallImg.Save(targetFilename)
31: Else
32: smallImg.Save(targetFilename)
33: End If
34:
35: Catch ex As Exception
36: cLogEventViewer.LogError( _
37: System.Reflection.MethodBase.GetCurrentMethod.DeclaringType.Name & _
38: " - Exception Resize Image - " & _
39: ex.Message & " " & _
40: ex.StackTrace)
41: Finally 'Clean up!
42: If Not img Is Nothing Then
43: img.Dispose()
44: img = Nothing
45: End If
46:
47: If Not graph Is Nothing Then
48: graph.Dispose()
49: graph = Nothing
50: End If
51: smlSize = Nothing
52: rectangle = Nothing
53: End Try
54: End Sub
Have a good one!
Cheers!
Patrice
Why should I use Nullables? What are they for? Why have they added the Nullables to the .Net Framework 2.0?
These are questions I asked myself. And because you are good people, I will share my thoughts with you. Isn't it wonderful? Nah! I'm just kidding. In fact, the following post is the product of some readings on the topic and I started using it in my day-to-day coding because it answered a real issue.
First thing first. Let's consider the following scenario: a form on a web page somehow bound to a database. On the form, there are several kind of inputs: textboxes, dropdownlists, radiobuttons, checkboxes, textboxes for date/time and so on. What if some fields are not mandatory? It means these fields may be left empty. How should you treat an empty field considering that the database accepts null values?
How do you manage the situation? Because, philosophically speaking, an absence of value is a value. It means the user did not want to add his input, for any reason, on the form.
With value types however, how could you move that piece of information from the form to the database knowing value types cannot be null (C#).
A Value type cannot be null because its value is not a pointer to an address in memory but the value itself. Whereas the reference type is a pointer to an address in memory. A null value represents an address in memory, x00000000. So setting a reference type to null is in fact pointing to an address in memory. When times come to instantiate the object, the pointer is redirected to the address in memory where the object is (somewhere on the heap).
There have been some thoughts spent over this to overcome the impossibility of assigning a null value to value types. Some have thought about adding a bite to all value types where this extra bit would serve as a flag to indicate whether or not the value is null. Although this possibility seems sexy, it seems it would have been a nightmare to manage and moreover to validate the flag whenever accessing its value. For instance, what if a Byte could have an extra bite to flag its has a null value. By definition, a Byte is defined with 256 possibilities ranging from 0 to 255 (00 to FF). An extra bite would mean 257 possibilities (there is the nightmare).
Another way to represent the null value is to use a default values throughout the application. The problem with this approach is to select a value that will be never use.
A third way is to wrap the value type in a reference type, such like the Object class or a custom class. Although it seems practical, it is however costly on memory and performance.
With the coming of the .NET Framework 2.0 and the Generics, the Framework addresses this issue with the Nullable<T> type. This type is a Generic class with a type value constraint. Since only type values can not be null, it makes sense.
Let's see how we can use the Nullable<t> Type:
1: public static void ShowNullable()
2:{
3: //Nullable<T> aInt = null;
4: Nullable<int> aInt = null;
5:
6: try
7: {
8: int assignerInt = aInt.Value;
9: }
10: catch (InvalidOperationException ex)
11: {
12: Console.WriteLine("Exception of type
InvalidOperationException: {0}", ex.Message);
13: }
14: catch (Exception ex)
15: {
16: Console.WriteLine("Exception de type
System.Exception: {0}", ex.Message);
17: }
18:
19: //Using the HasValue property
20: if (aInt.HasValue)
21: Console.WriteLine("Value: {0}", aInt);
22: else
23: Console.WriteLine("Value: null");
24:
25: //Using GetValueOrDefault
26: Console.WriteLine("Default value (with a parameter):
{0}", aInt.GetValueOrDefault(-5));
27: Console.WriteLine("Default value (without a parameter):
{0}", aInt.GetValueOrDefault());
28:}
On line 4), we see how a Nullable can be declared. Like Generics, the Nullable is fully qualified with a type parameter specified between angle brackets. The initial value of aInt is null. When you try to retrieve a Nullable value having a null value, it throws an InvalidOperatorException. To prevent the exception from being thrown, it is best to test the Nullable with the HasValue property. The property returns false when it has null as a value. You can process the value according to it. Another feature of the Nullable is the GetValueOrDefault where it returns a default value when the Nullable is null. You have the choice to assign yourself the default value to be returned in case the Nullable is null, or you let the Framework return the default value (0, false, date.MinVale, and so on).
For C# users, there are two things worth mentioning. First is the shortcut for declaring a Nullable. The other is the shorcut for the GetValueOrDefault method. Let's have a look at the following code sample:
1: public static void ShowNullableOperators()
2: {
3: Nullable<int> a = 1;
4: int? b = null;
5: int? c = null;
6: c = a ?? 3;
7: Console.WriteLine("Value of a: {0};
Value of b: {1},
Value of c with operator ??: {2}", a, b, c);
8: a = null;
9: c = a ?? 3;
10: Console.WriteLine("Value of a: {0};
Value of b: {1},
Value of c with operator ??: {2}", a, b, c);
11: }
On line 3), it is the usual Nullable declaration. On the next line, it is the shortcut for declaring a nullable. In this example, I have declare a Nullable of type int. I also assigned a null value to it. On the sixth line, it is the default value comparator. This operator first evaluate the left argument, in this case a, to determine if it has a null value. If it is not a null value, it returns the value. Otherwise, it returns the right value.
Conclusion
The Nullable type is a convenient type to use when a real type may be assigned to a null value. The few properties available are significant and useful. The HasValue property gives the opportunity to the programmer to decide the logic to be applied in the case of a null value. If no logic is required, the GetValueOrDefault method is a good alternative.
This post concludes the topics I covered four weeks ago in a lunch meeting. As you can see, there was a lot of stuff but it was a good study that covered some of the most important new features in .NET Framework 2.0.
Cheers!
Patrice
Sorry for taking so long to write the last part. I got a busy week last week with a few parties, a girlfriend birthday, an interview with a potential client bewise - which I will come over in a near future - and so on.
The last post was on three fundamental considerations of the Generics: Generic constraints, generics types and methods and generic type inference. When I review the second part, I believe I went over the type constraints a little too quickly and I consider I should have spent more time discussing and implementing examples to demonstrate how to efficiently use these. I took notice of it and I should come back to it when time will allow me to do so.
Today, we shall discuss of two things. How the JIT compiler manages the Generics and the Generic classes available in the .NET Framework.
JIT Compiler
The main task of the Just In Time - JIT - Compiler is to translate the IL, the Intermediate Language, to the native language in order to be executed by the computer.
The JIT Compiler produce different code for each type value but shares some native code regarding the generics for the reference types. It can do this because the compiler knows the length in memory of each reference, which is 32 or 64 bits depending on the architecture of the machine. An array of references will always be of the same size in the memory, whatever it is in the array, because the reference of the array is a pointer placed on the stack. Items in the array are however place on the heap and thus, dynamically created whenever needed and using the required memory they have to.
There are performance issues when using arraylist that are annihilated when using Generics. For instance, when someone used an arraylist of Bytes in .NET 1.1, each item had to be boxed and then to get a hold on the reference of the boxed value. When using a Generic List<T> there is no boxing/unboxing effect. Also, each item of the list is, for instance, a Byte instead of an Object. The array is of the right type and in memory is the right size.
This gives a better efficiency, saves memory, and is faster on runtime because there is no time lost on boxing or unboxing, there is no validation when unboxing and the Garbage Collector does not have to get involved when unboxed values are no more referenced.
Generic Classes
1. List<T>
The Generic List<T> is the counterpart of the arraylist in the .NET 1.1. There are a few functionalities and caracteristics that existed in arraylist that were not implemented in the Generic List<T>. Among them, the Missing in Action methods are:
- Adaper
- Clone
- FixedSized
- Repeat
- SetRange
- Synchronized
We can make an old API into a Generic List by implementing the IList and IList<T> interfaces.
The new functionalities are:
1. ConverAll: Converts each item of one type to another type and returns a list of the later.
2. Exists: Checks if at least one element in the list meets the predicate.
3. TrueForAll: Check if every element in the list meets the predicate
4. FindFirts, FindLast, FindAll: Find an element in the list.
5. RemoveAll: Remove all elements in the list that meets the predicate
6. ForEach: It is not the ForEach iterative structure but this method allowes to perform an action on each item of the list.
2. Dictionary<TKey, TValue>
The Generic Dictionary<,> is the counterpart of the HashTable in the .NET 1.1. Because in the .NET 2.0 the HashTable implements the IEqualityComparer interface, some functionalities available with the Dictionary<,> are also available with the HashTable. However, the most meaningful difference between the two is their behaviour when retrieving a value associated to a key.
If we ask for a value with a key not present in the dictionary, the HashTable will return a null value. The dictionary<,> will throw a KeyNotFoundException.
Both supports ContainKeys which retrieve the value associated to the key, if present, place it in the output parameter and returns true. Otherwise, it returns false and place the default value in the output parameter.
3. Queue<T>, Stack<T>
Both are lists that do not allow random access to their elements. Accessing items at random offers poor performances. However, when retrieving elements in the proper order, these list are quite effective.
Queue<T> is a FIFO, First In First Out list. To add an item, we have to use the Enqueue method. When adding an object to a queue, the object is added at the end of the list. To retrieve an item, we have to use the Dequeue method and the first object in the list is removed from the list.
To get the next object in the queue or the stack without removing it from the list, we can use the Peek method.
Speaking of the stack, it is a FILO, First In Last Out (or a LIFO, Last In First Out depending on how you see your half filled (or is it empty) glass of water)) list. To add an item, we use the Push method which adds an item at the beginning of the list. To get (and remove) an item from the list, we use the Pop method. It retrieves the last object put in the list.
4. SortedList<TKey, TValue>, SortedDictionary<TKey, TValue>
The sortedList allows access to its elements through an index. The sortedDictionary, however, is through a key. The most significant carateristic of both generic classes is that when enumerating items, they are sorted by their key.
Another thing worth mentioning is when using the sortedlist, that list is more memory efficient in contrast to the sortedDictionary. The sortedDictionary is more faster when adding unsorted items. However, when items are sorted, the sortedlist is more faster than the sortedDictionary.
5. LinkedList<T>
This is a new list in .NET 2.0. What is it exactly? It is a chained list where each item is a node linked to previous node and linked to the next node. This list is quite efficient when you need to iterate from the beginning to the end or from the end to the beginning. However, random access is not efficient and is rather slow.
Conclusion
This was the third post out of three on Generics. In this third part of the sequel, we examined how the JIT Compiler worked when faced with Generic and where were the advantages of using the Generics. We also summarized the Generic classes available in the .NET Framework. We saw that each class had its own advantages and taking advantage of it is merely a question of which context is the most favourable.
We could write until tomorrow morning about the Generics. However, there is only one thing you must have in mind though. And it is the fact that they are quite more effective and convenient to use than their counterpart (arraylist or hashtable).
Mots clés Technorati :
.NET,
.NET 2.0,
Generics