So, I'm making a web application, where users should be able to upload an image and crop it:
<img>
<img>
Note: Code is simplified
jQuery('#my_upload_input').change(function(my_event)
{
my_load_image(my_event.currentTarget.files);
});
jQuery(document).keyup(function(my_event)
{
if (my_event.which == 13)
{
my_crop_image();
}
});
var my_file_glob;
var my_image_glob;
var my_jcrop_api_glob;
function my_load_image(my_files)
{
var my_file_glob = my_files[0];
var my_image_glob = new Image();
my_image_glob.onload = function()
{
my_show_image();
};
my_image_glob.src = URL.createObjectURL(my_file_glob);
}
function my_show_image()
{
jQuery('#my_container').html('<img id="my_img" src="' + my_image_glob.src + '" />');
jQuery('#my_img').Jcrop(
{
boxWidth: 1280,
boxHeight: 720,
trueSize: [my_image_glob.width, my_image_glob.height],
setSelect: [0, 0, 1920, 1080],
aspectRatio: 1920 / 1080,
minSize: [1920, 1080],
bgColor: '',
allowSelect: false
}, function()
{
my_jcrop_api_glob = this;
});
}
function my_crop_image()
{
if (typeof my_jcrop_api_glob !== 'undefined')
{
var my_selection = my_jcrop_api_glob.tellSelect();
var my_canvas = document.createElement('canvas');
var my_canvas_context = my_canvas.getContext('2d');
my_canvas.width = my_selection.w;
my_canvas.height = my_selection.h;
my_canvas_context.drawImage(my_image_glob, my_selection.x, my_selection.y, my_selection.w, my_selection.h, 0, 0, my_selection.w, my_selection.h);
my_upload_canvas(my_canvas);
}
}
function my_upload_canvas(my_canvas)
{
var my_canvas_url = my_canvas.toDataURL('image/png');
jQuery.ajax(
{
type: 'POST',
url: 'ajax_calls.php',
data:
{
my_canvas_url: my_canvas_url
},
success: function(my_response)
{
alert(my_response);
window.location.reload(true);
}
});
}
if(isset($_POST['my_canvas_url']))
{
$my_canvas_url = $_POST['my_canvas_url'];
my_upload_canvas($my_canvas_url);
}
function my_upload_canvas($my_canvas_url)
{
$my_canvas_data_enc = explode(',', $my_canvas_url)[1];
$my_canvas_data_enc = str_replace(' ', '+', $my_canvas_data_enc);
$my_canvas_data_dec = base64_decode($my_canvas_data_enc);
file_put_contents(dirname(__FILE__) . '/menu.png', $my_canvas_data_dec);
if($my_png_created !== false)
{
echo 'success';
}
else
{
echo 'failure';
}
}
In the function my_upload_canvas(my_canvas)
, I've written these few lines to compare the size of the original image and the cropped area:
var head = 'data:image/png;base64,';
var imgfilesize = Math.round((my_canvas_url.length - head.length) * 3 / 4);
console.log('size orig: ' + Math.round(my_file_glob.size));
console.log('size crop: ' + Math.round(imgfilesize));
console.log('cropped area is ' + Math.round(imgfilesize / my_file_glob.size) + ' times bigger than the original image');
The outputs for three different images are the following:
JPEG (807 KB)
size orig: 826730
size crop: 2445081
cropped area is 3 times bigger than the original image
JPG (141 KB)
size orig: 144837
size crop: 1201146
cropped area is 8 times bigger than the original image
PNG (334 KB)
size orig: 342617
size crop: 53799
cropped area is 0 times bigger than the original image
Note that the sizes of the cropped areas of image #1 and #2 are bigger than the ones of the original images themselves, but not for image #3.
The 500 Internal Server Error was caused by the $
in front of the function plugins_url()
...silly me. But, unfortunately, saving the .png still won't work (I can't even create the file). Introduction and code updated.
Uploading the image works now! I replaced
file_put_contents(plugins_url('/menu.png', __FILE__), $my_canvas_data_dec)
with
file_put_contents(dirname(__FILE__) . '/menu.png', $my_canvas_data_dec)
as apparently a URL won't work, but a full path will. Introduction and code updated.
Mystery solved! As you can read here, the canvas contains no more information than the pixels of the image. Therefore the size of the data url depends on how the browser encodes these pixels and can result in being larger than the one of the image. Furthermore, a PNG will in most cases be much larger than a JPEG of the same canvas.
I figured it out myself. Please have a look at the updates of my post if you're interested in the answers.