CodeSnippet: Scanning with WIA & OCR with Office

23 September 2008 Tags  , , , ,

Scanners are perhaps becoming less and less used as we all move towards a paperless environment with digitals bills and digital photos, but a lot of "official" documentation must always be presented with the original physical copy. The wife and I have a huge collection of such documents which have been horribly archived in several filing cabinets – finding the right document is often a nightmare, let alone using any of the information in them. To combat this, I've started on a document manager which (aims to) make it a smooth process from scanning, archiving, searching, tagging, etc all in one.

I thought I'd share the scanning code section, because while scanning wasn't the easiest thing to dig up, it still wasn't half as daunting as I thought it would be. Further down you'll also see code to do optical character recognition (OCR) – that is converting a scanned text document into usable text.

TWAIN or WIA?

In years past, TWAIN (commonly known as Technology Without An Interesting Name) was the way to perform scanning, so that was my starting point on my dig for scanning code. However, I came across a mention of Windows Image Acquisition in my scanners drivers.

"In comparison to TWAIN, WIA is said to be more flexible, because it is a standardized interface that doesn't require a tight bundling of scanner software and driver (TWAIN-only scanners are often limited to functions that are enabled in its driver-software-bundle). Most recent scanners support WIA."

(source: Wikipedia)

Lift the image from a physical file into memory

To access WIA in .NET, you'll need to add a reference to the COM library, "Microsoft Windows Image Acquisition Library v2.0" (wiaaut.dll).

using WIA;

….

const string wiaFormatJPEG = "{B96B3CAE-0728-11D3-9D7B-0000F81EF32E}";
CommonDialogClass wiaDiag = new CommonDialogClass();
WIA.ImageFile wiaImage = null;

wiaImage = wiaDiag.ShowAcquireImage(
        WiaDeviceType.UnspecifiedDeviceType,
        WiaImageIntent.GrayscaleIntent,
        WiaImageBias.MaximizeQuality,
        wiaFormatJPEG, true, true, false);
wia_1 

This isn't the only way to perform a WIA scan, but it is a very quick and easy way to do it. A standard dialog will appear asking you to select the scanner, and then another dialog will give you a few options (such a previewing, image quality, image mode, which source - by that I mean a document feeder or flatbed depending on your scanners capabilities).

wia_2

Doing something with the scan

Once the document is scanned in you have to figure out what you want to do with it. If it was a photo for example, simply saving it to JPEG may be suffice, but if it is document you may want to perform OCR to extract the text first.

Saving to JPEG

Saving to JPEG is very easy, wiaImage.SaveFile("temp.jpg");

If you wanted to do more with the JPEG (resize, colour change, filtering, or simply just display in your app) but still wish to treat it as an image, you need to get the image data into either a System.Drawing.Image (WinForms) or System.Windows.Controls.Image (WPF).

WIA.Vector vector = wiaImage.FileData;
Image image = new Image();
image.Source = BitmapFrame.Create(new MemoryStream((byte[])vector.get_BinaryData()));

OCR

OCR is by no means a small task to undertake by yourself, but luckily Office (2003 and up) includes an API named Microsoft Office Document Imaging  (MODI) you can program against to let Office process the image for you. Unfortunately, MODI isn't installed by default with Office 2007 but it is easy enough to add by running the Office setup again, selecting "Add or Remove Features", and then selecting "Scanning, OCR and Indexing Service Filter"

install_modi

All Office OCR operations must go through the COM library, "Microsoft Office Document Imaging 12.0 Type Library" (that's for Office 2007) (MDIVWCTL.DLL) so add a reference to it.

MODI.Document mDoc = new MODI.Document();
mDoc.Create("temp.jpg");
mDoc.OCR(MODI.MiLANGUAGES.miLANG_SYSDEFAULT, true, true);
MODI.Image mImage = (MODI.Image)mDoc.Images[0];MessageBox.Show(mImage.Layout.Text);

The key thing to note is that MODI.Document only accept input files from an string representing the filepath, so you have to save the scanned document to disk (in either JPEG or TIFF) rather than reading from memory.

As far as I can tell, this doesn't retain any layout data (ie, BlockA of text was situation at X,Y) so it doesn't appear to be the perfect solution for my document manager but it is free (well, so long as you've got Office) so I'll overlook that for now.


1 Comment
 

WPF DataGrid CTP Available!

13 August 2008 Tags  , ,

I picked this one up via Rob Relyea (of the WPF Team), the long awaited and much requested DataGrid for WPF is available on CodePlex. For more information (including a screenshot), Vincent Sibal has a detailed 'how to use it' post

Requires .NET 3.5 SP1 to run, and it'll eventually will make its way into the WPF core libraries (I think?). Out of band releases are nice.


2 Comments
 

Remix Melbourne 2008

25 May 2008 Tags  , , , ,

remix_logo1 With Remix over, I thought I'd sum up my thoughts on the event. Last year's Remix was my first Microsoft event, but now I have a few more under my belt. This year I hung around Stephen Price, whose Quokka cartoons were featured all over the Remix blog. Stephen's a very cool bloke, even if he gets lost too easily.

 

Keynote

While Mark Pesce's keynote speech was fantastic, I'm not sure how much relevance there was to most of Remix. The content of Remix's sessions were always going to be about about XAML (Silverlight/WPF), IE8/ASP.NET, and Expression Studio - that is technically focused, rather than the social implications. The Live Platform session (the third session) certainly did expand on "hyper-connectivity"  (social) and the technological side of things, but the rest of the Remix "conversation" was perhaps a bit too focused on the technical or product side of things. That aside, I will repeat, it was a fantastic presentation. Get yourself on Twitter now!

If you weren't at Remix, watch the video above (text version)

Session 1 - What's New in Windows Presentation Foundation 3.5 and beyond

Speaker: Joseph Cooney

I quite like WPF, but I haven't really seen the need to move to .NET 3.5….until Joseph's presentation.

.NET 3.5 cool things are:

  • New (I think?) Addins space is in a secure isolate (separate app domains), and are able to have different security levels, such as (AddInSecurtyLevel.)Internet or FullTrust.
    For security purposes, Addins do not see a "parent" GUI object - they cannot "walk up the VisualTree".
  • Under .NET 3.5 SP1, ClickOnce and XBAPs supported in Firefox
  • Now possible to "brand"/customise the setup program (generated by the VisualStudio deploy wizard)

IMG_2870

The WPF cool things are:

  • Interactive 2D on 3D is now "native", rather than a third party/unsupported library
  • WPF can make use of some DirectX stuff natively, rather than having to Interop/P/Invoke
  • Better debugging for WPF Databinding (this stuff is gold - will be making use of it for MahTweets!)
  • Formatting in DataTemplates/DataBinding (ie, <TextBlock Text="{Binding textField, StringFormat= - \{1\}}" /> will prepend " - " to the string) Nothing "wow", but so much more logical to do that on the presentation side of things, rather than needing to modify the business objects so that you can present the data correctly.
  • Recycling Virtualisation. Emphasis because this is particularly cool. In .NET 3.0, UI controls such as a ListBox would be virtualised, generating the ListBoxItems for the items that are visible at the time (+5 items above or below). When the ListBox is scrolled, and a new bunch of ListBoxItems is visible, the old ones are destroyed.
    Recycling Virtualisation in .NET 3.5 doesn't destroy the "old' ListBoxItems, but reuses them. This means memory usage while scrolling stays about the same and doesn't continuously grow the more you scroll!
  • Out of band releases for new controls, much better than having to wait for .NET vNext
  • ShaderEffects sort of replace BitmapEffects (both still exist, but no reason to use BitmapEffects now) implemented in hardware so performance is much much better, and scales properly. You can create your own ShaderEffects using HSHL/PS

Ugly things:

  • .NET 3.5 is 200MB in size, compared to 50B for 3.0, and ~20meg for v1/1.1/2.0. 3.5 does include both x64 and x86 binaries, which partially explains the size. In VS2008/.NET3.5 SP1, there will be a ".NET Client Only Framework" (compile option in VS2008 SP1) that is aiming for ~25MB download, but wont include all the .NET libraries (such as System.Web), but only the ones that are most commonly used in client applications.

Joseph's slides and demos are up on his blog already!

Session 2 - Introducing Microsoft Expression Studio 2

Speaker: Tim Aidlin

This was a fairly run-of-the-mill "I have a new application, let me show you it" presentation, covering Expression Studio 2 (except Expression Encoder 2) as well as Deep Zoom Composer. Unfortunately, for any attendees of Remix 07 or Mix On Campus, this sort of stuff (albeit for xStudio1) was pretty much what the events were all about last time, and it felt like the audience knew a bit more (about their favourite specific application) than Tim did.

While the list of new features to xMedia2 are neat (RAW image handling, batch renaming, metadata browsing, voice annotations, gallery generation), I still don't really know what its purpose is in the Expression Studio suite. If it was a free app I could probably find a use for it, but for photo/image management Live Gallery is "good enough", and I manage all my music in Media Player…maybe its great for video management?

Contrasting with statements from Lee Brimelow from last year (that "everything you can do in Design, you can do in Blend, so I don't see the point of xDesign"), Tim showed off xDesign2 and some of the reasons why you'd use it over xBlend. Yes, you can probably do everything in xBlend, just like everything you can do in Photoshop can be done in Paint. Being a developer, I think I'll still be sticking to Blend, but I could see how the more artistic parts of XAML would be easier in xDesign.

Despite the improvements to xWeb2, as a developer and somebody who has been generated CSS/(X)HTML for years, I will not get any value out of xWeb2. VS2008 does all the stuff I need to do, or Notepad++ steps in when I need to go kung fu on my CSS. PHP IntelliSense/support has made it in, but this should have been a feature in xWeb2.

Session 3 - Windows Live Platform: Take the best of Windows Live and make it yours

Speakers: Angus Logan, Bronwen Zande, John O'Brien

I didn't really know what to expect from this session, the Live Platform session sounded like it would be pretty boring, but I wasn't overly interested in the other session which was upstairs, so the Live Platform session it was! I was pleasantly surprised, as this was a very cool session, possibly my favourite for the day! My laziness paid off!

The key things were how you can use Microsoft's Live Platform to create incredibly interactive websites by making use of the Live services such as Virtual Earth, Live Messenger (/Hotmail) contacts/presence, Spaces, Storage (FolderShare/SkyDrive), Notifications (via email, SMS for North America, or via WLM through the alerts service).

For a few projects I have in mind, the Live ID login system looks appealing, although I'm wondering if a service like OpenID is more 'acceptable' (by end users, since Microsoft is so evil and all, apparently). I'd be very interested in the Live Platform Team's view on OpenID vs LiveID, or if they can coexist.

IMG_2937

Angus left Twhirl running while giving his presentation, so I managed to get a few tweets popping up on the screen!

Session 4 - Building an Immersive, Integrated Media Experience in Silverlight

This session showed off the new ABC Silverlight Store, which while cool, is all Silverlight v1 stuff. It just seemed to lack the "wow", going over very similar things that were covered at Remix 07, without the edge the original presentations on Silverlight v1 had because it wasn't new. I walked out (I needed a break/fresh air, not because I was bored) before it finished, so the last 15 minutes may have been awesome, its hard to tell.

The Silverlight Store also had a matching desktop client…written in Silverlight? I think (as a demonstration of the power of Silverlight and WPF), it would have been mucho cooler to do that in WPF. The technical reasons for not doing so are more than understandable - WPF weighs in at 20meg, and Silverlight at about 4meg. Both clients being Silverlight means just one framework download/install, which is much more friendly for the target audience.

The presentation was done using DeepZoom, zooming into each slide or diagram to show more detail, such as exploding a file overview into the actual code behind that file. That bit was cool.

Session 5 - Skipped

I skipped session five, not because of the content available, but because I ran into Long Zheng, and we got to chatting. Long has a new Zune ("Long Zhune"). He's a cool guy, with or without the Zune!

Session 6 - Using Microsoft Silverlight for Creating Rich Mobile User Experiences

Speakers: Shane Morris, Michael Kordahi and David Lemphers. Originally meant to be presented by Leslie Nassar

I've been looking at creating a mobile version of MahTweets, using .NET CF. The three problems I have with .NET CF are limited controls available, it's all WinForms crap, and only available on Windows Mobile phones. Silverlight, however, will be on Windows Mobile phones and Nokia's S60 and S40 OS' phones, uses XAML solving both WinForms problem, and amount of controls available!

A good list of S60 phones can be found at the Nokia Gaming Blog - I think the cool thing is that it includes the popular E65, and all (I think) of the powerful N series phones! It is foreseeable that other phones (or browsers) will eventually be able to play Silverlight as well!

Shane talked about how Mobile is already big, but is already accelerating faster than PC/laptop markets, and the ways designs will have to change not just for the limited capability or screen real estate, but the way the mobile user "snacks" on content.

IMG_2961

Michael demo'd Silverlight on a HTC WinMo phone, but unfortunately its "pre-pre-pre-beta", so we aren't able to play with anything yet. Apparently some of the other Remix events around the world pulled the Silverlight mobile content! The goal of the Silverlight mobile project is to use the exact same Silverlight tools, and allow all existing Silverlight stuff to just work - you wont have to compile to "Silverlight Mobile", ala .NET and .NET CF.

Imagine Cup

During Session 5, I had Long talk me through what his teams project was all about. It is very cool, but rather than fumbling around to describe what it is, he's already blogged about the team SOAK entry.

IMG_2990

Congratulations again to Long, David Burela, Edward Hooper, and Dimaz Pramudya! Good luck in France guys.

Overall

It was fantastic to see that some of the feedback from last year made the event change this year, such as including free wifi and 'recharge' stations. Unfortunately, the wifi/net connection weren't too stable up until ~3pm, and other suggestions such as including pens for the feedback forms didn't make it through, so Stephen and I pinched one of the vendor's pens.

I can't remember if I wrote down "better food", but this year had a lot less salmon and cold wedges! There were even TimTams! ('cause, you know, this it totally the most important part of the day).

This year the event was split across Melbourne and Sydney, and cut down to one day (each). This year's venue (Melbourne Town Hall) was both better and worse than last year. More room to move between sessions and chairs to sit on, but higher ceilings (which created echo's and "lost the vibe"), consistently bad lighting and uncomfortable chairs during the sessions all worked against the Town Hall. A few others agreed on the venue being 'so-so', and Ed Hooper suggested that the Melbourne Convention Centre, which is where Heroes Happened was held, would have been a better choice - which I agree with.

Remix is still in an infant state, its still learning about itself, but it is developing, experimenting and evolving. While not everything was perfect, I still will be attending next year because despite all my complaints it was still a great (albeit exhausting) day. Next year, however I think I'll just take my camera and a notepad, rather than laptop + camera, which is fairly weighty. I'll also sit a bit closer so that some more of my photos turn out. Argh!

Just like last year, Nick Hodge has a summary post of activity on the blogosphere about Remix.


2 Comments
 

Expression Encoder 2(/API) Audio Limitations

7 May 2008 Tags  ,

ExpressionEncoder2_webWhen it was announced that Expression Studio 2 had gone RTM , I noticed on Frank Arrigo's blog, that the Expression Encoder (xEncoder from hereon in) had an API! (Side note, if you follow the Franks blog to the Expression Encoder Object Model post by the xEncoder team, please be aware that the API has changed since Beta 2, so if you're using RTM and it fails to compile, you just need to change a few names around)

I was initial excited, because I've been rather disenchanted with Handbrake which I've been trying to use since Jeff Atwood went on about it, and how he uses it to archive his DVD collection. While Expression Encoder won't allow you to directly encode a DVD, but working a bit of magic I've managed to create a system to encode DVD's to WMV's (VC1), but I'll save that for another time.

There are a few rather serious problems with using xEncoder or its API. For a start, you can't really really join an audio and video stream together. While this may seem harmless enough, when you combine it with the other faults, it grows in annoyance. The main problem I've noticed so far is that xEncoder can not do anything but stereo audio.

"First shalt thou take out the Holy Pin, then shalt thou count to three, no more, no less. Three shall be the number thou shalt count, and the number of the counting shall be three. Four shalt thou not count, neither count thou two, excepting that thou then proceed to three. Five is right out"

Holy Hand Grenade of Antioch

In the main Encoder GUI, there is a drop down box for Audio Channels, which only exposes Stereo; if you are using the API, you can set your MediaItems to have an AudioProfile. That AudioProfile has a Channels property (Int), but if it is set to anything above or below 2, my test program would simply crash!

Hopefully xEncoder v2.5 or v3 adds multichannel support, otherwise the API for xEncoder is really of no benefit over the older Windows Media Encoder (WME), which multichannel! The xEncoder API requires xEncoder to be installed which unlike WME, is not free, cannot join audio and video together, and cant handle multichannel audio. (edit, fixed, thanks Will)


No Comments
 

TweetSaver: WCF + WPF + fun

20 April 2008 Tags  , , ,

TweetSaver has slowly been creeping into the CodePlex project for MahTweets over the last week or so, and now the first alpha release of it is live!

tweetsaver

What is TweetSaver?

  • Twitter + Screensaver
  • Uses WCF to connect to MahTweets - you can have it on multiple machines with no extra API usage!
  • Uses WPF for display
  • Name is by Will, so blame him

It uses MahTweets (requires MahTweets "Alpha 3" and up - Alpha 3 is designated by Change Sets 4309 or higher) and WCF for communication (TCP endpoint). Just like MahTweets, TweetSaver will get tweets in real time as MahTweets pushes out the tweets via WCF, which means no more Twitter API calls are made!

The really cool part of this would be if you had one MahTweets 'server' (for lack of a better word), and TweetSaver on an entire office of computers. One connection/set of API calls could do an entire office (of…your twitter feed). If you went to any of the Australian Heroes Happens Here events, you'd have noticed they had lots of twitter screens setup, all logged into the Twitter webpage - this would get around having each one logged in, and look prettier ;)

Requirements

  • .NET 3.0
  • Twitter account
  • Jabber (G-Talk will do) account preconfigured for IM with Twitter
  • For TweetSaver to run correctly, MahTweets must be open

Installation

  • Download
  • Extract
  • Run MahTweets, click allow to the Windows Firewall request (if you want TweetSaver to work) and configure MahTweets
  • Right click on TweetSav.scr, and select 'Install' - no configuration is needed unless you want to try it out over a network

Disclaimer

You're downloading this of your own free will, so we take no responsibility if your computer crashes, hard drive self formats, you develop a drinking problem, and so on and so forth. While it is an "alpha" release, at worst, it should either crash itself or hog resources - nothing "deadly".

Download the release-build of changeset 4309


No Comments
 

CodeSnippet: Using SQL Compact Edition

14 April 2008 Tags  , ,

Many multi-user applications require a database, be it a web app (probably more often a web app!) or win forms. In single user applications, often it is beneficial if there is a database (in speed, complexity and robustness), but the problem is distributing the database server. I've had a few applications that come bundled with MySQL, and it just plain ole sucks.

Some of the reasons for using a database in your application include

  • Faster than flat file storage such as XML
  • Can have complex relationships
  • Can have varying datatypes that don't break an XML parser
  • Can then later redeploy in another project, such as a website using SQL Server easier

One of the easier ways to distribute your winform/WPF application with a database is with Microsoft's SQL Compact Edition (SQLCE). It has a fairly low footprint, is very fast, and is reasonably powerful despite the reduced operations (which allows it to be fast/low footprint/etc). Visual Studio's deployment tools even allow you to check for the SQL CE prerequisite on the target machine before installing, and will download SQL CE if it isn't found!

Adding SQL CE to your project

Providing SQL CE was installed during your Visual Studio install (default install settings), to get a SQL CE database in to your project, all you need to do is add a New Item > Local Database to your project. This will automagically add the references your project will need to access SQL CE databases (although you'll still need Using System.Data.SqlServerCE;)

image

image

Double clicking on your new database in the Project Explorer will activate the Server Explorer, allowing you to add Tables to the database.

image

Using SQL CE

The way you access data is nearly identical to a normal SQL Server, except it all lives in the System.Data.SqlServerCE namespace, and usually has SqlCeClass rather than SqlClass. ie:

SqlCeConnection sqlCon = new SqlCeConnection(TestApp.Properties.Settings.Default.TestConnectionString);
SqlCeCommand sqlCom = new SqlCeCommand();
sqlCom.Connection = sqlCon;
sqlCom.CommandText = "SELECT * FROM TestTable";

SqlCeDataAdapter sqlDa = new SqlCeDataAdapter(sqlCom);
DataSet ds = new DataSet();
sqlCon.Open();
sqlDa.Fill(ds);
sqlCon.Close();

Using LINQ with SQL CE

In .NET 3.5, you can also use LINQ against SQL CE. Currently (VS2008) you have to use the SQLMetal tool from the Visual Studio CLI, then add the generated dbml file to your project (Add -> Existing Item)

SqlMetal SqlCeFileName.sdf /dbml:LinqClassName.dbml

In the new version of MahTweetsMediaHorn (correction, thanks Will), I'll be using my own database rather than relying on Windows Media Players database. The LINQ to select all the albums (after generated the dbml via SqlMetal) is..

Music db = new Music(MediaHorn.Properties.Settings.Default.MusicConnectionString);
var album = from a in db.Album select a;
listBox2.ItemsSource = album;

Any and all of the usual tricks for LINQ apply to SQLCE - once you generate the dbml via SQLMetal, it really doesn't care what is underneath. If you want to bind it properly to WPF with automagic updates for when the datasource updates, I strongly recommend looking into the very clever SyncLINQ by the equally clever Paul Stovell, which also supports Silverlight.

Deploying apps with SQL CE

As I mentioned, the Visual Studio "Publish" tool makes sure the target system has all the prerequisites before installing. SQL CE is automatically added to the list, but if you need to modify it, right click on your project, Properties, then down to the Publish tab, and the Prerequisites option will launch a new dialog.

image

Just make sure you distribute your application via Build -> Publish :)


No Comments
 

CodeSnippet: Multithreading your app

1 April 2008 Tags  , , ,

Ever noticed how some applications tend to hang when you perform an operation? For example in MahTweets (my Twitter client), it used to have a looong pause every time it updated the Tweet list, and often the application would go black, almost to the 'not responding' stage. The GUI and application logic shared the same thread, meaning a massive change in GUI or lots of processing in the logic would stop the other.

The way around this is to use a separate thread for anything that requires a lot of processing, or that is bottled by another factor (Disk IO, or network speed, etc).

public delegate void MyDelegate();

// This method could be the method behind a button.clickpublic void InvokingMethod()
{
    Thread myThread = new Thread(new ThreadStart(new MyDelegate(MyMethod)));
    myThread.Start();
}
public void MyMethod()
{
    //Code to execute on new thread goes here
}

There is one caveat, your new thread cannot access the GUI because this could cause some serious synchronisation issues. The way around this (in WPF at least!) is to use the Dispatcher.Invoke method.

public void GuiMethod()
{
    if (!Dispatcher.CheckAccess())
    {
        Dispatcher.Invoke(DispatcherPriority.Normal, new voidDelegate(GuiMethod));
        return;
    }

    //Code that accesses the GUI
}

If you need to pass parameters, one (quick) way is with an anonymous delegate like below, I'll let you figure out the different ways to go about it though.

Thread t = new Thread(delegate() { MyMethod(MyParam); });

If you are having problems with concurrency and synchronisation, that's outside the scope of this post…start looking at wikipedia's article on threading, and go from there.


No Comments
 

Exploiting Live Gallery to upload to custom gallery

19 March 2008 Tags  , ,

My photo management tool of choice is Live Gallery (WLG): it's fast, free, and fairly featuresome.

One feature that is lacking however, is to upload to your own 'custom' gallery. Oh, sure, you can upload to Flickr, or Live Spaces, but honestly, who uses either of those services, pfft! Unfortunately, there doesn't seem to be a plugin API (yet?) for Live Gallery so it isn't possible to add your own image gallery service to upload - well, not as neatly as Flickr/Live Spaces.

Step 1: Add Your Gallery

To add your own custom gallery uploading to Live Gallery, we need to exploit the Online Printing functionality. Each printing service is actually defined in the registry, and the default "Print@Kodak" is a great starting point to seeing what data we need.

It is located at:

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\PublishingWizard\InternetPho
toPrinting\DownloadedProviders\Print@Kodak

The registry values look like:

"displayname"="Print@Kodak"
"description"="Get Kodak photo quality prints from your digital camera!"
"href"="http://print.fotowire.com/webprint/xp/start.asp?WID=25900"
"icon"="fwPrint.ico"

To add your own, it is as simple as creating your own key inside of DownloadedProviders, however either Windows or WLG seems to delete the registry key after closing WLG. Instead of inside DownloadedProviders, create a Providers key (inside InternetPhotoPrinting), and then create your own Provider key, with the same sorts of values (displayname, href, description and icon) as the Kodak Provider.

It should look something like this image when you're done

image

There is another benefit to doing it this way, under the printing menu, you will now have 'Print', 'Order prints', and 'Order prints from foo'

image

Step 2: Prepare your gallery

While it is great we've thrown it a random URL, how do we know what data is actually being sent?

Thankfully Elmar Putz had figured out the XP Web Publishing Wizard (which is very, very similar), so that was most of the leg work done.

First, the page set in the Href in Registry. I'm going to cut to the chase and just list the HTML/Javascript, if you want more of an explanation, see Elmar's article (linked above). All you need to do is change the UploadURL and EndUrl

<html>
    <
head>
        <
script language="JavaScript">
            var
UploadURL = "http://mydomain/upload/";
            var EndURL = "http://mydomain/aftertheupload.html";
            function window.onload()
            {
                window.external.SetWizardButtons(0,1,0);   
            }

            function window.onback()
            {
                window.external.FinalBack();
            }
           
            function window.onnext()
            {
                var xml = window.external.Property("TransferManifest");
                var files = xml.selectNodes("transfermanifest/filelist/file");

                for (i = 0; i < files.length; i++)
                {           
                    var postTag = xml.createNode(1, "post", "");
                    postTag.setAttribute("href", UploadURL);
                    postTag.setAttribute("name", "myfile");

                    var dataTag = xml.createNode(1, "formdata", "");
                    dataTag.setAttribute("name", "MAX_FILE_SIZE");
                    dataTag.text = "2000000";
                    postTag.appendChild(dataTag);

                    var dataTag = xml.createNode(1, "formdata", "");
                    dataTag.setAttribute("name", "action");
                    dataTag.text = "Save";
                    postTag.appendChild(dataTag);

                    files.item(i).appendChild(postTag);
                }

                var uploadTag = xml.createNode(1, "uploadinfo", "");
                var htmluiTag = xml.createNode(1, "htmlui", "");
                htmluiTag.text = EndURL;
                uploadTag.appendChild(htmluiTag);

                xml.documentElement.appendChild(uploadTag);
               
                window.external.FinalNext();
            }
           
            function document.oncontextmenu()
            {
                return false;
            }
        </script>
    </
head>
<
body>
    <
h2>Click Next to upload</h2>
</
body>
</
html>

image

The code for the page at UploadURL would look something like…

ASP.NET

String uploadDir = "Images/";
HttpFileCollection hpC = System.Web.HttpContext.Current.Request.Files;
for (int i = 0; i < hpC.Count; i++)
{
    HttpPostedFile file = hpC[i];
    if (file.FileName != string.Empty)
    {
        file.SaveAs(Server.MapPath(uploadDir + file.FileName));
    }
}

PHP

<?php foreach ($_FILES["pictures"]["error"] as $key => $error) { if ($error == UPLOAD_ERR_OK) { $tmp_name = $_FILES["pictures"]["tmp_name"][$key]; $name = $_FILES["pictures"]["name"][$key]; move_uploaded_file($tmp_name, "uploadDirectory/$name"); } } ?>

Step 3: Reading the file (optional)

If you're writing your own gallery, or simply just want a way to avoid having to FTP in to upload files, it may look as if you've lost the meta-data (specifically I mean tags)  from your photos. Fear not, however, as there is a way!

All the tags are stored in 'XMP' format, which is essentially just embedded XML.

.NET 2.0
In .NET 2.0, there is no native way to read in XMP Information, so we need to use some XML parsing to get it. Microsoft blogger Omir Shahine, has a great post on accessing XMP data in .NET 2, including the code/general discussion on the matter.

.NET 3.x+
In .NET 3 and above, inside the Windows Imaging Component, there is the BitmapMetaClass. However this is both more and less complex than using regular expressions (above), in that you nave to use the proper 'paths' for accessing specific data. I won't cover it here, but WIC/BitmapMetaClass is what you should look into if you want the .NET 3+ method of accessing XMP/EXIF data.

PHP
Like .NET 2, there is no native way to read in XMP information. The below code will return an array of XMP Tags.

<?php function GetTags($filename) { $handle = fopen($filename, "r"); $image = fread($handle, filesize($filename)); fclose($handle); preg_match("/LastKeywordXMP>([\w\W\t\f\s]*)LastKeywordXMP>/i", $image, $matches); $tags =split("</rdf:li>",$matches[1]); for ($i=0;$i<count($tags);$i++) { $tags[$i] = trim(strip_tags($tags[$i])); } return $tags; }?>

Final Notes

Since there isn't an authentication option in the printing wizard, security is a concern, particularly in a multiuser environment. You could implement any/all of the following however

  • Since it is just HTML, there is absolutely no reason that you couldn't add in a HTML form for entering the username and password as the "first stage". The second page would be returned from the server, with the (javascript) settings to allow uploading. It is a hosted IE session, so it should store/access cookies - if they've logged in via IE, they should remain logged in!
  • create a 'secure private' hash and append that to the url, ie http://mygallery/upload.php?hash=DADGGSDGFS123
    This would mean user would have a separate (auto-generated I'd assume…) REG file to import
  • IP based filtering (okay idea, sucks if your IP changes, or if you're on a public network)

 



1 Comment
 

Silverlight 2.0 Beta 1 rocks

9 March 2008 Tags  , ,

silverlight_logo.jpgI've tried to get excited about Silverlight, particularly when I found Silverlight stickers laying around at Mix on Campus and took one for my laptop.

Silverlight 1.0 sucked (this is in my opinion) because it was Javascript - ew ew ew. It was essentially an interesting graphic engine with some pretty good video (/streaming) tech. The killer here was Javascript - if I'm going to use a Microsoft technology, I damn well want to use C#, or another .NET language I'm already using.

Silverlight 1.1 was better in that it used .NET, but it sucked because if you wanted to do anything, you had to build all the controls (such as buttons, or listboxes, etc) yourself. NOT FUN AT ALL. While yes, Silverlight 1.1 was renamed 2.0, I'm referring to the 1.1 Alpha September Refresh.

Silverlight 2.0 Beta 1, now ships with most of the standard "WPF" controls (or controls very close to them anyway), meaning it requires very little effort to go from a WPF application to Silverlight 2 application - that's cool (and check them out on the samples page). And it can communicate with SOAP(Limited? v1.1 BP I believe)/XML services rather well, I've got a WSDL thing going on - that's cool. Oh, LINQ too? Local storage? What about Deep Zoom from Photosynth (when can we get that for WPF?!) which is capable of handling (from various sources) Petabytes (1024 Terrabytes) of data?  Oh yeah, Silverlight 2 is really starting to live up to the codename "WPF/E"!

I was toying with a WPF application yesterday, that I wanted to have online, and sure enough, I could copy the majority of the codebehind and UI, so very cool!

Silverlight 2 is much more exciting, a nice example of a few of the new technologies included in it can be found at the Hard Rock Memorabilia app.


No Comments
 

Expression Studio 2 Beta + Silverlight 2 Beta 1

6 March 2008 Tags  , , ,

I'm not sure if xBlend 2.5 was announced recently, but I happened to see it in one of the slides from the Mix08 keynote, thanks to Long.

Expression Blend 2.5 March Preview supports Silverlight 2 Beta 1, and SL2B1 has a lot more WPF UI Elements in it. For me, this is really exciting, because I really didn't want to be creating buttons, list boxes, etc. If I'm going to create a control, it isn't going to be a 'fundamental' control. Before now, Silverlight 1.1/2 to me was awesome, but pointlessly tedious to develop.

Apart from that exciting news, Expression Studio 2 Beta has been released! The biggest thing that stands out for me is xWeb2 now has  PHP Support! That's a huge step in the right direction, and seemed to be one of the biggest complaints at Remix last year.


2 Comments