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. You can 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.

JavaScript: Export HTML Table to Excel With Custom File Name

Web browser wars hurt developers’ hearts. It is mostly about CSS, sometimes about JavaScript, HTML etc…

Thus I know how it feels when you expect something to get done easily appears a lot more harder than you expected.

Code below is tested only with Chrome (24+). It is making these processes:

  • Gets the HTML code of your table inside your div element.
  • Replaces the spaces in the code with correct syntax for Excel (otherwise spaces will be removed in your Excel sheet).
  • Generates a specific file name (for minutes) in order to avoid overriding old files and to supply archiving by date values.
  • And lastly and most importantly, saving the file with a custom file name.

Here’s my combination of codes (from different SO questions or tutorials) if you want to save HTML table to client computer using JavaScript code.

$(document).ready(function() {
    $("#btnExport").click(function(e) {
        //getting values of current time for generating the file name
        var dt = new Date();
        var day = dt.getDate();
        var month = dt.getMonth() + 1;
        var year = dt.getFullYear();
        var hour = dt.getHours();
        var mins = dt.getMinutes();
        var postfix = day + "." + month + "." + year + "_" + hour + "." + mins;
        //creating a temporary HTML link element (they support setting file names)
        var a = document.createElement('a');
        //getting data from our div that contains the HTML table
        var data_type = 'data:application/vnd.ms-excel';
        var table_div = document.getElementById('dvData');
        var table_html = table_div.outerHTML.replace(/ /g, '%20');
        a.href = data_type + ', ' + table_html;
        //setting the file name
        a.download = 'exported_table_' + postfix + '.xls';
        //triggering the function
        a.click();
        //just in case, prevent default behaviour
        e.preventDefault();
    });
});

ScriptCam Integration for .Net: ScriptCamForDotNet Repository

Hi all,

Recently I had to take pictures from web camera in my Asp.Net page. There’s a great flash-based plugin works with jQuery, named ScriptCam. So I been dealing integration of this to my Asp.Net page.

You can see my bio above, I hate (unnecessary) postbacks. So it all works on client, faster, then I store the binary data of captured image in my Session variable. Next page I show it on Page_Load event.

You can see the working example here,
Or you can download the project from here.

That’s my first repository, I hope it becomes helpful for some fellas.

PHP Coding Standards (pear.php.net)

https://pear.php.net/manual/en/standards.php

52543667

Always use to delimit PHP code, not the <? ?> shorthand.

<?php ?>

Control statements should have one space between the control keyword and opening parenthesis, to distinguish them from function calls.

if (true) {
   switch (condition) {
      case 1:
         action1;
         break;
      case 2:
         action2;
         break;
   }
}

You are strongly encouraged to always use curly braces even in situations where they are technically optional.

if (true) {
   // single line stuff
}

Split long if statements onto several lines keeping the question mark and the colon at the front.

if (($condition1 || $condition2)
    && $condition3 && $condition4
   ) {
   //code here
}

There should be one space on either side of an equals sign used to assign the return value of a function to a variable

$long_variable = foo($baz);

The CS require lines to have a maximum length of 80 chars. It is allowed to split parameters in function calls onto several lines.

$this->someObject->subObject->callThisFunctionWithALongName(
   $parameterOne, $parameterTwo, $aVeryLongParameterThree
);

The same applies not only for parameter variables, but also for nested function calls and for arrays.

someFunction(
   array(
      "foo" => "bar"
   )
);

To support readability, the equal signs may be aligned in block-related assignments:

$short     = foo($bar);
$thelonger = foo($baz);
52543649

Class and function declarations have their opening brace on a new line:

class Foo_Bar
{
}
function doThing()
{
}

Function declarations follow the “K&R style” http://en.wikipedia.org/wiki/Indent_style#K.26R_style

Arguments with default values go at the end of the argument list.

function doAnotherThing($id = 0, $doAgain = false)
{
}

include_once and require_once are statements, not functions. Parentheses should not surround the subject filename.

include_once "/file.php";

Selecting Grouped Row Count When Using MySQL GROUP BY Column

You may have been using subqueries to get how many rows were grouped when using MySQL’s GROUP BY function. There’s a little trick that helps to get this number without using subqueries, more clean and faster (when the amount of rows get higher).

Let’s assume we have a table contain folks from different cities. Like this:

folk_name   |   city_name
---------------------------
evren       |   ohio
steve       |   ohio
cem         |   weston
don         |   sunderland
ritchie     |   weston
ian         |   hounslow
alican      |   ohio

When we want to get only city names (distinct) from this table, we may group the data by city_name column like this:

SELECT f.* FROM `folks` f GROUP BY f.`city_name`

And the result would be:

folk_name   |   city_name
---------------------------
ian         |   hounslow
evren       |   ohio
don         |   sunderland
cem         |   weston

The expected behaviour of GROUP BY is to select first rows so other folks from same cities do not appear. It also orders by the GROUP BY column (ascending).

Let’s say we want to get how many folks exist in each city by grouping by. First thing comes to mind could be using a subquery like this:

SELECT f1.*, (SELECT COUNT(f2.`folk_name`) FROM `folks` f2 WHERE f2.`city_name` = f1.`city_name`) AS `folk_count` FROM `folks` f1 GROUP BY `city_name`

And the result would be:

folk_name   |   city_name   |   folk_count
-------------------------------------------
ian         |   hounslow    |   1
evren       |   ohio        |   3
don         |   sunderland  |   1
cem         |   weston      |   2

Let’s admit, subqueries are messy. They make the query more complicated to read and also are question marks on performance.

How about selecting number 1 (one) for each row and sum it up on grouping by?

Doing something like this:

SELECT f.*,SUM(1) AS `folk_count` FROM `folks` f GROUP BY f.`city_name`

Would return:

folk_name   |   city_name   |   folk_count
-------------------------------------------
ian         |   hounslow    |   1
evren       |   ohio        |   3
don         |   sunderland  |   1
cem         |   weston      |   2

Nicely done.