Heavily inspired by this, I have made a plugin that works in mobiles and desktops to crop an image
What I made is added touch support, added dynamic canvas size based on image dimensions and trying to add functionality of moving an image rather selection area like here. I wanted to buy this item but it has failed my test case in devices (I am sorry to mention here). So thought of customizing the first mentioned source.
Here is the fiddle.
my html is
<div class="container">
<canvas id="panel" width="779" height="519"></canvas>
</div>
<input type="button" value="crop Selection" id="crop-image" />
<img id="croppedSelection" height="100px" width="100px" />
And calling it like
var Cropper = new CanvasCrop(document.getElementById('panel'), 'http://www.script- tutorials.com/demos/197/images/image.jpg');
$('#crop-image').on('click', function(){
var src = Cropper.getBase64();
$('#croppedSelection').attr('src', src);
});
My only problem is now, how can I keep the selection area on screen while image parent is being scrolled as here.
Thanks, help will be greatly appreciated.
Source code is huge to fit here, so added a working fiddle.. Thanks
Edit
Updated fiddle fixed canvas height and width issue
I wrote this code because I was bored.
Add this class above your code. you do not need the class if you only want one viewer on the page, you can put this all in a simple object. perhaps you need more:
function viewer (html_viewer)
{
this.html_viewer=html_viewer;
Object.defineProperty (html_viewer,"viewer_instance",{writeable:false,configureable:false,enumerable:false,value:this});
this.Selections=new Array ();
html_viewer.addEventListener ("mousedown",this.startScrolling);
html_viewer.addEventListener ("mouseup", this.endScrolling);
html_viewer.addEventListener ("scroll",this.setSelectionPosition);
}
viewer.prototype.startScrolling=function ()
{
var Selections=this.viewer_instance.Selections, Selection;
var l=Selections.length;
for (var i=0;i<l;i++)
{
Selection=Selections[i];
Selection.startLeft=Selection.x;
Selection.startTop=Selection.y;
Selection.viewer_startScrollLeft=this.scrollLeft;
Selection.viewer_startScrollTop=this.scrollTop;
}
}
viewer.prototype.setSelectionPosition=function ()
{
var Selections=this.viewer_instance.Selections, Selection;
var l=Selections.length;
for (var i=0;i<l;i++)
{
Selection=Selections[i];
Selection.x=this.scrollLeft-Selection.viewer_startScrollLeft+Selection.startLeft;
Selection.y=this.scrollTop-Selection.viewer_startScrollTop+Selection.startTop;
}
this.viewer_instance.drawScene ();
}
viewer.prototype.endScrolling=function ()
{
var Selections=this.viewer_instance.Selections, Selection;
var l=Selections.length;
for (var i=0;i<l;i++)
{
Selection=Selections[i];
Selection.startLeft=null;
Selection.startTop=null;
Selection.viewer_startScrollLeft=null;
Selection.viewer_startScrollTop=null;
}
}
viewer.prototype.addSelection=function (Selection)
{
Selection.startLeft=null;
Selection.startTop=null;
Selection.viewer_startScrollLeft=null;
Selection.viewer_startScrollTop=null;
Selection.viewerIndex=this.Selections.length;
this.Selections.push (Selection);
}
viewer.prototype.removeSelection=function (viewerIndex)
{
var Selections=this.Selections, l=Selections.length, i;
Selection=Selections[viewerIndex];
delete Selection.startLeft;
delete Selection.startTop;
delete Selection.viewer_startScrollLeft;
delete Selection.viewer_startScrollTop;
delete Selection.viewerIndex;
for (i=viewerIndex+1;i<l;i++)
Selections[i].viewerIndex=i-1;
Selections.splice (viewerIndex,1);
}
var imageViewer= new viewer (document.getElementById("panel").parentNode);
After line 27
theSelection = new Selection(64, 64, 64, 64);
Add
imageViewer.addSelection (theSelection);
imageViewer.drawScene=drawScene;
That's all, if you have problems let me know.
need further discussion how to implement image crop. do you want a selection inside the canvas or do you want to resize the complete imageCropper container and make a crop
// look at
http://jsfiddle.net/ThorstenArtnerAustria/5qdDW/1/
Related
I'm working on a client's web design and development powered by Wordpress and Woocommerce, the plugin is great but there's a few functions I wish it had. The main one is giving the ability for the user to save the preview of their configuration.
The plug-in is 'Woocommerce Visual Products Configurator':
It allows buyers to build their own item by selecting from a series of different attributes for different parts of an item. Ex, choosing different types of Soles for a shoe, as well as being able to choose from a series of laces for the same shoe.
My Issue: The configuration images are layered on top of each other as the user selects their options so any normal "save as" function will just save the top image.
I have succesfully managed to combine and save the images using html2canvas-Data URL() but the way it generates the screenshots means the quality becomes very poor.
My thoughts are to merge all the images within the "vpc-preview" DIV then force the download.
Hunting through the functions of the plugin I found this:
function merge_pictures($images, $path = false, $url = false) {
$tmp_dir = uniqid();
$upload_dir = wp_upload_dir();
$generation_path = $upload_dir["basedir"] . "/VPC";
$generation_url = $upload_dir["baseurl"] . "/VPC";
if (wp_mkdir_p($generation_path)) {
$output_file_path = $generation_path . "/$tmp_dir.png";
$output_file_url = $generation_url . "/$tmp_dir.png";
foreach ($images as $imgs) {
list($width, $height) = getimagesize($imgs);
$img = imagecreatefrompng($imgs);
imagealphablending($img, true);
imagesavealpha($img, true);
if (isset($output_img)) {
imagecopy($output_img, $img, 0, 0, 0, 0, 1000, 500);
} else {
$output_img = $img;
imagealphablending($output_img, true);
imagesavealpha($output_img, true);
imagecopymerge($output_img, $img, 10, 12, 0, 0, 0, 0, 100);
}
}
imagepng($output_img, $output_file_path);
imagedestroy($output_img);
if ($path)
return $output_file_path;
if ($url)
return $output_file_url;
} else
return false;
}
However the function isn't called anywhere. There's also a couple of "save" buttons that are commented out which makes me wonder if they removed from a previous build.
Ideally I'd like the user to be able to instantly share their creation to facebook but thought this would be a good start.
Any ideas would be greatly appreciated!
Thanks!
UPDATE:
I've managed to use the following code to output an alert of the url's of each of the config images. Useless for the user but at least I know it's targeting exactly what I need.
function img_find() {
var imgs = document.querySelectorAll('#vpc-preview img');
var imgSrcs = [];
for (var i = 0; i < imgs.length; i++) {
imgSrcs.push(imgs[i].src);
}
return alert(imgSrcs);
}
Any suggestions on how to manipulate this and merge the corresponding image of each URL then force the download?
Cick to see Fiddle
UPDATE 2: The following fiddle lets users upload images and then merges them into a single photo for download. Unfortunately my coding skills aren't good enough to manipulate this into using the SRC urls of images within certain DIV and to Merge all the photos on top of each other.
Fiddle
function addToCanvas(img) {
// resize canvas to fit the image
// height should be the max width of the images added, since we rotate -90 degree
// width is just a sum of all images' height
canvas.height = max(lastHeight, img.width);
canvas.width = lastWidth + img.height;
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (lastImage) {
ctx.drawImage(lastImage, 0, canvas.height - lastImage.height);
}
ctx.rotate(270 * Math.PI / 180); // rotate the canvas to the specified degrees
ctx.drawImage(img, -canvas.height, lastWidth);
lastImage = new Image();
lastImage.src = canvas.toDataURL();
lastWidth += img.height;
lastHeight = canvas.height;
imagesLoaded += 1;
}
Based on this question/answer, I would take a look at node-canvas.
What I have done in the past is use a #print css file to only capture the divs needed. Very simple concept but works well.
After looking at your link, that is exactly the situations I use it in..online designers. It is a little more difficult keeping your layers responsively aligned, but in the end I feel your codes become cleaner and it works well across devices and OS'.
If you dont want PDF and a simple preview and download than html2image.js is perfect.
$(document).ready(function(){
var element = $("#html-content-holder"); // global variable
var getCanvas; // global variable
$("#btn-Preview-Image").on('click', function () {
html2canvas(element, {
onrendered: function (canvas) {
$("#previewImage").append(canvas);
getCanvas = canvas;
}
});
});
$("#btn-Convert-Html2Image").on('click', function () {
var imgageData = getCanvas.toDataURL("image/png");
// Now browser starts downloading it instead of just showing it
var newData = imgageData.replace(/^data:image\/png/, "data:application/octet-stream");
$("#btn-Convert-Html2Image").attr("download", "your_pic_name.png").attr("href", newData);
});
});
<script src="https://github.com/niklasvh/html2canvas/releases/download/0.4.1/html2canvas.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="html-content-holder" style="background-color: #F0F0F1; color: #00cc65; width: 500px;
padding-left: 25px; padding-top: 10px;">
Place any code here
</div>
<input id="btn-Preview-Image" type="button" value="Preview"/>
<a id="btn-Convert-Html2Image" href="#">Download</a>
<br/>
<h3>Preview :</h3>
<div id="previewImage">
</div>
For High quality you want to use rasterizeHTML.js
Found here:
https://github.com/cburgmer/rasterizeHTML.js/blob/master/examples/retina.html
I am looking at a way to divide the image into pieces.
The no of pieces that the image can be split into is configurable using tile_height and tile_width.Looking for help.
I would not want any solution with any frameworks. Only using vanilla JavaScript
I tried the below
var _clipX =0;
var _clipY = _clipX;
var _clipHeight = IMAGE_HEIGHT/TILE_HEIGHT;
var _clipWidth = IMAGE_WIDTH/TILE_WIDTH;
var _nRows = Math.floor(IMAGE_HEIGHT/TILE_HEIGHT);
var _nColumns = Math.floor(IMAGE_WIDTH/TILE_WIDTH);
for(var i=0;i<_nRows;i++){
for(var j=0;j<_nColumns;j++){
el.getContext('2d').drawImage(image, _clipX, _clipY, _clipWidth, _clipHeight, _clipX, _clipY,_clipWidth , _clipHeight);
_clipX = _clipX + _clipWidth;
}
_clipX = 0
_clipY = _clipY + _clipHeight;
}
Below is the JSFiddle for the work
JSFiddle
Yes!!!
Found it. Instead of iterating over the image tag dimensions when you call draw image it does iterate over the natural dimensions of the image hence the issue I faced.
Now I have tried with the image size same as my img tag dimensions and it works perfectly fine.
Thanks everyone for the help offered
I have this code:
<script type="text/javascript">
var aImages = [
"images/gaming/GTAV/GTAVReviewImage1.jpg",
"images/gaming/GTAV/GTAVReviewImage2.jpg",
"images/gaming/GTAV/GTAVReviewImage3.jpg",
"images/gaming/GTAV/GTAVReviewImage4.jpg",
"images/gaming/GTAV/GTAVReviewImage5.jpg",
"images/gaming/GTAV/GTAVReviewImage6.jpg",
"images/gaming/GTAV/GTAVReviewImage7.jpg"];
var oImage = null;
var iIdx = 0;
function play() {
try {
if (oImage===null) { oImage=window.document.getElementById("review-images"); }
oImage.src = aImages[(++iIdx)%(aImages.length)];
setTimeout('play()',5000);
} catch(oEx) {
}
}
</script>
which changes the image on this page: http://chrisbrighton.co.uk/GTAV.php every five seconds.
How can I add image transition to it?
UPDATE: When I add -webkit-transition to the img tag nothing happens.
Thanks.
There are different ways to do it. A lot of people have went to CSS3 now that there is some really cool animating and transition effects... You can control your ccs3 effects using javascript. For a detailed tutorial check - controlling animations with javascript
I create a test code below and you can manipulate it on Jsfiddle:
http://jsfiddle.net/Stallman41/57hvX/31/
HTML:
<canvas id="test_canvas" style="background-color : #FFFF00" ; width="500px"
; height="340px"></canvas>
<br>
<button id="test_put_btn">Put an image</button>
<br>
<button id="save_dataURL">Save to dataURL</button>
<br>
<button id="draw_back">Final step: draw 3 images back.</button>
<br>
<img id="first_img"; width="100px" ; height="100px" ;></img>
<img id="second_img"; width="100px" ; height="100px" ></img>
<img id="third_img"; width="100px" ; height="100px" ;></img>
Javascript:
var drawing_plate;
var context;
var dataURL_arr = new Array();
$(document).ready(function () {
drawing_plate = document.getElementById("test_canvas");
context = drawing_plate.getContext('2d');
$("#test_canvas").bind("mousedown", Touch_Start);
$("#test_canvas").bind("mousemove", Touch_Move);
$("#test_canvas").bind("mouseup", Touch_End);
}); //document ready.
function Touch_Start(event) {
event.preventDefault();
touch = event;
touch_x = touch.pageX;
touch_y = touch.pageY;
line_start_x = touch.pageX - 0;
line_start_y = touch.pageY - 0;
context.beginPath();
context.moveTo(line_start_x, line_start_y);
}
function Touch_Move(event) {
event.preventDefault();
touch = event; //mouse
line_end_x = touch.pageX - 0;
line_end_y = touch.pageY - 0;
context.lineTo(line_end_x, line_end_y);
context.stroke();
}
$("#test_put_btn").click(function () {
var test_img = new Image();
test_img.src = "http://careerscdn.sstatic.net/careers/gethired/img/careers2- ad-header-so-crop.png";
context.drawImage(test_img, 0, 0);
});
$("#save_dataURL").click(function () {
dataURL_arr.push(drawing_plate.toDataURL("image/png"));
});
$("#draw_back").click(function () {
var f_image= $("#first_img")[0];
var s_image= $("#second_img")[0];
var t_image= $("#third_img")[0];
f_image.onload= function()
{
f_image.src= dataURL_arr[0];
}
f_image.src= dataURL_arr[0];
s_image.onload= function()
{
s_image.src= dataURL_arr[0];
}
s_image.src= dataURL_arr[0];
t_image.onload= function()
{
t_image.src= dataURL_arr[0];
}
t_image.src= dataURL_arr[0];
});
I develop a drawing plate on Android system, saving the drawings to a dataURL string. They can draw something on the canvas and put images on the canvas. And I need to let the users see their drawings on small icons.
I use canvas.toDataURL("image/png") to save the base64 string. And I choose <img> as the small icon container. However, what I got is only the drawings can be shown on the icon, and usually, when I write img.src= canvas.toDataURL("image/png"); the image shows nothing!
I investigate the issue for long time.
1. I think the problem might be the dataURL string is too long?
2. The support of the OS: Android?
The code in Jsfiddle here shows a similar procedure on my Android PhoneGap development.
First , you just draw something on the canvas, and press Press an image, and then Save to dataURL. But you should do the process three times. In this condition, the string array contains the base64 string generated by the drawings and the image.
In the final, you press Final step: draw 3 images back., nothing will be shown on the image icon.
In conclusion:
In my experience, as I write img.src= canvas.toDataURL("image/png"); (no matter the img is an dom element or var img = new Image();). It can't always work: sometimes it works... but sometimes not...(I work on Android 4.0.1, phonegap 1.7.0)
Second, especially if I store lots of base64 strings to an array, assigning them to lots of image DOM element, it definitely fails.
Third, if the user only draw something on the canvas, it can always work.( Except the example code in the Jsfiddle, but it works on my Android system...)
But if he draw an image context.drawImage(~) the image wouldn't show the pic.
Too much confusions...
I need to let the user can view their drawings in small icon, any alternative?
Some References:
1
2
3
I just stumbled across this question.
Click Put an image, then click Save to dataURL, then check your JavaScript console for something like:
SecurityError: DOM Exception 18
It's a browser security feature. Because you've inserted an image from a different domain, it counts as a cross-origin request.
If you eliminate the security error, you can export the canvas to a data URL.
Another thing in your code.
The image you try to draw onto the canvas into your test_put_btn onclick event handler, your image will never show up (or it will sometimes work accidentally) because you don't wait for your image to be loaded to draw it onto the canvas.
You have to handle the "onload" event of your image and draw it into the handler to permit the drawing of your image.
Before your test_img.src statement, you have to put :
test_img.onload = function()
{
context.drawImage(test_img, 0, 0);
};
Plus, the image you try to access is not accessible --> For me it does not work
I'm trying to create a very simple gallery using javascript. There are thumbnails, and when they're clicked the big image's source gets updated. Everything works fine, except when I try it in IE the images' size stays the same as the inital image's size was. Let's say initial image is 200x200 and I click on a thumbnail of a 100x100 image, the image is displayed but it is streched to 200x200. I don't set any width or height values, so I guess the browser should use image's normal size, and so does for example FF.
here's some code:
function showBigImage(link)
{
var source = link.getAttribute("href");
var bigImage = document.getElementById("bigImage");
bigImage.setAttribute("src", source);
return false; /* prevent normal behaviour of <a> element when clicked */
}
and html looks like this:
<ul id="gallery">
<li>
<a href="images/gallery/1.jpg">
<img src="images/gallery/1thumb.jpg">
</a>
</li>
(more <li> elements ...)
</ul>
the big image is created dynamically:
function createBigImage()
{
var bigImage = document.createElement("img");
bigImage.setAttribute("id", "bigImage");
bigImage.setAttribute("src", "images/gallery/1.jpg");
var gal = document.getElementById("gallery");
var gal_parent = gal.parentNode;
gal_parent.insertBefore(bigImage, gal);
}
There's also some code setting the onclick events on the links, but I don't think it's relevant in this situaltion. As I said the problem is only with IE. Thanks in advance!
Sounds like IE is computing the width and height attributes for #bigImage when it is created and then not updating them when the src is changed. The other browsers are probably noting that they had to compute the image dimensions themselves so they recompute them when the src is changed. Both approaches are reasonable enough.
Do you know the proper size of the image inside showBigImage()? If you do, then set the width and height attributes explicitly when you change the src:
function showBigImage(link) {
var source = link.getAttribute("href");
var bigImage = document.getElementById("bigImage");
bigImage.setAttribute("src", source);
bigImage.setAttribute("width", the_proper_width);
bigImage.setAttribute("height", the_proper_height);
return false;
}
If you don't know the new dimensions then change showBigImage() to delete #bigImage and create a new one:
function createBigImage(src) {
var bigImage = document.createElement("img");
bigImage.setAttribute("id", "bigImage");
bigImage.setAttribute("src", src || "images/gallery/1.jpg");
var gal = document.getElementById("gallery");
gal.parentNode.insertBefore(bigImage, gal);
}
function showBigImage(link) {
var bigImage = document.getElementById("bigImage");
if(bigImage)
bigImage.parentNode.removeChild(bigImage);
createBigImage(link.getAttribute("href"););
return false;
}