onsdag den 29. august 2012

Slow onClick on iPhone and iPad


I was building a javascript-powered zip-code registration web page, with a numeric display which would be used to enter the zip-codes of guests at a company grand social function, to later determine where they came from. The screenshot below is what I came up with:


Your basic numeric display with digits, a 'clear' button and a 'undo latest' button. Upon entering a 4-digit zip, the 'display' automatically clears, ready for a new one.

But the app was to run exclusively as a web-app within an iPad, and what I found was that the onClick handlers I'd attributed to the buttons, which are actually DIVs, were slow to trigger, on both my version 1 and version 2 iPad. A bit of googling suggested I went with the touchstart event instead; which worked beautifully, the javascript associated with the events executed quickly and beautifully.

So to recap, in the $(document).ready(function () -section I did this:


$('.digit').bind("touchstart", function () {

var clickedValue = this.getAttribute("value");
// do something with the button's digit value here
}

... where '.digit' corresponds with the class I give my DIVs:

9

Give me a shout if you want the code, it's a Visual Studio 2010 c# web application. HTH someone in a similar bind.

onsdag den 15. august 2012

Prevent zooming on iPhone and iPad web apps

Had to google more than I thought I'd have to in regards to this one, so here's a blog entry to hopefully help others out. To disallow the user to zoom in and out on a web page as displayed on an iPad or iPhone, add this tag to the meta-tags section of the page header: This will prevent the user from zooming in or out on the screen. I saw a range of other attempts to prevent this, using javascript and such, but the above is your best option.

tirsdag den 10. juli 2012

Editing PDF form on the web

I was asked to make a PDF form editable on the web. The HR department already had the form, now they wanted me to make it editable via an url.

The solution involves

- setting up a database to hold the PDF form data,
- making the PDF form submittable to a web page,
- utilizing the iTextSharp-library to parse the submitted PDF form

Setting up the database involves creating a table with columns for every field in the PDF-form you need stored - likely all of them. Also there must be a primary key in the form of an auto-incremented value or a global unique identifier. Having set up the database, allow the PDF form to be submittable to a web page. In Adobe Acrobat Pro, go to the "Forms -> Add or Edit Fields" and add a PDF button with the text "save" on it. Define a button action for the mouse-up event; specifically, a "submit form" action (*). The properties for the action should look akin to this:

















*) I'm using a Danish version of Acrobat Pro, so the menus and texts may slightly different from the above.

I.e. the form submits into a generic handler "pdfHandler.ashx" when it is clicked (the mouse-down action). The handler's default "ProcessRequest" function looks like this:


---

 public void ProcessRequest(HttpContext context)
        {

            HttpRequest pdfRequest = HttpContext.Current.Request;
            System.IO.Stream istream = HttpContext.Current.Request.InputStream;
            FdfReader fdf = new FdfReader(istream);

            // eksisterende?
            if (!string.IsNullOrEmpty(fdf.GetFieldValue("ident")))
            {
                DataClassesDataContext dbContext = new DataClassesDataContext();

                int id = Convert.ToInt32(fdf.GetFieldValue("ident"));
             
                lejere lejer = dbContext.lejeres.Single(foo => foo.id.Equals(id));
                lejer.ad1 = fdf.GetFieldValue("ad1") == null ? string.Empty : fdf.GetFieldValue("ad1").ToString();
                // populate all database object properties
         
                dbContext.SubmitChanges();
            }
            else
            {
                #region new lejer

                try
                {
                    DataClassesDataContext dbContext = new DataClassesDataContext();
                    lejere lejer = new lejere()
                    {
                        ad1 = fdf.GetFieldValue("ad1") == null ? string.Empty : fdf.GetFieldValue("ad1").ToString(),
                        ad2 = fdf.GetFieldValue("ad2") == null ? string.Empty : fdf.GetFieldValue("ad2").ToString(),
                        // populate all database object properties
                    };

                    if (string.IsNullOrEmpty(fdf.GetFieldValue("lejernavn1")) && string.IsNullOrEmpty(fdf.GetFieldValue("lejernavn2")))
                    {
                        lejer.lejernavn1 = "Uudfyldt";
                        lejer.lejernavn2 = "Uudfyldt";
                    }
                    dbContext.lejeres.InsertOnSubmit(lejer);
                    dbContext.SubmitChanges();
                }
                catch (Exception ex)
                {
                    throw ex;
                }

                #endregion
            }

            HttpContext.Current.Response.Redirect("Default.aspx", true);
        }
---


Basically what takes place here, is that an iTextSharp pdf-reader is instantiated from a HTTPRequest which is the submitted PDF document. Using LINQ to SQL, a database object corresponding to the PDF form (recall we just created the database and its table with columns for all the PDF form fields) is populated from the PDF form (the 'GetFieldValue' function of the iTextSharp library) and stored to the database via LINQ to SQL. 


The "New" option is relatively straight forward, in as much as the LINQ to SQL functionality itself works out to insert a new auto incremented integer primary key, if you're - as am I in this case - going with auto-integers for database keys. The "Edit" option is more of a challenge - here we'll have to inject the primary key into the PDF form, before allowing the generic handler to take over and grap this value when the form is submitted. The way to do this is so:


In the edit-button click function, do this:


---

 int lejerId = Convert.ToInt32(LejereDropDown.SelectedValue);
                DAL.lejere lejer = dbContext.lejeres.Single(foo => foo.id.Equals(lejerId));

                PdfReader reader = null;
                AcroFields af = null;

                PdfStamper ps = GetPDFFields(ref reader, ref af);

                SetFormData(ref af, lejer);

                // forget to close() PdfStamper, you end up with
                // a corrupted file!
                ps.Close();
             
                if (reader != null)
                {
                    Response.AddHeader("Content-Disposition", "inline;filename=lejekontrakt.pdf");
                    Response.ContentType = "application/pdf";
                }


What happens here is that we instantiate an iTextSharp PDF-reader and use the "GETPDFField"-method to achieve a reference to all the form fields in this PDF. THe "SetFormData" function simply fills in these form fields (like so;  "af.SetField("ident", lejer.id.ToString());") - including a hidden "ident" field on the form. Once the form fields have been populated, we'll redirect into the form by changing the page headers and response contenttype, as written.

Hope the above helps! All the references to 'fields', 'forms' and such can get confusing, so be sure to get in touch with me if anything needs explaining further.

tirsdag den 3. juli 2012

Unsafe code in App_Code folder

I ran into an issue where my Visual Studio 2010 Professional reported "CS0227: Unsafe code may only appear if compiling with /unsafe".

But I had already checked the appropriate checkbox in the solution properties dialog!

Turns out the problem was having the unsafe code reside in the App_Code folder. Moving it to a different location solved the problem.

mandag den 4. juni 2012

Live c# video streaming webcam server and client

I wanted to capture live video from a webcam and stream it directly to a client application. This was thought to be for a robot which would stream video from its webcam eyes and allow me to see what the robot sees, but really it would be possible to build a cheap DIY home surveillance network around this.

The VS 2010 c# solution holds two projects, one commandline project for the server and one windows forms project for the client.

The server stream not video, but rather a series of captures images, but in presenting these images in a rapid fashion the end result will seem like a naturally flowing video stream. The images  made available to a connecting client IP by an initialized WCF service, namely via a tcp/ip binding. The images capture is done by utilizing the AForge framework to access an available webcam. The images are saved to disk and not to memory, as I wanted to retain the option of going through them again at a later point. The last captured image is always kept in memory, to be delivered to the calling client as the WCF's 'getWebCamImage()' method is invoked.

I set the web cam framerate to 15 frames per second, which is fine enough to moving images. The maximum number of images the human eye can distinguish is 30 per second, so I'm told, so 15 images per second makes for a comfortably video experience.

The client creates an instance of the WCF service. A timer is set to call the service and return an image-stream, which is placed into a standard winforms picturebox. In the example code the timer is set at 100 milliseconds, which will yield only 10 images per second - thus not the 15 frames which are actually captured, I did this to perserve bandwidth but in reality it should be perfectly possible to call the timer 15 times per second. The viewing experience is nice enough just the same.

Check out the source code below if you're in need of something like this. Please bear with all the references to 'robot this' and 'robot that', the functionality was meant for a robot control project. The WCF service runs localhost, but you would of course in due time seperate the client from the server and allow the service to run via an external IP, firewall-configured to the port of your choice and not my standard port no 8733.

Link to solution source code

Let me know if there's anything I can do to help you in implementing the project, if it gives you any trouble.

Hope this helps you!

Buy me a coffeeBuy me a coffee

torsdag den 10. maj 2012

Recommending a free subversion service

If you're in need of a free SVN service to hold your code, I can recommend trying Assembla. I've been with them for a few months and so far it's been very smooth sailing. Their free plan for non-commercial code hosting and versioning is great for my needs. Couple with the - also free - Ankh Visual Studio SVN plugin, and you'll never loose code or sleep again.

And I'm not affiliated with them in any way, suffice to say.

tirsdag den 1. maj 2012

could not create type webservice

A little reminder, if you encounter the "could not create type 'whatever'" when trying to access an asmx web service you created, this could be caused by the virtual directory not being marked as an IIS web application - like this:



In IIS 7, right-click the virtual directory and select "Convert to application".