Dealing with images in content management systems
Tom Crane
16 January 2006
Navigation:
Page 1 | Page 2 | Page 3 | Page 4 | Page 5 | Samples
(Download the source code for this article)
Most web-based content management systems offer a variety of tools to
help contributors enter text. When it comes to graphics, content contributors
are usually expected to provide web-ready images to the system. This means that
either editorial users needs to know about image optimisation and web image
formats, or additional staff are required to make web-ready images out of raw
materials. This article demonstrates a technical solution to this problem.
The raw images might be from digital cameras, from mobile phones or from
scans. These will almost always be far too large, both in pixel dimensions and
file size, to be used as web images. In a typical scenario the finished images
will need to be constrained to a certain pixel size to fit into whatever
templates the site uses. For example, if we look at news stories on the
BBC
News site we can see that content images are always 203 pixels wide. Where they
appear on the home page they must also be 152 pixels high, but when they appear
alongside the text of a news story the height of the picture can vary to fit
the content. Thumbnails are 66 pixels square. We need some form of user
interface that takes a "raw" image as input and allows the non-technical user
to generate an appropriately sized image that is both aesthetically pleasing,
optimised for the web, and conforms to any arbitrary image dimension rules that
we might like to impose. Almost always a raw image will be improved for web use
by some judicious cropping.
Many content management systems offer some degree of automation for
processing images, usually confined to automatically generating thumbnails from
supplied files. While this method is good for showing you what a batch of
images contains, it seldom produces a satisfactory "teaser" thumbnail like the
ones you might find on a site homepage. Such thumbnails require human
intervention.
The solution is an ASP.NET server control that allows the end user to upload
an image from the local file system and crop, scale and optimise it to obtain a
satisfactory web image. The server control inherits from the new
CompositeControl class, which makes it easier to compose new server controls
out of existing, simpler controls. This control makes heavy use of JavaScript, DOM
and CSS on the client to power the user interface and requires a modern web
browser. It will work in Firefox across all platforms, IE6 on Windows and
Safari on MacOSX. The control looks like this when used on an aspx page:
<guild:WebImageMaker id="wim_main" runat="server" width="250"
BorderStyle="Solid" BorderColor="#c0c0c0" BorderWidth="1px"
CancelButtonText="Cancel" ConfirmButtonText="OK"
UploadButtonText="upload image..."
ImageWidth="203" ImageHeight="*"
ImageUrl=" "
WorkingDirectory="C:\imagemaker_workingdir"
Format="jpg" Quality="High" />
The key attributes here are the last 6. ImageWidth and ImageHeight dictate
the dimensions of the web image that the control will create. These properties
are actually strings which allow us to enter a "*" character, indicating that
we don't mind what one of the dimensions is. At least one of these two
properties must evaluate to a positive integer, otherwise the control doesn't
have enough information to determine the final image size. ImageUrl is used to
allow the control to render a current web image if it is being used to change
an existing web image rather than create a new one. WorkingDirectory indicates
where the control will save the images it creates. Before you can run this project
successfully you'll need to create this directory and grant the process that
ASP.NET is using write access to it. The working directory doesn't need to be
under the web root. Format and Quality dictate how the control will produce the
final web image.
The control looks like this in its "default" condition. No image has been
uploaded yet. If the user was changing an existing image then the existing web
image (the ImageUrl attribute) would be visible here instead of the default
placeholder graphic.

The file selector is a standard WebControls.FileUpload control. The user
browses the file system to find an image file to upload, then clicks the
"upload file..." button. This might take a while for a large image. Once the
form is posted the control's server-side code examines the file to check that
it is an image. It also stores the raw image dimensions for later use.
For the user to crop the image, the control must render the image back out
to the browser once the file is uploaded so that the user has a "canvas" to
work on. However, the uploaded image will often be far too big to fit into the
user's browser window, so the control needs to scale the image before rendering
it back out as a canvas. This scaling operation is nothing to do with the
creation of the final web image – it is solely to generate an appropriately
sized canvas for the user to work on. By default the control generates a canvas
that is scaled to be 4/5 of either the width or height of the user's browser
window, depending on the aspect ratio of the uploaded image. This guarantees
that the image will always be visible without scrolling regardless of the size
of the user's browser window. Client-side script stores the dimensions of the
browser window (the "viewport") in a hidden form field just before the form is
submitted.

The control renders the canvas (and some accompanying UI) in a DIV that is
positioned to appear floating above the control. Although the rendered HTML for
this DIV is nested in the control's rendered HTML, the DIV itself needs to
occupy as much screen space as possible. We wouldn't have a usable canvas if it
had to be confined within the space occupied by the control in its default
setting. So client-side script repositions the div appropriately, using CSS
absolute positioning and the z-index property to take the canvas div out of the
normal flow of the document and allow it to appear floating above the rest of
the page.
Floating above the generated canvas is the selection rectangle. This is
another DIV, with a dashed border.

Client side script responds to mouse move events, so that when the pointer
is near the edges of the div the cursor changes to a resize icon and when the
pointer is over the body of the div the cursor becomes a move icon. The user
can move and resize the selection box to select an appropriate crop. When only
one of the dimensions (ImageWidth and ImageHeight) is specified the shape of
the cropping rectangle is unconstrained – the control will scale the image so
that the specified dimension is correct, and the other dimension will end up whatever
it needs to be to match the crop selected by the user. If both dimensions are
specified then a particular aspect ratio (width/height) needs to be enforced,
so client-side script constrains the cropping rectangle to this aspect ratio as
the user drags the corners around.

Once a satisfactory crop has been selected the user presses the "OK" button.
Client-side script stores the location and size of the selection rectangle
relative to the canvas image, and a postback is initiated. On the server, these
client coordinates are transformed into coordinates on the original raw image
(the control knows the dimensions of both the original raw image and the canvas
it produced for the user to "draw" on). The original raw image is then cropped
and scaled, and saved according to the format and quality specified as
attributes of the control. The newly created web image is displayed in the
control.

The control exposes a property that allows a developer to access the created
web image (e.g., for storage in a content management system) at a later point.
Two additional features aid usability. A typical scenario where this control
might be used is to supply two related pictures for a news story – a main image
and a thumbnail. In an editing interface, two instances of the control would be
presented, one for the main image and one for the thumbnail. The first might
have ImageWidth set to "203" and ImageHeight set to "*", and the thumbnail's
control might have both ImageWidth and ImageHeight set to "66". The user will
often want to use the same raw image for both web images, with different crops.
To avoid the user having to upload the same raw image more than once, the
control makes its own thumbnail image of each raw file uploaded (not to be
confused with any images that happen to be used as thumbnails somewhere else
that a user might create using the control) and stores a key to identify the
uploaded image in the user's session. The control examines the session to see if
any images have already been uploaded and generates a UI to select an already
uploaded image if it finds any. All the user needs to do is click the image to
go straight to the canvas, bypassing the potentially lengthy upload process.

The other feature accommodates the scenario where the user already has a
web-ready image of the correct size. If the control finds that the uploaded
image is already correct it will bypass the canvas stage and just save the raw
file as the final image file.
Click here to see the control in action.
Navigation:
Page 1 | Page 2 | Page 3 | Page 4 | Page 5 | Samples