Using JS (or jQuery) and CSS, I am trying to build a web page that enables the positioning of one image inside a very specific rectangular area of another image. Think of how Paste Into works in Photoshop; that is conceptually what I’m trying to achieve.
I was looking deeply into the excellent cropperjs library, thinking that would provide an efficient way to do this (without reinventing a bunch of wheels) and so I made this post within the cropperjs forum. But the developer of cropperjs posted this as a response:
I think you may need another library, this library may not fit your
purpose.
Now to describe my need in more detail:
Begin with IMAGE #1. This will be an image on the web page that doesn’t move, crop, or change in any way. BUT it will have a rectangular region within its boundaries (defined by me) inside which another image (IMAGE #2) must be placed. This placement needs to behave similarly to Photoshop’s Paste Into
, in that IMAGE #2 will not be distorted in any way: it will be placed inside the predefined region of IMAGE #1 and able to drag/position around (by mouse on a PC or finger on a phone). Much of IMAGE #2 will be cropped away and invisible.
Only the portion inside the defined rectangular region will be visible. Within that region, IMAGE #2 will overlay/cover/obscure the region of IMAGE #1. So a portion of IMAGE #2 will be on top of IMAGE #1, but IMAGE #2 can only live within the predefined region of IMAGE #1. IMAGE #2 needs to be draggable within that region. When the desired positioning is complete, I need to enable the user (via js) to capture and save the entire composite image.
Sorry to belabor the point, but in case that’s not clear, let me describe it pictorially:
IMAGE #1 (fixed on the page):
Notice the blue border: that is my predefined region. Everything outside that region will remain the same. Everything inside that region will be covered by a portion of IMAGE #2.
IMAGE #2:
A cropped version of IMAGE #2 will appear inside the predefined (blue-border) region of IMAGE #1, and the user will be able to drag it around as desired until the position is satisfactory.
IMAGE #3 (the final composite):
Finally, I need the user to be able to click a button that (calling some JS) captures the composite image and enables it to be saved, or transmitted via ajax to my server. The final image needs to be high-res without any compression or degradation: just as high-res as the original images on the page.
I’m OK using a third-party library. I’m also OK doing this from scratch. But I need some guidance as to the simplest and most efficient way to do it. I’m very comfortable with HTML, CSS, JavaScript, and jQuery. Any pointers to a working example of something similar, or a library that does it, is all I’m looking for.
2
Answers
Here’s a small standalone example of how to do something like this with the Canvas 2D Context API.
In your example, your user would probably not choose the base image themselves but you’d get it from your server or whatnot.
As you mentioned in your comment, you could use draggable functionality from jQuery UI to enable positioning for the second image. You could also use html2canvas to capture your montage.
Since I got a cross-origin issue with the built-in snippet on Stack Overflow, please take a look at this JSFiddle. I put the code below too:
I used a bit of Vanilla JS in there, especially when I found it more convenient than jQuery.
Notice that you can modify image quality through the
scale
option (see html2canvas options).EDIT 1
As explained in my comment, I initially put a very restrictive height to avoid large images for my demo. Your test shows that your first image has been reduced too much, so you do not see that its width can actually be larger than the frame. This is because it depends on the aspect ratio…
To give you a more insightful answer, I edited my JSFiddle. Now you can select the area (using draggable and resizable interactions from jQuery UI) before pasting the second image. I also defined a less restrictive height and added html2canvas options to make it work.
Here is the updated code:
EDIT 2
If you do not want to ignore what is outside the crop area in your export, you can define a
$firstChild
variable containing$container.children().first()
(above$lastChild
declaration and initialization) then configure html2canvas like this: