Subscribe | Alerts via Email
View All Quotes
“The key to being an effective programmer is maximizing the portion of the program that you can safely ignore while working on any one section of code.”
-Steve McConnell
<October 2007>
SunMonTueWedThuFriSat
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

©2010 Cal Zant
Sign In
Total Posts: 106
This Year: 5
This Month: 1
This Week: 0
Comments: 2

This is a class I created to handle thumbnail generation and other typical image resizing tasks.  I think it is flexible and simple enough to be used in a variety of situations.  I will define the class and then give a couple of examples of how to use it.

public static class ImageProcessor
{
    /// <summary>
    /// Resizes the image located at the given originalRelativePath, making its longest side equal to the given maxSize 
///
(keeping it proportional), and then saves it to the location indicated by the saveToRelativePath parameter. /// </summary> public static void CreateThumbnail(string originalRelativePath, string saveToRelativePath, int maxSize) { Bitmap originalImage = new Bitmap(HttpContext.Current.Server.MapPath(originalRelativePath)); Bitmap newImage = CreateThumbnail(originalImage, maxSize);         
        FileStream thisFS = new new FileStream(HttpContext.Current.Server.MapPath(saveToRelativePath), FileMode.Create);
        n
ewImage.Save(thisFS, ImageFormat.Jpeg); originalImage.Dispose(); newImage.Dispose(); } /// <summary> /// Returns a Bitmap object that represents the image located at the given relativePath, resized so that it's
/// longest side is
equal to the given maxSize (keeping it proportional). /// </summary> public static Bitmap CreateThumbnail(string relativePath, int maxSize) { Bitmap originalImage = new Bitmap(HttpContext.Current.Server.MapPath(relativePath)); return CreateThumbnail(originalImage, maxSize); } /// <summary> /// Returns a Bitmap object (which is just a generic image object that isn't necessarily related to the .bmp
/// filetype) that is the
same image is the given originalImage, but scaled down to the given size. If it is
/// a vertical image the height would be equal to
the max size, and if it was a horizontal image the width would
/// be the maxSize ... but it always keeps the image proportional.
/// </summary> public static Bitmap CreateThumbnail(Bitmap originalImage, int maxSize) { float newWidth, newHeight; if (originalImage.Width >= originalImage.Height) { newWidth = maxSize; newHeight = (newWidth * (float)originalImage.Height) / (float)originalImage.Width; } else { newHeight = maxSize; newWidth = (newHeight * (float)originalImage.Width) / (float)originalImage.Height; } // Don't ever enlarge the picture ... if the user is trying to resize it to a size that is larger than
// the original, simply
return the same size image as the original with the border around it. if (newHeight >= (float)originalImage.Height || newWidth >= (float)originalImage.Width) { newHeight = (float)originalImage.Height; newWidth = (float)originalImage.Width; } Bitmap newBitmap = new Bitmap(originalImage, (int)newWidth, (int)newHeight); Rectangle recBorder = new Rectangle(0, 0, (int)newWidth - 1, (int)newHeight - 1); Graphics thisGO = Graphics.FromImage(newBitmap); thisGO.DrawRectangle(new Pen(Color.Black), recBorder); originalImage.Dispose(); return newBitmap; } }

You could call the code a variety a ways ... here are two examples or how it might be used:

string originalImagePath = Server.MapPath("/images/Original.jpg");
string thumbnailImagePath = Server.MapPath("/images/Thumbnail.jpg");
ImageProcessor.CreateThumbnail(originalImagePath, thumbnailImagePath, 300);

...

Bitmap thumbnail = ClassLibrary.ImageProcessor.CreateThumbnail(new Bitmap(thisFileUpload.PostedFile.InputStream), 50);
thumbnail.Save(thumbnailImagePath, System.Drawing.Imaging.ImageFormat.Jpeg);
Friday, October 12, 2007 8:15:06 AM (Central Standard Time, UTC-06:00)  # 

I have been a long time user of iTunes (started around version 3), and openly admit that in the past it has been a much better product than Windows Media Player and other media player applications ... at least for me.  But, a few weeks ago I heard Scott Hanselman mention in one of his podcasts, that iTunes has been on a downhill spiral since the release of version 7.  There are constant, sometimes daily, updates that prompt me download a new 50MB install file (not just a patch), and really 99% of the changes in those updates are for the new iPhone functionality that Apple thought would be a good idea to tightly bind to iTunes.  But those aren't the only issues. 

I can't remember the native burning software in iTunes ever working on my Dell Precision M90 laptop.  I have read some forum posts that said Apple simply doesn't have 64 bit drivers yet.  Whatever the reason, after I installed iTunes on a clean machine I got an error saying:

iTunes was not property installed. If you wish to import or burn CDs, you need to reinstall iTunes.

There is a 64 bit driver available from Gear Software that I was able to download and install, and it fixed this issue.  However, from that point on every time I opened iTunes I got the error message shown below:

iTunes cannot locate the CD Configuration folder, so you cannot import or burn CDs

After searching and reading a few more forums, I figured out this folder was "missing" from C:\Program Files (x86)\iTunes.  I don't usually make it a habit to go in and delete random folders from the Program Files directory ... so I am thinking this folder was never really there.  Luckily, I had a friend who was able to make a copy of his "CD Configuration" directory from one of his machines.  I copied it into the iTunes directory, and viola ... no more error messages, and CD ripping and burning actually work in iTunes.  You can download a copy of that folder here.  Thanks for the painful process Apple.

Tuesday, October 09, 2007 1:51:16 PM (Central Standard Time, UTC-06:00)  # 

I struggled with this error message for quite some time on one of my home computers.  When I tried to install some software like Adobe Reader or iTunes, the installation would fail and show me a popup alert saying "Invalid Drive: P:\".  This was really frustrating, because it was keeping me from installing some programs I really needed.  

I originally mapped the P: drive to the shared "Pictures" folder on my Windows Home Server (which is very cool by the way), and also changed the "My Pictures" folder for all users to point to that drive instead of the default location.  I did this so everyone would access and store pictures in the same place, and that would be on the Home Server which I had set up to have raid-like fault tolerance (can't loose those pictures).  Since that time I figured out a different way to do this, but although I had disconnected or "unmapped" the P: there was still a key deep in the registry pointing to this location for "My Pictures" ... and that was causing the conflict.

To resolve the issue, all I had to do was go into the Registry Editor (run "regedit") and navigate to folder shown below (the path is shown at the bottom of the window).

Remove registry key referencing mapped drive

I just changed the value of the "My Pictures" key to point to the default location of "C:\Users\Cal\Pictures" ... and the next time I tried to install those programs everything went smoothly.

Sunday, October 07, 2007 3:57:14 PM (Central Standard Time, UTC-06:00)  # 

I've found it useful a few times to map a folder residing on a local machine to a drive letter.  Here is a simple command line script that allows you to do just that:

subst G: "C:\Program Files (x86)"

This would create a new drive named "G:", which would appear like an entirely seperate hard drive or partition ... but really would just be a shortcut to "C:\Program Files (x86)".  If you want to "delete" the mapped drive later, just run this:

subst G: /d

Thursday, October 04, 2007 10:28:36 AM (Central Standard Time, UTC-06:00)  # 

In SQL you can use the LIKE operator to perform simple keyword searches.  For example:

SELECT CustomerID, CompanyName, ContactName
FROM   dbo.
Customers
WHERE  CompanyName LIKE '%St%' OR ContactName LIKE '%St%'

Using the Northwind database, the script above would return 21 results:

CustomerID  CompanyName                  ContactName
----------------------------------------------------------------
ALFKI       Alfreds Futterkiste          Maria Anders
BERGS       Berglunds snabbköp           Christina Berglund
EASTC       Eastern Connection           Ann Devon
ERNSH       Ernst Handel                 Roland Mendel
FRANR       France restauration          Carine Schmitt
GALED       Galería del gastrónomo       Eduardo Saavedra
GROSR       GROSELLA-Restaurante         Manuel Pereira
HILAA       HILARION-Abastos             Carlos Hernández
HUNGC       Hungry Coyote Import Store   Yoshi Latimer
...

However, this can be slow because it usually involves a full table scan.  SQL Server has a much more efficient way to perform full-text searches, which utilizes the Microsoft Search Engine.  This involves creating a full-text catalog, which is external to the database (actually stored outside normal database structure) so it requires a little configuration but has the potential to significantly improve search performance.

Defining A Full-Text Index
To define a full-text index, just navigate to the table you want the index on using SQL Management Studio, right click on the table name, and choose "Define Full-Text Index..." as shown below:

SQL Server Define Full-Text Index

A wizard will appear like the one shown below, and you will need to configure what you want to index and how you want SQL to keep that index up-to-date (remember ... it is stored outside the normal database structure, so SQL has to keep it in-sync).  Most the time you don't need to change the wizard's default selections, but the next few screen shots show how I configured a full-text index for Northwind's Customer table.

SQL Server Full-Text Indexing Wizard

Full-Text Indexing Wizard Select Table Columns

Full-Text Indexing Wizard Select a Catalog

After you have the index created, you can use the FREETEXT, FREETEXTTABLE, CONTAINS, and CONTAINSTABLE keywords (for more info on the functionality that each provides go here).  You could rewrite the query from the earlier example to be more like this:

SELECT   C.CustomerID, C.CompanyName, C.ContactName, R.[Rank]
FROM     dbo.Customers C INNER JOIN
         CONTAINSTABLE(dbo.Customers, (CompanyName, ContactName), '"St*"') R ON C.CustomerID = R.[KEY]
ORDER BY R.[Rank] DESC

Which would yield the following results:

CustomerID  CompanyName                  ContactName      Rank
----------------------------------------------------------------
LAZYK       Lazy K Kountry Store         John Steel       112
VICTE       Victuailles en stock         Mary Saveley     112
HUNGC       Hungry Coyote Import Store   Yoshi Latimer    96
LETSS       Let's Stop N Shop            Jaime Yorres     96
QUICK       QUICK-Stop                   Horst Kloss      96

The script using LIKE returned 21 results, but the one using the full-text index only returned 5 results.  However, that is actually a good thing, because the full-text index only returned relevant results (the ones someone would most likely be looking for if they searched for "St").  The LIKE clause returned any row that had "st" somewhere in it ... whether it was the first of a word or buried in the middle of it.  The full-text index is smart enough to only return words that start with "St," but notice that doesn't necessarily mean it is at the start of the string or preceded by whitespace ... because it returned "Quick-Stop" as well.  A hidden benefit of using full-text indexes is that the Microsoft Search Engine will intelligently parse the text, and yield more relevant results.

When you search a full-text index using the CONTAINSTABLE method, you are also able to utilize a new column named rank.  This column indicates how relevant the match is compared to the rest of the results.  In this example, the rank column isn't too useful.  But if you were searching a long product description, this column could become very useful.  I chose this really simple example to just show the bare bones functionality of searching SQL, but when you are searching columns with a lot of text (like a product description) ... that is when this approach really pays off in terms of efficiency, only returning relevant results, and providing a rank of how relevant a result was in comparison to the rest of the set.

Wednesday, October 03, 2007 3:05:10 PM (Central Standard Time, UTC-06:00)  #