effengud software http://www.effengud.com It's Simple. It's Elegant. It's effengud!™ Wed, 15 Feb 2012 15:19:57 +0000 http://wordpress.org/?v=2.8.4 en hourly 1 A Faster VBScript Base64 Encode http://www.effengud.com/index/2009/09/03/a-faster-base64-encode/ http://www.effengud.com/index/2009/09/03/a-faster-base64-encode/#comments Thu, 03 Sep 2009 18:10:07 +0000 admin http://www.effengud.com/wp/?p=37 When passing this encrypted data over the wire, it is BINARY data, which means that you can’t really pass it as part of a querystring. So many developers try saucing it up with a Server.URLEncode function, but what they don’t always realize is that Microsoft’s URLEncode function does NOT play well with embedded ASCII NULs. In fact, it assumes that the ASCII 0 (zero) signifies the end-of-string marker, and will stop as soon as the first NUL is encountered.

So how do we pass binary information?

The solution I have recommended (and used myself) is to further ENCODE the data with Base64 encoding. And the solution I have often recommended is the one found at Motobits.com (found here: . It is a proven solution and I have personally used it in many of my own projects. Recently, however, one of our own applications seemed to be getting bottle-necked at the Base64 encode and decode functions. The application in question had to encode blocks of data that were 64K-bytes in size, and it sometimes had to do several thousand of those blocks.

So I started looking at the old MotoBits code, with an eye toward optimizing it. And what I ended up with is new version that is much faster (over 40 times faster in most cases!). Interested? Well, if you’re currently doing Base64 encoding with VBScript, you should be.

As an example (rough and unscientific, but useful for comparison), to encode 10 blocks of 64K Bytes each, the original Motobits version takes 13.94 seconds on a dual-core system. On that same system, the new version takes about 0.31 seconds. So, whereas the former version managed around 47,000 bytes per second, the new one does over 2,097,000 in that same time period.

Here is the new, optimized code:

Function FasterBase64Encode(inData)
  ' Notice: This routine is based on:
  '2001 Antonin Foller, Motobit Software, http://Motobit.cz

  'Speed enhancements by Mike Shaffer

  Const Base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
  Dim arybase64(64)
  For intX = 1 To 64
     aryBase64(intX) = Mid(Base64,intX,1)

  Dim cOut, sOut, I, L2
  Dim nGroup, pOut, sGroup
  Dim ary1(), aryCTR

  aryCTR = -1

  L2 = Len(inData)
  ReDim ary1(Int(L2*1.5))

  'For each group of 3 bytes
  For I = 1 To L2 Step 3    

    nGroup = Oct(&H10000 * Asc(Mid(inData, I, 1)) + &H100 * _
                 MyASC(Mid(inData, I + 1, 1)) + _
                 MyASC(Mid(inData, I + 2, 1)))

    'Add leading zeros
    nGroup = Right("00000000" & nGroup, 8)

    'Convert To base64
    aryCTR = aryCTR + 1
    ary1(aryCTR) = arybase64(CLng("&o" & Mid(nGroup, 1, 2)) + 1)
    aryCTR = aryCTR + 1
    ary1(aryCTR) = arybase64(CLng("&o" & Mid(nGroup, 3, 2)) + 1)
    aryCTR = aryCTR + 1
    ary1(aryCTR) = arybase64(CLng("&o" & Mid(nGroup, 5, 2)) + 1)
    aryCTR = aryCTR + 1
    ary1(aryCTR) = arybase64(CLng("&o" & Mid(nGroup, 7, 2)) + 1)

  ReDim preserve ary1(aryCTR)
  sOut = Join(ary1,"")

  ' Perform fixup
  Select Case L2 Mod 3
    Case 1: '8 bit final
      sOut = Left(sOut, Len(sOut) - 2) + "=="
    Case 2: '16 bit final
      sOut = Left(sOut, Len(sOut) - 1) + "="
  End Select

  FasterBase64Encode = sOut

End Function

Function MyASC(OneChar)
  If OneChar = "" Then MyASC = 0 Else MyASC = Asc(OneChar)
End Function
http://www.effengud.com/index/2009/09/03/a-faster-base64-encode/feed/ 0
RC4 Encryption with VBScript http://www.effengud.com/index/2009/08/04/rc4-encryption-with-vbscript/ http://www.effengud.com/index/2009/08/04/rc4-encryption-with-vbscript/#comments Tue, 04 Aug 2009 17:23:40 +0000 admin http://www.effengud.com/wp/?p=32

I recently had a need to query a remote server via HTTP and receive rather sensitive information. SSL was not an option because of the ISP’s setup. For these reasons (and a few others), I found myself in need of a good, general-purpose encryption module. For the purposes of prototyping and early testing, I whipped one up using the old stand-by system of circular-XOR’s. Geez, that’s quick and dirty, but it’s about as secure as a message sent on a postcard in the US Mail. My own home-grown cryptanalysis tools made quick work of cracking the code.

Obviously, I was going to need something much stronger than that for the site once it went into general production. I also wanted something that I could code completely in VBscript for ASP. Mainly because I wanted to be able to use the code in any ASP environment, regardless of any ISP’s component registration policies (or lack thereof), etc. In addition, I wanted something that was publicly proven and recognized as being fairly secure.

I chose the streaming-encryption algorithm known as RC4. RC4 is generally regarded as being “strong”, and has no known attacks (although a relatively weak class of keys has been identified – the discussion of which is beyond the scope of this document).

Other strengths of this algorithm include decent encryption/decryption speed and relative ease of coding in VBscript. It is also interesting to note the symmetrical nature of the RC4 algorithm. What I mean by ’symmetrical’ is that the same routine is called to do both encryption and decryption. To encrypt data, simply pass the data and the password you choose to the routine to receive encrypted data. To decrypt, pass the encrypted data and the same password. (Note: It is possible to encrpyt the data multiple times, even with different passwords on each iteration. To decrypt, simply reverse the steps you followed during encryption).

There’s an interesting story behind this algorithm. Well, OK, maybe it’s not interesting if you’re not a self-proclaimed geek. But here it is anyway. RC4 was invented by RSA Data Security. It is not a patented algorithm, but it is protected under federal law as a trade secret by RSA. In 1994, an anonymous person posted what they called the (do your Dr. Evil air-quotation marks here) “source code” to the RC4 algorithm. No one (outside of RSA) knows whether or not the “source code” that was posted was the actual RC4 algorithm or not, but it certainly does produce exactly the same output as the RSA product. So, in fact, the “source code” presented here can only be said to be “RC4-like” in nature… there’s no telling if it actually is RC4 as implemented by the RSA company.

One word of warning is in order here: If you plan to use this code outside the US, or if you plan to include it in a product that you are going to ship outside the US, please make yourself aware of the legal restrictions of crypto export. Always remember… guns don’t kill people, algorithms kill people.

I have included a sample test harness (rc4test.html and rc4test.asp) to help you see how the algorithm (contained in rc4.inc) works. The output of the test looks like this:

RC4 Test Harness

Plaintext was: “To be or not to be: that is the question, whether tis nobler in the mind to suffer the slings and arrows of outrageous fortune.” can be anagrammed to form: “In one of the Bard’s best-thought-of tragedies, our insistent hero, Hamlet, queries on two fronts about how life turns rotten.”
Encrypted text: 0E%89%02y%D9%9B%F7%C0%D48%D21%10%BF%0De%1A%7E%F9%C6%BE%B1%B8h4%ED%A6%1D%8B%27%B4O%3DXAk2%3F%88%98%E592s%DE%8C%E6%E1IM%0A%7F%C5f%C7V%3E%EC%19%C7%18%DA%25%B4%C1%2C%12%B8%80c%14%BB%E1h%A7m%E5%E8%E9%F6%21%04%9F%2B%0E%E3%B2%9D%A8%FB%FA%D7T%7B%FAQ%3Dw%E21%E4%29%FA%23%FB%F9%1D%0AT%BF%0E%FF%94%7Dm%B4%2A%C8%3E%01J%AF%C8%7EB%2CF%F0q%F8%AD%9EFB%DAo%17%AF%7C%3A%13T%B3%9E%B5%11%12%7F%94%3D%1C%0C9%21%26%AE%06%E6%E6%F0%0Em%90%EC%12%039%1DG%D7%BA%9C%A1%04%BF%FA%F9%A3%ED%C1l%E8AEM%CB%B4%1Ba%D2%ADT%BCZ%04%C2%1Bvv%F9%8F%DF%B8U%8C%17%8F%BF%A7%D1kV%D2%B2%C6%3F%2E%BFD%C3%E1Ht%2E%EF%A7%C6%0E%FFRFU%92%22%CC%FA%92%5E%DA%FAn%AB5%E1%DB%D9%83%D9%E8%C2i%ADP%8Fk%E7+%1E%A9%2C%1C6%16%8D%27%AF%B6R%C50%81KJ%18%F8%0CQ%2EU%04%C3%5B%9E%3E

Hex dump of encrypted string:

30 45 89 02 79 D9 9B F7 C0 D4 38 D2 31 10 BF 0D 65 1A 7E F9 C6 BE B1 B8 68 34
ED A6 1D 8B 27 B4 4F 3D 58 41 6B 32 3F 88 98 E5 39 32 73 DE 8C E6 E1 49 4D 0A
7F C5 66 C7 56 3E EC 19 C7 18 DA 25 B4 C1 2C 12 B8 80 63 14 BB E1 68 A7 6D E5
E8 E9 F6 21 04 9F 2B 0E E3 B2 9D A8 FB FA D7 54 7B FA 51 3D 77 E2 31 E4 29 FA
23 FB F9 1D 0A 54 BF 0E FF 94 7D 6D B4 2A C8 3E 01 4A AF C8 7E 42 2C 46 F0 71
F8 AD 9E 46 42 DA 6F 17 AF 7C 3A 13 54 B3 9E B5 11 12 7F 94 3D 1C 0C 39 21 26
AE 06 E6 E6 F0 0E 6D 90 EC 12 03 39 1D 47 D7 BA 9C A1 04 BF FA F9 A3 ED C1 6C
E8 41 45 4D CB B4 1B 61 D2 AD 54 BC 5A 04 C2 1B 76 76 F9 8F DF B8 55 8C 17 8F
BF A7 D1 6B 56 D2 B2 C6 3F 2E BF 44 C3 E1 48 74 2E EF A7 C6 0E FF 52 46 55 92
22 CC FA 92 5E DA FA 6E AB 35 E1 DB D9 83 D9 E8 C2 69 AD 50 8F 6B E7 20 1E A9
2C 1C 36 16 8D 27 AF B6 52 C5 30 81 4B 4A 18 F8 0C 51 2E 55 04 C3 5B 9E 3E 

Decrypted text:
“To be or not to be: that is the question, whether tis nobler in the mind to suffer the slings and arrows of outrageous fortune.” can be anagrammed to form: “In one of the Bard’s best-thought-of tragedies, our insistent hero, Hamlet, queries on two fronts about how life turns rotten.”

22 54 6F 20 62 65 20 6F 72 20 6E 6F 74 20 74 6F 20 62 65 3A 20 74 68 61 74 20
69 73 20 74 68 65 20 71 75 65 73 74 69 6F 6E 2C 20 77 68 65 74 68 65 72 20 74
69 73 20 6E 6F 62 6C 65 72 20 69 6E 20 74 68 65 20 6D 69 6E 64 20 74 6F 20 73
75 66 66 65 72 20 74 68 65 20 73 6C 69 6E 67 73 20 61 6E 64 20 61 72 72 6F 77
73 20 6F 66 20 6F 75 74 72 61 67 65 6F 75 73 20 66 6F 72 74 75 6E 65 2E 22 20
63 61 6E 20 62 65 20 61 6E 61 67 72 61 6D 6D 65 64 20 74 6F 20 66 6F 72 6D 3A
20 22 49 6E 20 6F 6E 65 20 6F 66 20 74 68 65 20 42 61 72 64 27 73 20 62 65 73
74 2D 74 68 6F 75 67 68 74 2D 6F 66 20 74 72 61 67 65 64 69 65 73 2C 20 6F 75
72 20 69 6E 73 69 73 74 65 6E 74 20 68 65 72 6F 2C 20 48 61 6D 6C 65 74 2C 20
71 75 65 72 69 65 73 20 6F 6E 20 74 77 6F 20 66 72 6F 6E 74 73 20 61 62 6F 75
74 20 68 6F 77 20 6C 69 66 65 20 74 75 72 6E 73 20 72 6F 74 74 65 6E 2E 22 

Encryption took: 0.0078125 seconds (±55 msec)

(Note that the output of the encrypted text is shown in ‘urlencoded’ form. This is because it may contain illegal characters for a web browser. IMPORTANT NOTE: Microsoft’s URLEncode function does NOT work if there are embedded ASCII NULs in the data you’re encoding… the function assumes that the ASCII 0 is an end-of-string marker, and thus will not encode past that point)

Overview: This article contains a decent encryption tool that you may find useful. Read up on encryption technology to determine if this algorithm is strong enough for your needs. Don’t give this code to anyone who doesn’t love baseball and apple pie.

Test the script by clicking here

Article collateral materials:

    View/download RC4.INC in text format
    View/download RC4TEST.HTML in text format
    View/download RC4TEST.ASP in text format

http://www.effengud.com/index/2009/08/04/rc4-encryption-with-vbscript/feed/ 0
Improving the “Calculating the Distance Between Cities” Algorithm http://www.effengud.com/index/2009/08/04/improving-the-calculating-the-distance-between-cities-algorithm/ http://www.effengud.com/index/2009/08/04/improving-the-calculating-the-distance-between-cities-algorithm/#comments Tue, 04 Aug 2009 12:29:01 +0000 admin http://www.effengud.com/wp/?p=61 Calculating the Distance Between Cities". That article talked about finding the distance between cities as being a useful way to determine, for example, which of a company's many locations might be closest to a particular customer. ]]>

In that example, your store database may consist of several dozen to several hundred records (one for each store), and for each record you would have to perform the distance calculation. This is not so bad. But what if you had over 1,000 locations? Or what if you wanted to find all cities located within a particular radius from a customer, regardless of whether or not you have a store there?

In this case, you would certainly NOT want to loop through all cities within your database making the distance calculation. That would take a VERY long time. You might, in a flash of inspiration, attempt to perform the distance calculation only for cities within that customer’s state… but that would not work very well for people who live near a state’s border, or for people who live, say, in Rhode Island.

This article details a method for dramatically reducing the amount of processing necessary to find all locations within a certain radius.

By first performing a rough trim of the cities list based on latitude and longitude, we limit the number of calculations we must make. By using the algorithm below, we can accomplish that, as well as ensure that we are grabbing all cities within a particular area, regardless of state boundaries, etc.

Given a customer’s latitude (iStartLat) and longitude (iStartLong), and the radius we wish to search (iRadius, in miles), the following algorithm will return the latitude and longitude range for cites we will evaluate (using the formula provided in the last article). NOTE: Be aware that — as in the last article — this algorithm is accurate enough for most e-commerce applications, but NOT for navigational applications:

iRadius = 150

LatRange = iradius / ((6076 / 5280) * 60)
LongRange = iRadius / (((cos(cdbl(iStartLat * _
3.141592653589 / 180)) * 6076.) / 5280.) * 60)

LowLatitude = istartlat – LatRange
HighLatitude = istartlat + LatRange
LowLongitude = istartlong – LongRange
HighLongitude = istartlong + LongRange

Now you can create a SQL statement which limits the recordset of cities in this manner:

FROM Locations
WHERE Latitude <= [HighLatitude]
AND Latitude >= [LowLatitude]
AND Longitude >= [LowLongitude]
AND Longitude <= [HighLongitude]

(Note: This algorithm works pretty well for US and Canadian cities. Adapting the algorithm to other regions may require changing the comparison order due to negative latitudes, etc.)

Performing the distance calculation (covered in the previous article) on the resulting recordset ensure that you are not wasting too many CPU cycles on cities that are obviously outside the radius you have specified.

http://www.effengud.com/index/2009/08/04/improving-the-calculating-the-distance-between-cities-algorithm/feed/ 0
Calculating the Distance Between Cities http://www.effengud.com/index/2009/08/04/calculating-the-distance-between-cities/ http://www.effengud.com/index/2009/08/04/calculating-the-distance-between-cities/#comments Tue, 04 Aug 2009 12:21:54 +0000 admin http://www.effengud.com/wp/?p=57

Do you remember sitting in high-school, taking your first trigonometry course, wondering to yourself, “When will this crap ever apply to me in the ‘Real World’?” Well, my friend, today is that day. No, I am not going to make you dig out your old trig textbooks… nor am I going to go into the theory behind how these routines work. After all, these articles are meant to provide quick solutions to real-world problems, not to torture you with the arcana of your teen years.

So let’s just say that these functions are derived from spherical trigonometry, and leave it at that. “But wait,” I can hear some of my geek friends starting to say, “the planet we live on is more of an oblate spheroid, not a perfect sphere.” To which I would say, “That is correct.” I would then probably also add, under my breath, “Get a life,” but that is a topic for another article entirely. These routines should be plenty accurate for the type of applications I mentioned above. In general, you can expect that the distance you receive will average an accuracy of +/- one percent.

The code below includes three routines. The main one, called GetDistance, calculates the distance between two points on the globe. To use it, you must pass the latitude and longitude (in decimal degrees, e.g. 32.9697) of both points. You also pass the unit of measure that you’d like the results returned in, either ‘K’ for kilometers, ‘M’ for statute miles, or ‘N’ for nautical miles.

Here is an example of the output produced by the code below:

Calculating the distance between Dallas (75248) and San Antonio (78201)

262.513422981729 Miles

422.474402195107 Km

228.117927751138 Nautical Miles

Dallas’ decimal latitude of 32.9697 can also be shown as 32° 58′ 10″

At this point, you may be wondering how to obtain information such as latitudes and longitudes for various points on the globe. effengud software sells a high-speed COM component and the complete US Zip code database for as little as $99. Click here for more details.

The DegToRads function is mainly used in support of the GetDistance routine, but can be used by itself. It simply converts decimal degrees to radians.

The DecimalDegToDMS routine can be used to convert decimal degrees (e.g. 32.9697) to a more readable degrees/minutes/seconds (e.g. 32° 58′ 10″).

So, using our example above, how would we go about creating a store finder application? It’s actually pretty straightforward. You could ask a visitor to your website to give you their zip code. You would then look up their zip code in your handy-dandy zip code database (mentioned above). This would yield their latitude and longitude. You would then cycle through your database of store locations, calculating the distance from the user to every store, sorting them by distance. When finished, present the user with the three stores that are closest to them.

NOTE: This article has a follow-up article that explains how to greatly reduce the search time required for a dealer locater application. To read it, click here.

Adding geographical calculations to you website can provide users with interesting and useful information. I hope this article has helped give you the headstart you need to implement such features. Feel free to >contact me with any enhancements you make to this software!

Article collateral materials:

    View/download the script in text format

http://www.effengud.com/index/2009/08/04/calculating-the-distance-between-cities/feed/ 0
Timing the Execution of an ASP Script http://www.effengud.com/index/2009/08/04/timing-the-execution-of-an-asp-script/ http://www.effengud.com/index/2009/08/04/timing-the-execution-of-an-asp-script/#comments Tue, 04 Aug 2009 12:10:10 +0000 admin http://www.effengud.com/wp/?p=50

Actually, there are several possible solutions for the task of timing VBScript routines and functions. You can obtain ActiveX components that act as a stopwatch, but that solution will usually cost you a few dollars. It would also force you to use a component that has to be registered on the server (which many people cannot do because of hosting restrictions) and/or would force you to use a component for which you have no source code.

You can also use Javascript within the HTML page to perform timing. This has the drawbacks of being less portable (because you are relying on the browser’s implementation of Javascript) and somewhat less accurate (too many dependencies on network speed, browser/machine/interpreter efficiency, etc.)

One gentleman suggested grabbing the current time (TIMEVALUE(NOW)) at the beginning and the end of a section of code and using the DATEDIFF function to obtain elapsed times. Unfortunately, this approach can only be accurate to approximately 1/2 second in any given case (when averaging times over several iterations), so is probably not suitable.

Fortunately, there is a very simple way to perform timing on your ASP code.

Examine this code:

Dim Iterations, StartTime, ElapsedTime, AverageTimePerIteration, X

Iterations = 1000
StartTime = Timer

For X = 1 TO Iterations
‘… do operations to be timed

ElapsedTime = Timer – StartTime
AverageTimePerIteration = ElapsedTime / Iterations

The TIMER function returns the elapsed time in seconds (and fractional seconds) since Midnight on the previous day. An important fact to keep in mind with the TIMER function is that it is only accurate to roughly 50 milliseconds. As a result, if you want to time a routine or a certain
patch of code with any accuracy that is useful, you will want to do multiple iterations of that code (similar to the example above) and then divide the elapsed time by the number of iterations (this yields an average time per iteration that is reasonably accurate).

When using the TIMER function to benchmark certain sections of code to determine which is more efficient, we are usually looking for relatively LARGE differences in time. For example, I don’t really care if, over 10,000 iterations of a routine, one method outperforms the other by .002 seconds overall. So in the final analysis, for this type of benchmarking, the actual accuracy of the timer is not nearly as important as its timing consistency.

Here, then, is some code that will help you get started in timing your own routines. To use this code, simply place this line in your variable declaration section:

Dim StopWatch(19)

and then include these two routines:

sub StartTimer(x)
‘::: Here we start the timer :::
StopWatch(x) = timer
end sub

function StopTimer(x)
‘::: Here we ’stop’ the timer and calculate :::
‘::: the elapsed time (allowing for the :::
‘::: midnight wrap-around. NOTE: These :::
‘::: routines should not be used to time :::
‘::: very long events (>1 hour) or very :::
‘::: short events (< 100 milliseconds) :::
EndTime = Timer

'Watch for the midnight wraparound...
if EndTime < StopWatch(x) then
EndTime = EndTime + (86400)
end if

StopTimer = EndTime - StopWatch(x)
end function

(Note: You could keep this code snippet as an INCLUDE file.)

With this code, you have access to 20 individual stopwatches (you can easily increase that number to whatever you wish by changing the DIM statement). To start a stopwatch, use:

StartTimer x

where x is the number of the stopwatch you wish to use (example: to start stopwatch #7, use StartTimer 7).

When you’re ready to end the stopwatch and get the elapsed time, simply reference the StopTimer function, e.g.:

Elapsed = StopTimer(x)

Response.Write “Elapsed time was: ” & Elapsed

Notice that the StopTimer function does not reset the initial time. Calling the StopTimer multiple times (without resetting the timer with StartTimer) will continue to return total elapsed time for that particular timer. If you like, you could add this line to the end of the StopTimer function to make the timer automatically reset (and act more like a ‘lap’ counter):

StopWatch(x) = Timer

Summary: This is a very easy to use timing system that is free and uses no components. It is reasonably accurate, especially when averaged over
multiple iterations of a function. It is also very easy to use, and did I mention, it’s free?

Remember… Optimize ’til you die!

Article collateral materials:

    View/download source code for the timing script in text format

http://www.effengud.com/index/2009/08/04/timing-the-execution-of-an-asp-script/feed/ 0
Determining Image Properties using ASP http://www.effengud.com/index/2009/08/01/determining-image-properties-using-asp/ http://www.effengud.com/index/2009/08/01/determining-image-properties-using-asp/#comments Sat, 01 Aug 2009 16:42:48 +0000 admin http://www.effengud.com/wp/?p=25

In a recent small project, I needed a way to display a series of images in a square area (150×150 pixels). The images in question are uploaded by our customers, and we have no real control over what size or color depth (or even type) they are. While it’s easy to force a resize of an image to, say, 150 pixels wide x 150 pixels high, you run the risk of stretching the image incorrectly in one dimension. And if you simply decide to force the width of the image to 150 and leave the height proportional (or vice-versa), then you may exceed the boundaries of 150 pixels.

This is a problem.

Fortunately, the solution is relatively easy. All we need is a tool that will report the dimensions (and color depth) of any image. I looked out on the web and found several that will do the trick. Of those, some were relatively inexpensive, and some were even free, but all of them were distributed as components. While
there is certainly nothing wrong with that, I wanted something that could run entirely within an ASP page, without needing the ability to register a component on the server (since many people are unable to do so).

Therefore, what follows is a set of routines (written in VBScript for your ASP pages) which will determine the height, width, and color depth of any GIF, JPG, BMP or PNG file. Additionally, these routines do not rely on the file extension to determine the graphic file-type. In other words, you can dynamically point this routine to any filename, regardless of name and extension, and determine if is a valid graphic file (actually, there is a very small chance [roughly one in 17 million] that a non-graphic file chosen at random will appear to be a graphics file, so it would be more appropriate to say that this routine determines PROBABLE graphic formats).

Here are some possible uses for these routines:

  • intelligent image scaling (as mentioned above)

  • Check user file upload, to see if the graphical image
    adheres to your requirements (e.g. make your upload function
    accept only files that are 640×480 or less and 256 colors)

  • perform directory scans and gather information on
    your graphics files

  • Show graphical directories (using thumbnails) on the web

The comments in the routine should be sufficient to help you get started. The only real thing you need to understand is the format of the call to the main routine, gfxSpex:

xxx = gfxSpex(strFlnm, lngWidth, lngHeight, lngDepth, strImageType)


  • strFlnm => Filespec of file to read

  • lngWidth => width of image

  • lngHeight => height of image

  • lngDepth => color depth (in number of colors)

  • strImageType => type of image (e.g. GIF, BMP, etc.)

The routine returns FALSE if the file was not recognized as a valid image type, and TRUE if it is ‘probably’ a valid image file.

So there you have it, a complete new tool for your arsenal, with all VBScript source code, and best of all, IT’S FREE!

Article collateral materials:

    Download the IMGSZ.ASP source code in text format

http://www.effengud.com/index/2009/08/01/determining-image-properties-using-asp/feed/ 0
Proportional Image Resizing(within a constrained area) http://www.effengud.com/index/2009/08/01/proportional-image-resizing/ http://www.effengud.com/index/2009/08/01/proportional-image-resizing/#comments Sat, 01 Aug 2009 14:59:14 +0000 admin http://www.effengud.com/wp/?p=12 History

The IMGSZ code presented in my earlier article, Determining Image Properties in ASP, was written in response to my need to be able to fit images proportionally within a given area. My client had asked me to develop a photo gallery application for their site, and the photo gallery was to display photos surrounded by a complex graphical ‘photo album’ motif. As a result, all photos (regardless of their original size) needed to ‘fit’ within a defined pixelspace.

Many questions ensued: So how would I accomplish that within HTML? Would I need to buy a component? And is ‘pixelspace’ even a real word? Although I mentioned the possibility of enhancing the IMGSZ routines to allow for proportional resize, I left it up to the readers of that original article to enhance those routines to do the proportional sizing. However, so many of you have asked for the resizing routine that I am pleased (relieved?) to offer it here now.

Why Do I Need It?

If you are just learning HTML (or any of its younger variants) you already know that the IMG tag has HEIGHT and WIDTH properties that can be used to force an image to a particular size. However, it has no easy way to do a proportional resize that fits in a desired area. For example, let’s say you’re showing images in a table for an on-line product catalog. To make things look nice, you’re defining the size of the image presented to 100×75 pixels. So you may decide to use WIDTH="100" HEIGHT="75" in your IMG tag for each picture. What will happen is that images may get squashed or stretched in ways that you (and your customers) do not find pleasing. This IMGSZ add-on function will allow you to overcome that problem.

How Does It Work?

The ImageResize function is passed an image filename, a maximum width and a maximum height. The function returns either a HEIGHT=xxx or a WIDTH=xxx string that you embed in your IMG tag to provide the proportional resize.

So How Do I Use It?

Using the function can be as simple as embedding a function call in your IMG tag. For example, the following code will present an image proportionally in a 100×75 pixel area:

response.write "<img src=""graphic.gif"" " & ImageResize(strImageName, 100, 75) & ">"

The parameters passed to the function are as follows:

ImageResize Parameters
Property Description
strImageName The actual filename (on the server’s drives)
of the image you will display
intDesiredWidth The width constraint
intDesiredHeight The height constraint

As a further example, let’s look at some simple test code. This code will look at your server’s C:\ drive, root directory, and display all GIF images that it finds there in a table. The images will be proportionally resized to fit within a 75×45 pixel area. Be sure to view the live demo!

   ':::                                                   :::
   ':::  SCRIPT:   testpropresize.asp                     :::
   ':::  AUTHOR:   Mike Shaffer                           :::
   ':::  DATE:     11-Jan-01                              :::
   ':::  PURPOSE:  Test/show the operation of the resize  :::
   ':::            (proportional) function                :::
   ':::                                                   :::
  <!--#INCLUDE FILE='imgsz.asp'-->
  <!--#INCLUDE FILE='propresize.asp'-->
' To test, we'll just try to show all files with a .GIF
' extension in the root of C: by fitting them to a common
' area (75 pixels x 45 pixels)

dim objFSO, objF, objFC
dim f1, w, h, c, strType

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objF = objFSO.GetFolder("c:\")
Set objFC = objF.Files

response.write "<table border=""1"" cellpadding=""5"">"

For Each f1 in objFC
  if instr(ucase(f1.Name), ".GIF") then
     response.write "<tr><td>" & f1.name & "</td><td>" & _
         f1.DateCreated & "</td><td>" & f1.Size & "</td><td>"

     if gfxSpex(f1.Path, w, h, c, strType) = true then
        response.write w & " x " & h & " " & c & " colors</td>"
        response.write "<td><img src=""" & f1.Path & """ " & _
              ImageResize(f1.Path, 75, 45) & " border=""1""></td>"
        response.write " </td><td align=""center"">bad image</td>"
     end if

     response.write "</tr>"

  end if

response.write "</table>"

set objFC = nothing
set objF = nothing
set objFSO = nothing

[View the live demo!]

Enough Yakking Already, Show Me The Code!

The code for the function (below) is quite simple, really. Here is a description of the steps it follows to do its magic:

  • First, call the gfxSpex function (contained in IMGSZ.ASP) to determine
    the height and width (and color depth and validity!) of the image.
  • Determine the target image ratio and the file’s image ratio
    (width divided by depth)
  • If the file’s image ratio is greater-than the target image ratio,
    then we know that we have to size proportionally based on WIDTH,
    otherwise we size proportionally based on HEIGHT (and if it was
    not a valid image, return an empty resize string)

Oops! I’m yakking again, here’s the code, already!

function ImageResize(strImageName, intDesiredWidth, intDesiredHeight)
   dim TargetRatio
   dim CurrentRatio
   dim strResize
   dim w, h, c, strType

   if gfxSpex(strImageName, w, h, c, strType) = true then
      TargetRatio = intDesiredWidth / intDesiredHeight
      CurrentRatio = w / h
      if CurrentRatio > TargetRatio then  ' We'll scale height
         strResize = "width=""" & intDesiredWidth & """"
         ' We'll scale width
         strResize = "height=""" & intDesiredHeight & """"
      end if
      strResize = ""
   end if

   ImageResize = strResize
end Function


You can integrate the PROPRESIZE.ASP contents into the IMGSZ.ASP code if you like. Note that this does NOT perform an actual resize of the graphical image file, only the visual representation of the image. What this means is that if you have an image that is 800×600x24 bits which is 1 megabyte in size, and you ask the routine to scale the image to a 100×75 pixel area, you will STILL be downloading that entire 1 megabyte of picture information from the server. If you want to do TRUE thumbnail file creation (on disk) you will need to obtain any one of the graphical components available today that offer this feature.

Article collateral materials:

Download the PROPRESIZE.ASP source code in text format
Download the IMGSZ.ASP source code in text format

http://www.effengud.com/index/2009/08/01/proportional-image-resizing/feed/ 0
effengud software – facelift http://www.effengud.com/index/2009/08/01/effengud-software-facelift/ http://www.effengud.com/index/2009/08/01/effengud-software-facelift/#comments Sat, 01 Aug 2009 14:47:49 +0000 admin http://www.effengud.com/wp/?p=3 Welcome to the rebirth of effengud software. effengud software offers tools for web developers (mainly classic ASP and ASP.NET), including a ZIP code distance finder, dealer locator, simple portfolio manager tool, and many relevant and helpful source code snippets.

http://www.effengud.com/index/2009/08/01/effengud-software-facelift/feed/ 0