|
Take a walk on the mild side.
August 2007 - Posts
-
I have many websites where the user has the ability to upload images, mostly as logos. I am able to limit them to uploading JPG or GIF files, but it is rare when they understand picture dimension limitations. I found that I needed to resize most images. Sometimes they had to be an exact size where I would have to shrink and/or pad the file to the specified dimensions or it might be a maximum situation where the file could be "up to" xxx pixels wide or tall.
The built-in picture resizing capabilities of ASP.Net worked pretty well on JPGs. However, it was awful on GIFs. I did find some help on the Microsoft website. I took their code and modified it for my own purposes. The resizing function is below.
Public Function Resize_Image(ByVal DesiredWidth As Integer, ByVal DesiredHeight As Integer, ByVal PicturePath As String, ByVal DimensionChoice As String) As String
'get current image and size
Dim imLogo As Drawing.Image = Drawing.Image.FromFile(PicturePath)
Dim SourceWidth As Integer = imLogo.Width
Dim SourceHeight As Integer = imLogo.Height
Dim SourceFormat As ImageFormat = imLogo.RawFormat If DimensionChoice.ToLower = "exact" Then
If SourceWidth = DesiredWidth And SourceHeight = DesiredHeight Then Return ""
Else 'max
If SourceWidth <= DesiredWidth And SourceHeight <= DesiredHeight Then Return ""
End If
'determine how much to shrink
Dim Percent As Decimal = 1
Dim PercentWidth As Decimal = DesiredWidth / SourceWidth
Dim PercentHeight As Decimal = DesiredHeight / SourceHeight
If PercentWidth < 1 Or PercentHeight < 1 Then 'shrinking is necessary
If PercentWidth < PercentHeight Then Percent = PercentWidth Else Percent = PercentHeight
End If
'get destination values
Dim DestWidth As Integer = Round(SourceWidth * Percent)
Dim DestHeight As Integer = Round(SourceHeight * Percent)
Dim DestX As Integer = 0
Dim DestY As Integer = 0
If DimensionChoice.ToLower = "exact" Then
DestX = Floor((DesiredWidth - DestWidth) / 2) 'for padding if necessary
DestY = Floor((DesiredHeight - DestHeight) / 2) 'for padding if necessary
Else 'max
DesiredWidth = DestWidth 'no padding
DesiredHeight = DestHeight 'no padding
End If
'convert image to desire size
Try
Dim bmLogo As Drawing.Bitmap = New Bitmap(DesiredWidth, DesiredHeight, PixelFormat.Format24bppRgb)
bmLogo.SetResolution(imLogo.HorizontalResolution, imLogo.VerticalResolution)
Dim grLogo As Drawing.Graphics = Drawing.Graphics.FromImage(bmLogo)
grLogo.Clear(Color.White)
grLogo.InterpolationMode = InterpolationMode.HighQualityBicubic
grLogo.SmoothingMode = SmoothingMode.HighQuality
grLogo.PixelOffsetMode = PixelOffsetMode.HighQuality
grLogo.CompositingQuality = CompositingQuality.HighQuality
grLogo.DrawImage(imLogo, New Rectangle(DestX, DestY, DestWidth, DestHeight), New Rectangle(0, 0, SourceWidth, SourceHeight), GraphicsUnit.Pixel)
grLogo.Dispose()
grLogo = Nothing
imLogo.Dispose()
imLogo = Nothing
If Right(PicturePath, 3) = "gif" Then 'gif's need quantizing
Dim quantizer As New OctreeQuantizer(255, 8)
Dim quantized As Bitmap = quantizer.Quantize(bmLogo)
quantized.Save(PicturePath, SourceFormat)
quantizer = Nothing
quantized = Nothing
Else 'jpg
bmLogo.Save(PicturePath, SourceFormat)
End If
bmLogo = Nothing
Catch ex As Exception
Return Err.Description
End Try
Return ""
End Function |
I have one website where the user can upload a logo and then I resize that one image into three images - small, medium, and large sizes.
|
'save large file strFile = "LargeFile." & LCase(Right(LogoAFile.PostedFile.FileName, 3)) LogoAFile.PostedFile.SaveAs("D:\Website\images\" & strFile) 'resize image Resize_Image(150, 120, "D:\Website\images\" & strFile, "exact")
'resize for medium logo strFile = "MediumFile." & LCase(Right(LogoAFile.PostedFile.FileName, 3)) LogoAFile.PostedFile.SaveAs("D:\Website\images\" & strFile) 'resize image Resize_Image(125, 100, "D:\Website\images\" & strFile, "exact") 'resize for small logo strFile = "SmallFile." & LCase(Right(LogoAFile.PostedFile.FileName, 3)) LogoAFile.PostedFile.SaveAs("D:\Website\images\" & strFile) 'resize image Resize_Image(100, 80, "D:\Website\images\" & strFile, "exact")
|
|
-
I needed to add a blog to a website. Nothing fancy, just a simple blog, but it had to be quick. I've looked at many blogging programs over the years and eliminated them as possibilities for one reason or another. One of those was DasBlog. I was turned off by the fact that it writes the data to an XML file. I figured real software would use a database. But I was desperate and decided to give it another chance. One big thing in its favor is that it creates search engine friendly URLs. Most of the simpler blogging packages do not - they use querystring parameters. For search engine optimization, though, distinct URLs was a must. I installed DasBlog and started playing around with it. The installation was very easy. Not having a database and all the extra permissioning that goes along with it really sped things up. I was pleasantly surprised to find it had quite a few themes. It was easy to find one that looked close to our existing website and then modify it. I also rearranged the items in the right-side column. I had set it up on our test server. To get it to the live server, I just FTP'ed the whole directory, added write permission to a few folders and modified one configuration setting. Another side benefit to not having a database, is that I could tell the content writer that after entering data on the test server, she can FTP her entries to the live server herself.
I am very pleased with the performance and ease of use with DasBlog on our website.
|
-
Who hasn't built a website and had people putting garbage in the "Contact Us" form? The new version of this website, Blogiversity.org, wasn't live two days before I started receiving trash through the "Contact Us" form. I decided it was time to investigate ways to make sure it was a human filling out and submitting the form. As usual, I wanted to find a control that someone else had built and was giving away from free. God bless the internet and programmers who are very willing to share their experiences!
I found a wonderful solution for a CAPTCHA server control for ASP.NET that can be downloaded here. The article does an excellent job of explaining how it works. I had a few concerns about whether I would be able to implement this CAPTCHA control into the Community Server program (CS2007), but I had it up and running well very quickly. All it required was the following steps:
-
Put the WebControlCaptcha.dll file in the bin directory.
-
Add the following to the web.config file under httpHandlers: <add verb="GET" path="CaptchaImage.aspx" type="WebControlCaptcha.CaptchaImageHandler, WebControlCaptcha"/>
-
Put a Captcha contol and a Validate Summary control on the webpage. I didn't even have to change any of the default settings. <cc1:CaptchaControl ID="CaptchaControl1" runat="server" />
<asp:ValidationSummary ID="ValidationSummary1" runat="server" />
-
Add a reference to the assembly at the top of the webpage. <% @ Register Assembly="WebControlCaptcha" Namespace="WebControlCaptcha" TagPrefix="cc1" %>
It works beautifully. I have not had any trash posts since it was installed.
|
-
I thought I had a fairly simple task. I was displaying a very complicated report as an HTML webpage. It had five repeaters that were filled and one table I had to manually create the HTML and put it into a literal control because the calculations were too complicated for a canned report or a data control. The customer also requested it to be emailed as well to a distribution list. I thought I could copy the response stream right before it went to the browser and put the HTML in an email and send it out. I didn't even need to change the output stream, just look at it. Much to my chagrin, I discovered that you can't look at the response output stream unless you put a filter in place.
I searched the Internet trying to find someone else's solution. Most of them are in C#. I tried to convert it to VB but was unsuccessful. Finally I found someone that had provided the solution in VB here. I modified it for my own needs. The code for the new class, which I called ReportFilter.vb since so far the only need I have is to copy a report, appears below. The heart of it is in the Write Sub towards the bottom.
Public Class ReportFilter
Inherits IO.Stream
Private strmFilter As IO.Stream
Private enc As System.Text.Encoding
Sub New()
With HttpContext.Current.Response
strmFilter = .Filter
enc = .ContentEncoding
End With
End Sub
Public Overrides ReadOnly Property CanRead() As Boolean
Get
Return strmFilter.CanRead
End Get
End Property
Public Overrides ReadOnly Property CanSeek() As Boolean
Get
Return strmFilter.CanSeek
End Get
End Property
Public Overrides ReadOnly Property CanWrite() As Boolean
Get
Return strmFilter.CanWrite
End Get
End Property
Public Overrides Sub Flush()
Call strmFilter.Flush()
End Sub
Public Overrides ReadOnly Property Length() As Long
Get
Return strmFilter.Length
End Get
End Property
Public Overrides Property Position() As Long
Get
Return strmFilter.Position
End Get
Set(ByVal Value As Long)
strmFilter.Position = Value
End Set
End Property
Public Overrides Function Read(ByVal buffer() As Byte, ByVal offset As Integer, ByVal count As Integer) As Integer
If strmFilter.CanRead Then
Return strmFilter.Read(buffer, offset, count)
Else
Return -1
End If
End Function
Public Overrides Function Seek(ByVal offset As Long, ByVal origin As System.IO.SeekOrigin) As Long
If strmFilter.CanSeek Then
Return strmFilter.Seek(offset, origin)
Else
Return -1
End If
End Function
Public Overrides Sub SetLength(ByVal value As Long)
Call strmFilter.SetLength(value)
End Sub
Public Overrides Sub Write(ByVal buffer() As Byte, ByVal offset As Integer, ByVal count As Integer)
'get html in string
Dim output As New StringBuilder(enc.GetString(buffer, offset, count))
'code to email report is put here
'or you can add code to change the output StringBuilder
'...
'pass along data to response
strmFilter.Write(enc.GetBytes(output.ToString), 0, output.Length
End Sub
End Class
The webpage that builds the report and displays it simply needs to say that the response output stream for this page needs to go through the filter. That is done in the Page_Load event as shown below.
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Response.Filter = New ReportFilter
Report_Display()
End Sub
|
-
I work some in PhotoShop when designing websites or I work in a PSD file that others have created and passed along to me to add to a website. I know just enough to be dangerous. I was feeling very frustrated by how badly I was doing some processes (like selecting an item) or how confused I was by some of the adjustment controls (like Levels and Curves). I finally had the opportunity to go to an Adobe PhotoShop CS2 Conference.The conference was offer by CompuMaster. They did an excellent job.
|
-
I had one of those times when a website works just fine in development but does not work in the live environment. I hate it when that happens.
There was a Flash object embedded on one of the website pages and it had an associated audio file of type .flv. The Flash would show up on the webpage, but the audio file could not be heard. I did an internet search hoping someone had come across the same problem and had a fix for it. I found the solution on the Adobe website. Of course, they made it clear it was NOT a problem with Flash. It was a configuration issue with IIS 6.0 on Windows 2003 Server, but they were kind enough to post it.
The nice part is that it does not require a website adjustment on every site that needs it. You make one change to IIS and a Flash flv file will work on any website hosted there.
-
Open IIS. Right-click on the local computer and select Properties.
-
Click the MIME Types button.
-
Click the New button and fill in .flv for Extension and flv-application/octet-stream for MIME type.
Problem solved!
|
-
For one of my ASP.Net applications, I am required to generate monthly invoices in PDF format upon demand. Knowing that the number of users could grow to a great many, I was hoping to find a way where I did not have to write each PDF to the hard drive before putting it in a browser window for the customer. Luckily, this is quite easily done using the Crystal Reports that comes with Visual Studio 2005.
I usually build my Crystal Reports off of a dataset .xsd file. Rather than having the report attempt to connect to the database by passing in log in information, I declare a new dataset from an .xsd file, fill it myself with a data reader and then load the dataset into the report.
'load data set
Dim dset As New dsStatement
dset.Statement.Load(dr) '(data reader filled previously)
'fill report
rptDoc.Load(Server.MapPath("reports/Statement.rpt"))
rptDoc.SetDataSource(dset)
From there I can convert the Crystal Report to a PDF and save it in a stream and then return the stream as the Response.
'display report
Dim strm As Stream = rptDoc.ExportToStream(CrystalDecisions.Shared.ExportFormatType.PortableDocFormat)
Dim bytes(strm.Length) As Byte
strm.Read(bytes, 0, strm.Length)
Response.Clear()
Response.ClearHeaders()
Response.ContentType = "application/pdf"
Response.AddHeader("Content-Length", UBound(bytes) + 1)
Response.AddHeader("Content-Disposition", "inline; filename=Statement.pdf")
Response.BinaryWrite(bytes)
Response.Flush()
|
-
One problem when converting a website from one programming language to another is broken links. The search engines can keep cached versions of the older pages with their old extension (in this case .php) for a long time. I didn't want anyone following a link with .php in the URL to get the missing page error so I went through several steps to get the ASP.Net website to process those requests.
- Get IIS to handle page requests with the .php extension.
- View the properties of the website in IIS. Select the Home Directory tab and click the Configuration button which opens a new window. The easiest way to get the executable path is to click on any ASP.Net extension, such as .asax, then click the edit button. Right-click in the executable field and select Copy then Cancel to close the window.
- Click the Add button to open the Add/Edit Application Extension Mapping window. Right-click in the Executable field and select Paste. In the extension field type in .php. Make sure to UN-check the box that says "Verify that file exists".

- Keep clicking OK until all of the windows are closed.
- Get the website to handle the page request with the .php extension.
- Create a new class to process the request. I called the class "PHPHandler.vb". The code is as follows:
Imports System.Web
Public Class PHPHandler
Implements IHttpHandler
Public Sub ProcessRequest(ByVal context As System.Web.HttpContext) Implements _
System.Web.IHttpHandler.ProcessRequest
Dim request As HttpRequest = context.Request
Dim response As HttpResponse = context.Response
' This handler is called whenever a file ending in .php is requested.
'A file with that extension does not need to exist.
response.Status = "301 Moved Permanently"
response.AddHeader("Location", "http://www.Blogiversity.org")
End Sub
Public ReadOnly Property IsReusable() As Boolean _
Implements System.Web.IHttpHandler.IsReusable
Get
Return False
End Get
End Property
End Class
This code redirects every .php request to the new home page in ASP.Net. You can get a lot fancier. Simply do a test for the requested page and then do the redirect to the new page, such as:
If request.ServerVariables("PATH_INFO").ToLower.IndexOf("oldpage.php") > -1 Then
response.Status = "301 Moved Permanently"
response.AddHeader("Location", "http://www.Blogiversity.org/newpage.aspx")
End If
- The last step is to modify the web.config file so that it will call the PHPHandler code when a request for a .php file comes in. Include the following lines in your web.config file:
<system.web>
<httpHandlers> <add verb="*" path="*.php" type="PHPHandler"/> </httpHandlers> </system.web>
|
-
I've searched for and tried many free ASP.Net Content Management Systems (CMS). My favorite is DotNetNuke. They have made substantial improvements to the system. One of the biggest is their search engine friendly URLs. They used to pull out pages based on a querystring with the ID of the page in it. Search engines would not recognize these as independent pages. Now every page has a (more) normal looking URL that simply ends with Default.aspx. You can title each page with key words and these will appear in the URL. You can also specify different key words and meta description for each page. I built a site for my aikido school (North Florida Aikido) using DotNetNuke. I started off with one of the standard skins and was able to modify it enough so that the North Florida Aikido website doesn't look like every other site built with DotNetNuke. Modifying or creating a skin is not for the faint of heart, but I've had enough style sheet experience and certainly enough ASP.Net experience to do it.
I especially like that the Frequently Asked Questions module can use AJAX to populate the answers instead of relying on a postback. I find the photo gallery to be a little quirky, but I expect I'll figure out the best way to work with it and then it won't give me any more problems. I was pretty impressed with the events calendar. I did some tweaky of the code right in the desktop module, but I was pleased with its overall look and performance. I wrote my own stored procedure in the database so that I could insert events right into the database without having to go through the web interface. I needed a lot of recurring events (such as aikido class times), but I needed the ability to edit each one to include the instructor's name that was teaching on that day. I had been hoping that once a recurring event was scheduled I would be able to edit each one independently, but no such luck. My stored procedure:
.style1 {
FONT-SIZE: 8pt; FONT-FAMILY: "Courier New", Courier, mono
}
.style2 {
FONT-SIZE: 8pt; COLOR: #0000ff; FONT-FAMILY: "Courier New", Courier, mono
}
.style4 {
FONT-SIZE: 8pt; COLOR: #009900
}
ALTER PROCEDURE dbo.AddEvent (
@EventDateBegin datetime,
@EventDateEnd datetime,
@EventTimeBegin datetime,
@Duration int,
@EventName nvarchar(100), @Category int )
AS
INSERT Events (PortalID,ModuleID,EventDateBegin,EventDateEnd,
EventTimeBegin,Duration,EventName, EventDesc,Importance,CreatedBy,
Every,Period,RepeatType,Notify,Approved,Signups,MaxEnrollment,
EnrollRoleID,EnrollFee,EnrollType,PayPalAccount,PayPalPassword,
Cancelled,ImageURL,ImageType, ImageWidth,ImageHeight,ImageDisplay,
Location,Category,Reminder,TimezoneOffset,SendReminder, ReminderTime,
ReminderTimeMeasurement,ReminderFrom,SearchSubmitted )
VALUES (0,380,@EventDateBegin,@EventDateEnd,@EventTimeBegin,
@Duration,@EventName, '',2,'1','0',N'','N ',
N'Ref. Event Notification for Event: {0} on {1} @ {2} to {3}, {4}',
1,0,0,N'',0,'FREE','admin@northfloridaaikido.com','',0,'','',0,0,0,0,
@Category, N'You requested notification for Event: {0} on {1} @ {2} to {3}, {4}',
-300,0,8,'h',N'admin@northfloridaaikido.com',0 )
GO
I call the stored procedure using a loop in Query Analyzer:
declare @DateStart datetime,
@TimeStart datetime
set @DateStart = '07/02/07'
set @TimeStart = '07/02/07 18:30'
while @DateStart < '01/01/09'
begin
exec AddEvent @DateStart, @DateStart, @TimeStart, 105, 'Aikido 6:30-8:30PM',6
set @DateStart = dateadd(dd,7,@DateStart)
set @TimeStart = dateadd(dd,7,@TimeStart)
end
This saved a lot of time. I do have to edit the event description to include the instructor's name afterwards, but I only get those a month at a time so it isn't too time consuming at that point.
|
-
I am a big fan of the ASP.Net AJAX Control Toolkit. I've used the Accordion, the Animation, and the Collapsible Panel for their "gee whiz" factor. The calendar has been invaluable. But the control I appreciate the most is the Masked Edit. I use it for dates and phone numbers, for credit card numbers and their expiration dates, and for SSNs. The only problem I've come across is that I had the Masked Edit for the credit card expire date set up as 99/9999 (for month and year) and I had the mask type set to number. The first person that entered a month of 07 found that the first zero was disappearing when they tabbed off of the field. Apparently, the masked edit doesn't like a number to start off with a zero. I changed the mask type to None and then it worked just like intended. I also changed the mask type to None on the SSN, although I don't believe a valid SSN will start with zero.
|
-
My boss got the idea into his head that we needed a Wiki website. I wasn't familiar with what a Wiki website was so I checked out the only one I know about, Wikipedia. I was very surprised to find that when you edit a page, the interface is mostly just text. They offer you a few buttons to help with formatting, but the buttons only create more text. It is definitely not a WYSIWYG (what-you-see-is-what-you-get) interface. I didn't want to write a Wiki website myself, so I searched the internet for a free ASP.Net Wiki program.
There were not nearly as many free ASP.Net programs available as there are for blogging or content management. The few that are available are limited in capabilities or they haven't been upgraded in years. The one I decided to give a try was ScrewTurn Wiki. It had a very recent release and it looked like it was being upgraded regularly. It also looked similar to the Wikipedia interface. I was hesitant, though, because it appears to be European in origin. In the past I have tried to use some software from Europe before but found that it had parts not yet converted to English. No such problems with ScrewTurn Wiki. I got up and running pretty quickly. I did go with the data being saved into text files, but I might try at a later time to store the data in an SQL Server database.
| |
|