CropperJS creating new images on page instead of cropping the specified image - javascript

Using cropper js to attempt to crop an img on the page, however,
it's actually appending 2 more of the same images on the page that I can "scroll" to change their aspect ratio.
const cropper = new Cropper(image, {
aspectRatio: 16 / 9,
crop(event) {
console.log(event.detail.x);
console.log(event.detail.y);
console.log(event.detail.width);
console.log(event.detail.height);
console.log(event.detail.rotate);
console.log(event.detail.scaleX);
console.log(event.detail.scaleY);
}
});
I also tried to do this to set the crop sizes;
viewMode: 1,
setData() {
x: dimensions.left;
y: dimensions.top;
width: dimensions.width;
height: dimensions.height;
}
However, it's proving to be difficult. Am I missing something?

Switched to using the Jimp library. Was much easier to figure out how to crop using that.

Related

Split image file in two separate image

I have on my server an image file with an height of 50 000px.
I want to save 2 files of 25 000px each (first and second part of the original image)
Any suggestions about how to do that ?
Thanks
The sharp image package might be useful for this scenario. More specifically the extract method.
I've added a link to the documentation but here's a possible implementation to split up the image.
const sharp = require("sharp");
const originalFilename = "image.jpg";
const image = sharp(originalFilename);
// this is just a placeholder
const imageWidth = 500;
image
.extract({ left: 0, top: 0, width: imageWidth, height: 25000 })
.toFile("top.jpg", function(err) {
// Save the top of the image to a file named "top.jpg"
});
image
.extract({ left: 0, top: 25000, width: imageWidth, height: 25000 })
.toFile("bottom.jpg", function(err) {
// Save the bottom of the image to a file named "bottom.jpg"
});
I'm assuming you can reuse the original sharp image object to call the extract function twice. If not you might need to call the sharp constructor again.

Clipping mask using fabricjs

I'm currently working on web app for photo editing using FabricJS and one of features I need to implement is something like Clipping masks from Photoshop.
For example I have this assets: frame, mask and image. I need to insert image inside frame and clip it with mask. Most tricky part is in requirements:
User should be able to modify image inside frame, e.g. move, rotate, skew... Frame itself also can be moved inside canvas.
Number of layers is not limited so user can add objects under or above masked image.
Masks, frames and images is not predefined, user should be able to upload and use new assets.
My current solution is this:
Load assets
Set globalCompositeOperation of image to source-out
Set clipTo function for image.
Add assets on canvas as a group
In this solution clipTo function preserve image inside rectangular area of frame and with help of globalCompositeOperation I'm clipping image to actual mask. At first sight it works fine but if I add new layer above this newly added group it will be cutted off because of globalCompositeOperation="source-out" rule. I've created JSFiddle to show this.
So, that else could I try? I've seen some posts on StackOverflow with advices to use SVGs for clipping mask, but if I understand it correctly SVG must contain only one path. This could be a problem because of third requirement of my app.
Any advice in right direction will help, because right now I'm totally stuck with this problem.
You can do this by using ClipPath property of Img Object which you want to mask. With this, you can Mask Any Type of Object. and also you need to add some Ctx Configuration in ClipTo function of Img Object.
check this link https://jsfiddle.net/naimsajjad/8w7hye2v/8/
(function() {
var img01URL = 'http://fabricjs.com/assets/printio.png';
var img02URL = 'http://fabricjs.com/lib/pug.jpg';
var img03URL = 'http://fabricjs.com/assets/ladybug.png';
var img03URL = 'http://fabricjs.com/assets/ladybug.png';
var canvas = new fabric.Canvas('c');
canvas.backgroundColor = "red";
canvas.setHeight(500);
canvas.setWidth(500);
canvas.setZoom(1)
var circle = new fabric.Circle({radius: 40, top: 50, left: 50, fixed: true, fill: '', stroke: '1' });
canvas.add(circle);
canvas.renderAll();
fabric.Image.fromURL(img01URL, function(oImg) {
oImg.scale(.25);
oImg.left = 10;
oImg.top = 10;
oImg.clipPath = circle;
oImg.clipTo = function(ctx) {
clipObject(this,ctx)
}
canvas.add(oImg);
canvas.renderAll();
});
var bili = new fabric.Path('M85.6,606.2c-13.2,54.5-3.9,95.7,23.3,130.7c27.2,35-3.1,55.2-25.7,66.1C60.7,814,52.2,821,50.6,836.5c-1.6,15.6,19.5,76.3,29.6,86.4c10.1,10.1,32.7,31.9,47.5,54.5c14.8,22.6,34.2,7.8,34.2,7.8c14,10.9,28,0,28,0c24.9,11.7,39.7-4.7,39.7-4.7c12.4-14.8-14-30.3-14-30.3c-16.3-28.8-28.8-5.4-33.5-11.7s-8.6-7-33.5-35.8c-24.9-28.8,39.7-19.5,62.2-24.9c22.6-5.4,65.4-34.2,65.4-34.2c0,34.2,11.7,28.8,28.8,46.7c17.1,17.9,24.9,29.6,47.5,38.9c22.6,9.3,33.5,7.8,53.7,21c20.2,13.2,62.2,10.9,62.2,10.9c18.7,6.2,36.6,0,36.6,0c45.1,0,26.5-15.6,10.1-36.6c-16.3-21-49-3.1-63.8-13.2c-14.8-10.1-51.4-25.7-70-36.6c-18.7-10.9,0-30.3,0-48.2c0-17.9,14-31.9,14-31.9h72.4c0,0,56-3.9,70.8,26.5c14.8,30.3,37.3,36.6,38.1,52.9c0.8,16.3-13.2,17.9-13.2,17.9c-31.1-8.6-31.9,41.2-31.9,41.2c38.1,50.6,112-21,112-21c85.6-7.8,79.4-133.8,79.4-133.8c17.1-12.4,44.4-45.1,62.2-74.7c17.9-29.6,68.5-52.1,113.6-30.3c45.1,21.8,52.9-14.8,52.9-14.8c15.6,2.3,20.2-17.9,20.2-17.9c20.2-22.6-15.6-28-16.3-84c-0.8-56-47.5-66.1-45.1-82.5c2.3-16.3,49.8-68.5,38.1-63.8c-10.2,4.1-53,25.3-63.7,30.7c-0.4-1.4-1.1-3.4-2.5-6.6c-6.2-14-74.7,30.3-74.7,30.3s-108.5,64.2-129.6,68.9c-21,4.7-18.7-9.3-44.3-7c-25.7,2.3-38.5,4.7-154.1-44.4c-115.6-49-326,29.8-326,29.8s-168.1-267.9-28-383.4C265.8,13,78.4-83.3,32.9,168.8C-12.6,420.9,98.9,551.7,85.6,606.2z',{top: 0, left: 180, fixed: true, fill: 'white', stroke: '', scaleX: 0.2, scaleY: 0.2 });
canvas.add(bili);
canvas.renderAll();
fabric.Image.fromURL(img02URL, function(oImg) {
oImg.scale(0.5);
oImg.left = 180;
oImg.top = 0;
oImg.clipPath = bili;
oImg.clipTo = function(ctx) {
clipObject(this,ctx)
}
canvas.add(oImg);
canvas.renderAll();
});
function clipObject(thisObj,ctx)
{
if (thisObj.clipPath) {
ctx.save();
if (thisObj.clipPath.fixed) {
var retina = thisObj.canvas.getRetinaScaling();
ctx.setTransform(retina, 0, 0, retina, 0, 0);
// to handle zoom
ctx.transform.apply(ctx, thisObj.canvas.viewportTransform);
thisObj.clipPath.transform(ctx);
}
thisObj.clipPath._render(ctx);
ctx.restore();
ctx.clip();
var x = -thisObj.width / 2, y = -thisObj.height / 2, elementToDraw;
if (thisObj.isMoving === false && thisObj.resizeFilter && thisObj._needsResize()) {
thisObj._lastScaleX = thisObj.scaleX;
thisObj._lastScaleY = thisObj.scaleY;
thisObj.applyResizeFilters();
}
elementToDraw = thisObj._element;
elementToDraw && ctx.drawImage(elementToDraw,
0, 0, thisObj.width, thisObj.height,
x, y, thisObj.width, thisObj.height);
thisObj._stroke(ctx);
thisObj._renderStroke(ctx);
}
}
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.3/fabric.min.js"></script>
<canvas id="c" width="400" height="400"></canvas>
Not sure what you want.
If you want the last image loaded (named img2), the one you send to the back to not effect the layers above do the following.
You have mask,frame,img, and img2;
Put them in the following order and with the following comp settings.
img2, source-over
img, source-over
mask, destination-out
frame, source-over
If you want something else you will have to explain it in more detail.
Personally when I provide masking to the client I give them full access to all the composite methods and allow them to work out what they need to do to achieve a desired effect. Providing a UI that allows you to change the comp setting, and layer order makes it a lot easier to sort out the sometimes confusing canvas composite rules.
I'd suggest looking at this solution.
Multiple clipping areas on Fabric.js canvas
You end up with a shape layer that is used to define the mask shape. That shape then gets applied as a clipTo to your image.
The one limitation I can think off though that you might run into is when you start to rotate various shapes. I know I have it working great with a rectangle and a circle, however ran into some issues with polygons from what I recall... This was all setup under and older version of FabricJS however, so there may have been some improvements there that I'm not experienced with.
The other issue I ran into was drop shadows didn't render correctly when passed to a NodeJS server running FabricJS.

CreateJS - Can't get my spritesheet to animate

I've checked this forum/the internet/google forwards and backwards for my particular question, but to no avail. I get examples that come close to mine - which I try to impart into my own example, but nothing doing. Please help! Again I apologize if this has been answered and I just overlooked, if so please throw me a link - otherwise here is my code:
All I'm trying to do is animate a single sprite image of a jumping Mega Man.
Thanks, and Happy Holidays!
NOTE: Here the sprite I'm using
HERE IS MY: JsFiddle
var stage, canvas,
bmpA, data,
megaman, spriteSheet;
function Main() {
canvas = document.getElementById('canvas');
stage = new createjs.Stage(canvas);
container = new createjs.Container();
megaman = new Image();
megaman.src = "megaman__jump.png";
var bmpA = new createjs.Bitmap(megaman);
data = new createjs.SpriteSheet({
images: [bmpA],
frames: {
width: 79,
height: 139,
count: 7
},
animations: {
jump: [0, 6, "jump"]
}
});
spriteSheet = new createjs.BitmapAnimation(data);
spriteSheet.gotoAndPlay("jump");
createjs.Ticker.setFPS(30);
createjs.Ticker.addEventListener("tick", update);
}
function update(event) {
stage.addChild(spriteSheet);
stage.update();
}
</script>
</head>
<body onload = "Main();">
<canvas id = "canvas" width = "780" height = "300"
style = "border: 1px solid #000;"></canvas>
</body>
</html>
[1]: http://i.imgur.com/Q1OQM.png
Here is a quick edit. http://jsfiddle.net/lannymcnie/f58mr0Lk/9/
Your Fiddle wasn't very helpful, since it was just your code pasted in. I modified it to drop the body tag (jsfiddle does that for you), import easeljs, and use the full image path.
The BitmapAnimation class was renamed to Sprite sometime ago. I am not sure what version of EaselJS you are using, but it might not have that class anymore.
I removed the Bitmap. The SpriteSheet data accepts either a string path, or an Image reference, not a Bitmap.
As I suggested below, I pulled out the entire update method, added the Sprite one time, and then had the tick just update the stage directly.
The fiddle "works" now, but the spritesheet dimensions don't seem right. Have a look.
data = new createjs.SpriteSheet({
images: ["http://i943.photobucket.com/albums/ad274/Rah5er0/megaman__jump.png~original"],
frames: {
width: 79,
height: 139,
count: 7
},
animations: {
jump: [0, 6, "jump"]
}
});
var sprite = new createjs.Sprite(data);

Why does the Jcrop-tracker not show it's correct position?

In my app users can take a picture or upload an image from their device. This image is the source for a Jcrop function. This function works correctly, as in it 'crops' correctly. However the jcrop-tracker that previews what you are cropping doesn't show it's correct position on the image.
Please see this example:
When moving the tracker to the top of the image, it'll show almost the entire image. When moving further down, it'll show nothing at all. How is this possible?
My guess is this is because of jCrop having issues with downscaled pictures (for example pictures taken from device camera).
I use CSS to downscale the image so it can fit on on device screen:
#imgContainer {
max-width: 100%;
max-height: 100%;
}
#imgContainer img {
max-width: 100%;
max-height: 100%;
}
Is there any way to prevent this?
Here's my code:
$(window).load(function() {
var jcrop_api, boundx, boundy;
function updatePreview(c) { // croping image preview
if (parseInt(c.w) > 0) {
var rx = 220 / c.w, ry = 220 / c.h;
}
}
function showCoords(c) { // show all coords
$('#x').val(c.x);
$('#y').val(c.y);
$('#x2').val(c.x2);
$('#y2').val(c.y2);
$('#w').val(c.w);
$('#h').val(c.h);
}
$('#cropImage').Jcrop({
onChange: updatePreview,
onSelect: showCoords,
bgFade: true,
bgOpacity: .8,
aspectRatio: 1,
maxSize: [ 150, 150 ],
boxWidth: 284,
boxHeight: 382
},function(){
jcrop_api = this;
});
var canvas = document.getElementById("canvasresult");
$("#m1-cropScreen-cropIt").on("click", function(){
var context = canvas.getContext("2d");
var img = document.getElementById("cropImage"),
$img = $(img),
imgW = img.naturalWidth,
imgH = img.naturalHeight;
console.log($img.width());
console.log($img.height());
var ratioY = imgH / $img.height(),
ratioX = imgW / $img.width();
var getX = $('#x').val() * ratioX,
getY = $('#y').val() * ratioY,
getWidth = $('#w').val() * ratioX,
getHeight = $('#h').val() * ratioY;
context.drawImage(img,getX,getY,getWidth,getHeight,0,0,150,150);
$('#cropResult').attr('src', canvas.toDataURL());
});
});
Gentleman, I'm sorry for the delay in responding to you. Thank you everyone who replied on my question.
I've had a very busy week so I had little time to work on this project. Today I've picked it up again and I first tried to solve this problem myself again.
Fortunately, this time it worked. I ended up using Jcrop's box sizing method. I believe I had tried it before, but this time it works flawlessly. So problem solved :)
Unfortunate this did not work for me but I had a different issue that I hope will help anyone else who has this this issue.
Mine was due to a css styling conflict.
From a 3rd party style sheet
img { max-width: 100% }
My Style Sheet -- adding this fixed it
.jcrop-holder img, img.jcrop-preview { max-width: none !important }

Resize KineticJS Stage without losing quality

I need to put a high resolution image (approx 3072x2304) into a HTML5 Canvas based interface using KineticJS, which the user can add text to, and subsequently output an downloadable image.
However, I want the canvas to be able to fit in a typical monitor for ease of viewing purposes.
In other words, I want the display resolution to be less than 1024x768.
At the same time, I still want the HTML5 Canvas output image to remain at the high 3072x2304 resolution. I am struggling to achieve a scaled down display resolution without losing image quality.
Right now, either I have to upload a smaller 1024x768 file and sacrifice output quality, or I am forced to introduce scroll bars to the canvas.
How do I get it to work like a regular HTML img tag, where the browser resizes the image, but the source stays high resolution?
var stage = new Kinetic.Stage({
container: 'container',
width: 1024,
height: 768,
});
imageObj.onload = function() {
var backgroundimg = new Kinetic.Image({
x: 0,
y: 0,
image: imageObj,
width: 3072,
height: 2304,
draggable: false,
});
stage.add(backgroundimg);
You just about have it worked out...
Load the image into a javascript image object and then use that to create a kinetic image
imgFull will remain at 3072 x 2304 (its original size)
backgroundimg will be scaled down to 1024 x 768
Here's example code:
// create the stage
var stage = new Kinetic.Stage({
container: 'container',
width: 1024,
height: 768,
});
// create a layer on the stage
var layer=new Kinetic.Layer();
stage.add(layer);
// create a full sized javascript image object (imgFull)
// and use that to create a Kinetic.Image at 1/3 size (backgroundimg)
var backgroundimg;
var imgFull=new Image();
imgFull.onload=function(){
backgroundimg=new Kinetic.Image({
x: 0,
y: 0,
image: imageObj,
width: 1024,
height: 768,
draggable: false,
});
layer.add(backgroundimg);
}
imgFull.src="yourImage.png";

Categories