html2canvas- Take Screenshot of Web Page and Save It to Server (Javascript and PHP)

FeedBack is important. Usually, end-users struggle to clarify their problems. And you might be unreachable for a phone call or remote connection.

That causes a huge need of visualization. First solution that appears in mind is to capture the current screen of user.

However, when I tried to implement that, it wasn’t so easy as I expected. Some old ways offer ActiveX but it seems too outdated. Since there’s a bridge needed between client side and server, JS libraries are the best way.

There’s a great library, html2canvas. It is told to be reverse-engineered version of Google Plus’ way of taking screenshots.

When I first discovered this library, it took me a while to use for simplest implementation. I just wanted to visualize a div element. However, there was no single page to tell the whole path to follow, thus I had to combine various sources.

Here’s how you can easily use for taking a screenshot of a div:

1- Import libraries
There are 3 libraries to import:

  • jquery.js
  • html2canvas.js
  • jquery.plugin.html2canvas.js

You can download html2canvas and html2canvas jQuery plugin from this link.
Note: The source link contains html2canvas v0.40. I recommend you to check for a newer version and use it instead from official html2canvas site.

I have used jquery.min.js v1.7.1 but you can try other versions. For this jQuery library, use this link.
Here’s first lines of code:

<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" src="js/html2canvas.js"></script>
<script type="text/javascript" src="js/jquery.plugin.html2canvas.js"></script>
<!-- -->

2- Create your div
In my code, I used html2canvas for a div. You can use the whole body tag instead, it’s up to you.
Attach a div element to the page with a certain id:

<div id="target">
<!-- Render your page inside of this div. -->
</div>

3- Create a button and a hidden form
This part is important. In order to save the image to server, we need to pass captured image data with a form field.
In 4th step, you’ll see JavaScript code that writes the image data to hidden field and posts the form.

<input type="submit" value="Take Screenshot Of Div" onclick="capture();" />
<form method="POST" enctype="multipart/form-data" action="save.php" id="myForm">
    <input type="hidden" name="img_val" id="img_val" value="" />
</form>

4- JavaScript Code

    function capture() {
        $('#target').html2canvas({
            onrendered: function (canvas) {
                //Set hidden field's value to image data (base-64 string)
                $('#img_val').val(canvas.toDataURL("image/png"));
                //Submit the form manually
                document.getElementById("myForm").submit();
            }
        });
    }

5- Use the posted values
Here I used a form to post the value. You can use Ajax calls or whatever. I have a PHP file, save.php. In this file, we will both show the picture and save it to the server.

//save.php code

//Show the image
echo '<img src="'.$_POST['img_val'].'" />';

//Get the base-64 string from data
$filteredData=substr($_POST['img_val'], strpos($_POST['img_val'], ",")+1);

//Decode the string
$unencodedData=base64_decode($filteredData);

//Save the image
file_put_contents('img.png', $unencodedData);

6- Enjoy your day
So that’s pretty much it. Click here for a live demo or download the codes from Github repository page.

7- Notes

* This tutorial uses html2canvas v0.4.0 – 30.1.2013. It has a new release, v0.4.1 – 7.9.2013, can be downloaded from here. Though avaliability of newer versions haven’t been tested with the code above.

* Some people have declared that they had issues with checkbox/radiobutton states on the captured image. Stu has shared his code to capture these elements with their states. I haven’t tried by myself but people who face problem about this may get some opinion from his comment.

166 Comments

Asp.Net Server Side: How to get Iframe’s Parent Window Url?

In Asp.Net server sided button’s click event, I somehow needed to find parent window url of an iframe, which means the url you see in the address bar of your web browser.

Let’s think of 2 pages: Parent.aspx and Child.aspx. Child.aspx is loading to an iframe in Parent.aspx. If you have a button in Child.aspx, you will be getting “Child.aspx” result when you use Request.Url method in this button’s click event.

But you see “Parent.aspx” in the address bar, right? So how to get it?

Here you need to work with client side peacefully. Otherwise the server will keep giving you the same result.

First, place a button running at server, add a click event and a client-click event.

    <asp:Button ID="btnFindParentUrl" runat="server" Text="Get Url!" OnClick="btnFindParentUrl_Click" OnClientClick="fillHidden();"></asp:Button>

Put a hidden textbox inside a div with style=”display: none;” (not Visible=”false” for button because if you do client can’t see and fill it):

    <div style="display: none;">
        <asp:TextBox ID="txtHiddenUrlField" runat="server" BorderStyle="None" Font-Size="0px" ForeColor="#F6F6F6" Height="0px" Width="0px"></asp:TextBox>
    </div>

Now place javascript code of fillHidden() function:

    <script type="text/javascript">
        function fillHidden() {
            document.getElementById('<%= txtHiddenUrlField.ClientID %>').value = parent.document.location.href;
        };
    </script>

That’s all you have to do at client side.
Let’s go to the server:

    protected void btnFindParentUrl_Click(object sender, EventArgs e)
    {
        string parentUrl = txtHiddenUrlField.Text;
    }

This way, you should be getting parent url from button in an iframe.

4 Comments

T-SQL: How to Order by Surname in Full Name Column?

Sometimes you need to do ordering by in a full name column. If you want to order by first name, that’s cool, but when you need to order by last name, you need to find the surname for each field.

Let’s take a look at this data:

[Full Name]
—————————-
Albert Einstein
Leonardo da Vinci
Nicolas Tesla

 
These values are ordered by first name so there’s no problem with that. But if we wanted to order by last name(which is not a particular column in this table), we had to find a way like splitting these fields or something else.

Anyway, there was a good line of code in StackOverflow (see question&answer here) written by user Recep.

SELECT [Full Name], REVERSE(SUBSTRING(REVERSE([Full Name]), 0, CHARINDEX(' ', REVERSE([Full Name])))) AS SurnameAfterReversing
FROM GENIUS_TABLE
ORDER BY REVERSE(SUBSTRING(REVERSE([Full Name]), 0, CHARINDEX(' ', REVERSE([Full Name]))))
--We need to select our ORDER BY expression as a new column otherwise it will warn that it can't order by a column which is not exist in query result.

It reverses the whole name here, then gets text until the first space (‘ ‘) character, then reverses the new text back. That way, we actually get the last name so you can do anything you want with this column.

And here is the data as a result of this query:

[Full Name] SurnameAfterReversing
—————————- —————————-
Albert Einstein Einstein
Nicolas Tesla Tesla
Leonardo da Vinci Vinci
1 Comment

iOS 6 is Still Beta

iOS 6

The ones who involved with iOS or iOS development might have heard about the beta version of iOS 6. It’s only open for registered Apple developers at the moment but I assure you it’s better this way. People expecting Apple to release latest and common version in fall 2012.

If you want to take a look at new features, here’s 2 links:
One is in English: #iLounge.com Link [Eng],
Another is in Turkish:  #iPhoneTurkey Link [Tr]

Since I am registered as a developer, I had a chance to try iOS 6 beta in my iPhone 4S.

Before I start, I also downloaded the new beta version of Xcode 4.5 and I tried to upgrade through it. But I had the “The iPhone “xxx” could not be updated. This device isn’t eligible for the requested build.” error. I did what adviced on some websites but it didn’t change the result. Then I tried to upgrade through iTunes (which I guess the supported way) and it was successfully done.

I was be able to restore my data but I forgot to sync the apps so all of them was lost. I had to go to my history in App Store and redownload all. Luckily, my restore data had all the data of applications so I lost no data.

As you see, if you want to upgrade, you better not try Xcode instead of iTunes and don’t forget to backup your iPhone then sync all the apps.

What I saw at first that my iPhone was struggling to run iOS 6 sometimes, it was ending up burning like hell. It wasn’t happening all the time actually but for certain applications.

For example, iOS 6 mail application was running too slow sometimes and it doesn’t even respond. Then the iPhone’s temperature was getting high quickly.

Also, since Apple will be using its own maps application instead of Google Maps, the Map application is working on Apple Maps. I wasn’t sure about what the problem is but the maps application is totally useless at the moment. I guess my location Turkiye is involved with this issue but maps application is very slow and it doesn’t even show the maps. They added voice navigation and 3D view too but I couldn’t even get there since the maps app was not working stabile. It also caused heat problem, too.

For sure, beta version had pretty cool features which you will get a chance to see in the links I shared above. What I liked that Siri could open applications now [in iOS 5, it says “I’d like to but I’m not allowed to :(“] and navigation in maps will save most people buying a navigation app (I might be one of those), you have options for incoming calls like reply with an sms etc., you can set your iPhone to “don’t disturb” mode or you can keep it open for chosen contacts and all that kind of stuff.

But even though I’m an Apple Developer, I think I’ll wait for the community version of iOS 6. If they release fixed version of beta, that will stay as an option too.

Post a comment

Asp.Net Menu | Hide The Last Seperator Image

Sometimes it’s hard to understand why things work different in Asp.Net. Maybe that’s because I’m not so expert with it. Though, it makes no sense to me not to be able to seperate Asp.Net Menu items with chars like ‘|’ or ‘-‘ etc. Allright, we create little seperator images but when we do it, it either adds before all elements or after. Like “Home | News | Contact |”. What’s the sense of last seperator? What is it seperating actually? I never seen such usage…

Anyway, there’s always a way to do what we want but I just don’t know why we have to cross that bridge.

Here’s the code that hides last menu item’s seperator image so that we have a normal menu:

protected void myMenu_PreRender(object sender, EventArgs e)
{
    //We define seperator image for all menu items except the last (Items.Count -1)
    for (int i = 0; i < myMenu.Items.Count-1; i++)
    {
        myMenu.Items[i].SeparatorImageUrl = "~/Images/MasterPage/menu-seperator.png";
    }
}
Post a comment