如何在前端截取包含用户上传图片的 div 的屏幕截图?
How to take screenshot of the div that contain user Uploaded images in frontend?
请查看此代码。在下面的代码中,用户可以上传图片,他们可以移动、调整大小、旋转上传的图片等。
$(function() {
var inputLocalFont = $("#user_file");
inputLocalFont.change(previewImages);
function previewImages() {
var fileList = this.files;
var anyWindow = window.URL || window.webkitURL;
for (var i = 0; i < fileList.length; i++) {
var objectUrl = anyWindow.createObjectURL(fileList[i]);
var $newDiv = $("<div>", {
class: "img-div"
});
var $newImg = $("<img>", {
src: objectUrl,
class: "newly-added"
}).appendTo($newDiv);
$(".new-multiple").append($newDiv);
$newDiv.draggable();
$newDiv.rotatable();
$newDiv.resizable({
aspectRatio: true,
handles: "ne, nw, e, se, sw, w"
});
$newDiv.find(".ui-icon").removeClass("ui-icon ui-icon-gripsmall-diagonal-se");
window.URL.revokeObjectURL(fileList[i]);
}
$(".newly-added").on("click", function(e) {
$(".newly-added").removeClass("img-selected");
$(this).addClass("img-selected");
e.stopPropagation()
});
$(document).on("click", function(e) {
if ($(e.target).is(".newly-added") === false) {
$(".newly-added").removeClass("img-selected");
}
});
}
$(".user_submit").on("click",function(e){
e.preventDefault();
html2canvas($('.new-multiple'), {
allowTaint: true,
onrendered: function(canvas) {
document.body.appendChild(canvas);
}
});
});
});
.new-multiple {
width: 400px !important;
height: 400px !important;
background: white;
border: 2px solid red;
overflow: hidden;
}
.img-div {
width: 200px;
height: 200px;
}
.newly-added {
width: 100%;
height: 100%;
}
.img-selected {
box-shadow: 1px 2px 6px 6px rgb(206, 206, 206);
border: 2px solid rgb(145, 44, 94);
}
/*
.ui-resizable-handle.ui-resizable-se.ui-icon.ui-icon-gripsmall-diagonal-se {
background-color: white;
border: 1px solid tomato;
}
*/
.ui-resizable-handle {
border: 0;
border-radius: 50%;
background-color: #00CCff;
width: 14px;
height: 14px;
}
.ui-resizable-nw {
top: -7px;
left: -7px;
}
.ui-resizable-ne {
top: -7px;
right: -7px;
}
.ui-resizable-e {
top: calc(50% - 7px);
right: -7px;
}
.ui-resizable-w {
top: calc(50% - 7px);
left: -7px;
}
.ui-resizable-sw {
bottom: -7px;
left: -7px;
}
.ui-resizable-se {
right: -7px;
bottom: -7px;
}
.ui-resizable-se.ui-icon {
display: none;
}
.ui-rotatable-handle {
background-size: 14px;
background-repeat: no-repeat;
background-position: center;
border: 0;
border-radius: 50%;
background-color: #00CCff;
margin-left: calc(50% - 9px);
bottom: -5px;
width: 18px;
height: 18px;
}
<link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet"/>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<link href="https://cdn.jsdelivr.net/gh/godswearhats/jquery-ui-rotatable@1.1/jquery.ui.rotatable.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/gh/godswearhats/jquery-ui-rotatable@1.1/jquery.ui.rotatable.min.js"></script>
<script src="https://html2canvas.hertzen.com/build/html2canvas.js"></script>
<form method="post" action="">
<input name="user_file[]" id="user_file" style="position: relative;overflow: hidden" multiple="" type="file">
<div class="new-multiple"></div>
<input type="submit" name="submit" class="user_submit" value="submit" />
</form>
https://jsfiddle.net/s99kxydw/15/
上传图片后,旋转、移动然后用户将按下提交按钮。那个时候我们需要生成 window 的截图,这样用户和我们都可以了解用户做了什么更改。这是我们的要求。
How we can generate this screenshot ?
我们找到了一种解决方案。即html2canvas
https://html2canvas.hertzen.com/
但问题是 html2canvas 不支持 css transform
属性
因此屏幕截图中没有旋转。我们怎么能克服这个。请检查代码。
有没有不用html2canvas的其他方法?
我明白你的问题是什么,因为我用 html2canvas 做过类似的事情。它的问题。是它不能保存所有内容,所以它可能不完全准确,例如它不能进行 css 文本剪辑。这对我有用(我用它下载了图片,但你也可以很容易地保存它,看看这个 link 如何做到这一点):
html2canvas($('.classOfElementToSave'), {
allowTaint: true,
onrendered: function(canvas) {
var dataURL = canvas.toDataURL();
$.ajax({
type: "POST",
url: "script.php",
data: {
imgBase64: dataURL
}
}).done(function(o) {
console.log('saved');
// If you want the file to be visible in the browser
// simply return the url previously saved
});
}
});
然后在您的 script.php 或文件(或任何文件名称)中:
$img = $_POST['data'];
$img = str_replace('data:image/png;base64,', '', $img); //Because saved as a data image
$img = str_replace(' ', '+', $img);
$fileData = base64_decode($img);
//saving the image to server
$fileName = 'image.png';
file_put_contents($fileName, $fileData);
这只是一半的回答。正如我所说,另一半将取决于您使用什么类型的脚本来生成新图像。
这半部分展示了如何捕获所有各种细节。假设您的红色框是新图像的视口,这将在您进行更改时收集详细信息,以便您可以将它们传递给将构建图像的脚本。
我假定了捕获以下详细信息的选项:
- 文件名
- 文件大小
- 维度
- 位置
- 旋转
如果需要,您可以删除文件名并让用户指定名称值。
HTML
<form method="post" action="">
<button id="browse-btn">Browse Images</button>
<input name="user_file[]" id="user_file" style="display: none; position: relative;overflow: hidden" multiple="" type="file" />
<div class="new-multiple"></div>
<button id="submit-btn" type="submit">Submit</button>
<div class="meta-details">
<ul>
<li>
<label>Name:</label>
<span></span>
</li>
<li>
<label>Size:</label>
<span></span>
</li>
<li>
<label>Width:</label>
<span></span>
</li>
<li>
<label>Height:</label>
<span></span>
</li>
<li>
<label>Top:</label>
<span></span>
</li>
<li>
<label>Left:</label>
<span></span>
</li>
<li>
<label>Rotation:</label>
<span></span>
</li>
</ul>
</div>
</form>
CSS
form button {
margin: 3px;
}
.new-multiple {
width: 400px !important;
height: 400px !important;
background: white;
border: 2px solid #faa;
border-radius: 3px;
overflow: hidden;
}
.img-div {
width: 200px;
height: 200px;
}
.newly-added {
width: 100%;
height: 100%;
}
.img-selected {
box-shadow: 1px 2px 6px 6px rgb(206, 206, 206);
border: 2px solid rgb(145, 44, 94);
}
.ui-resizable-handle {
border: 0;
border-radius: 50%;
background-color: #00CCff;
width: 14px;
height: 14px;
}
.ui-resizable-nw {
top: -7px;
left: -7px;
}
.ui-resizable-ne {
top: -7px;
right: -7px;
}
.ui-resizable-e {
top: calc(50% - 7px);
right: -7px;
}
.ui-resizable-w {
top: calc(50% - 7px);
left: -7px;
}
.ui-resizable-sw {
bottom: -7px;
left: -7px;
}
.ui-resizable-se {
right: -7px;
bottom: -7px;
}
.ui-resizable-se.ui-icon {
display: none;
}
.ui-rotatable-handle {
background-size: 14px;
background-repeat: no-repeat;
background-position: center;
border: 0;
border-radius: 50%;
background-color: #00CCff;
margin-left: calc(50% - 9px);
bottom: -5px;
width: 18px;
height: 18px;
}
.meta-details ul {
padding: 0;
margin: 0;
list-style: none;
font-family: Arial, sans-serif;
font-size: 9px;
}
.meta-details ul li label {
display: inline-block;
width: 45px;
}
JavaScript
$(function() {
var inputLocalFont = $("#user_file");
inputLocalFont.change(previewImages);
function humanFileSize(bytes, si) {
var thresh = si ? 1000 : 1024;
if (Math.abs(bytes) < thresh) {
return bytes + ' B';
}
var units = si ? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] : ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
var u = -1;
do {
bytes /= thresh;
++u;
} while (Math.abs(bytes) >= thresh && u < units.length - 1);
return bytes.toFixed(1) + ' ' + units[u];
}
function logMeta(d) {
var $m = $(".meta-details ul li span");
$m.eq(0).html(d.name);
$m.eq(1).html(humanFileSize(d.size));
$m.eq(2).html(d.width + " px");
$m.eq(3).html(d.height + " px");
$m.eq(4).html(d.top + " px");
$m.eq(5).html(d.left + " px");
$m.eq(6).html(d.rotateDeg + " °");
}
function previewImages() {
var fileList = this.files;
var fileMeta = [];
$.each(fileList, function(key, val) {
fileMeta[key] = {
name: val.name,
size: val.size,
modified: val.lastModified
};
});
var anyWindow = window.URL || window.webkitURL;
for (var i = 0; i < fileList.length; i++) {
var $list = fileList[i];
var $meta = fileMeta[i];
var objectUrl = anyWindow.createObjectURL(fileList[i]);
var $newDiv = $("<div>", {
class: "img-div"
});
var $newImg = $("<img>", {
src: objectUrl,
class: "newly-added"
}).appendTo($newDiv);
$meta['width'] = $newImg.width();
$meta['height'] = $newImg.height();
$meta['rotateDeg'] = 0.000;
$meta['top'] = $newImg.position().top;
$meta['left'] = $newImg.position().left;
$(".new-multiple").append($newDiv);
$newDiv.draggable({
drag: function(e, ui) {
$meta['top'] = ui.position.top;
$meta['left'] = ui.position.left;
logMeta($meta);
$newImg.data("meta", $meta);
}
});
$newDiv.rotatable({
rotate: function(e, ui) {
$meta['rotateDeg'] = Math.round(ui.angle.degrees * 10000) / 10000;
$meta['rotateRad'] = ui.angle.current;
logMeta($meta);
$newImg.data("meta", $meta);
}
});
$newDiv.resizable({
aspectRatio: true,
handles: "ne, nw, e, se, sw, w",
resize: function(e, ui) {
$meta['width'] = ui.size.width;
$meta['height'] = ui.size.height;
logMeta($meta);
$newImg.data("meta", $meta);
}
});
$newDiv.find(".ui-icon").removeClass("ui-icon ui-icon-gripsmall-diagonal-se");
window.URL.revokeObjectURL(fileList[i]);
console.log($meta);
logMeta($meta);
$newImg.data("meta", $meta);
}
$(".newly-added").on("click", function(e) {
$(".newly-added").removeClass("img-selected");
$(this).addClass("img-selected");
e.stopPropagation();
});
$(document).on("click", function(e) {
if ($(e.target).is(".newly-added") === false) {
$(".newly-added").removeClass("img-selected");
}
});
}
$("button").button();
$("#browse-btn").click(function(e) {
e.preventDefault();
$("#user_file").trigger("click");
});
$("#browse-btn").click(function(e) {
e.preventDefault();
$(this).parent().submit();
});
$("form").submit(function(e) {
e.preventDefault();
console.log("Prepared Meta Data:");
$(".newly-added").each(function() {
console.log($(this).data("meta"));
});
// AJAX Post Code will be entered here
});
});
首先参考 @mpen here from converting file size in bytes to human-readable string 文件大小转换功能。
您可以看到我们创建了一个数组来存储与文件关联的相应详细信息。这会随着项目被拖动、调整大小或旋转而更新。您可以在提交表格时连同原始图像一起提交这些详细信息。所以至少你的用户界面现在已经构建好了。
您的下一步将是根据这些详细信息查看您希望如何构建和保存图像。因此,开始查看 Image Processing 以获得 PHP。查看您要使用哪个并从该后端脚本开始。
html2canvas 不 支持大多数 css 属性(基本属性除外),其中之一是您可能拥有的 transform
已经知道,不幸的是,也有没有解决方法(使用html2canvas)。
但是,您可以使用一个名为 FabricJS 的 JavaScript canvas 库,它似乎最适合您的目的,例如操纵 (移动、调整大小、旋转等) 用户上传的图片(s).
使用此库的最佳部分是,您无需使用 html2canvas 或任何其他附加库来截取屏幕截图。您可以直接将 canvas (截屏) 保存为图像,因为 FabricJS 本质上是一个 canvas 库。
这是一个 basic example 证明:
var canvas = new fabric.Canvas('myCanvas', {
backgroundColor: 'white'
});
function renderImage(e) {
var imgUrl = URL.createObjectURL(e.target.files[0]);
fabric.Image.fromURL(imgUrl, function(img) {
// set default props
img.set({
width: 150,
height: 150,
top: 75,
left: 75,
transparentCorners: false
});
canvas.add(img);
canvas.renderAll();
});
}
function saveOnPC() {
var link = document.createElement('a');
link.href = canvas.toDataURL();
link.download = 'myImage.png';
link.click();
}
function saveOnServer() {
$.post('https://your-site-name.com/save-image.php', {
data: canvas.toDataURL()
}, function() {
console.log('Image saved on server!');
});
/* use the following PHP code for 'save-image.php' on server-side
<? php
$img = $_POST['data'];
$img = str_replace('data:image/png;base64,', '', $img);
$img = str_replace(' ', '+', $img);
$fileData = base64_decode($img);
$fileName = 'myImage.png';
file_put_contents($fileName, $fileData);
*/
}
canvas{border:1px solid red}input{margin-bottom:6px}button{margin:10px 3px 0 0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.19/fabric.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="file" onchange="renderImage(event)">
<canvas id="myCanvas" width="300" height="300"></canvas>
<button onclick="saveOnPC()">Save on PC</button>
<button onclick="saveOnServer()">Save on Server</button>
要了解有关 FabricJS 库的更多信息,请参阅它 的 Official Documentation。
您尝试过 rasterizeHTML 吗?
我会引用它:
For security reasons rendering HTML into a canvas is severly limited... However it is possible by embedding the HTML into an SVG image as a and then drawing the resulting image via ctx.drawImage().
您可以在 Github 上找到该项目,他们在那里解释了如何使用它:
在@ValfarDeveloper 之后,您可以将 <img>
的 .src
的值分配给 data URI
而不是 Blob URL
并设置当前的 HTML 的 ".new-multiple"
在 <svg>
字符串中的 <foreignObject>
元素处。
$(function() {
var inputLocalFont = $("#user_file");
inputLocalFont.change(previewImages);
async function previewImages() {
var fileList = this.files;
var anyWindow = window.URL || window.webkitURL;
for (var i = 0; i < fileList.length; i++) {
var objectUrl = await new Promise(resolve => {
var reader = new FileReader;
reader.onload = e => resolve(reader.result);
reader.readAsDataURL(fileList[i]);
});
var $newDiv = $("<div>", {
class: "img-div"
});
var $newImg = $("<img>", {
src: objectUrl,
class: "newly-added"
}).appendTo($newDiv);
$(".new-multiple").append($newDiv);
$newDiv.draggable();
$newDiv.rotatable();
$newDiv.resizable({
aspectRatio: true,
handles: "ne, nw, e, se, sw, w"
});
$newDiv.find(".ui-icon").removeClass("ui-icon ui-icon-gripsmall-diagonal-se");
}
$(".newly-added").on("click", function(e) {
$(".newly-added").removeClass("img-selected");
$(this).addClass("img-selected");
e.stopPropagation()
});
$(document).on("click", function(e) {
if ($(e.target).is(".newly-added") === false) {
$(".newly-added").removeClass("img-selected");
}
});
}
$(".user_submit").on("click",function(e){
e.preventDefault();
let html = $(".new-multiple").html();
let svg = `<?xml version="1.0" standalone="yes"?>
<svg xmlns="http://www.w3.org/2000/svg" width="400px" height="400px" viewBox="0 0 400 300">
<foreignObject width="400px" height="300px"
requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<html xmlns="http://www.w3.org/1999/xhtml">
${html}
</html>
</foreignObject>
</svg>`;
$("body").append(svg);
});
});
.new-multiple {
width: 400px !important;
height: 400px !important;
background: white;
border: 2px solid red;
overflow: hidden;
}
.img-div {
width: 200px;
height: 200px;
}
.newly-added {
width: 100%;
height: 100%;
}
.img-selected {
box-shadow: 1px 2px 6px 6px rgb(206, 206, 206);
border: 2px solid rgb(145, 44, 94);
}
/*
.ui-resizable-handle.ui-resizable-se.ui-icon.ui-icon-gripsmall-diagonal-se {
background-color: white;
border: 1px solid tomato;
}
*/
.ui-resizable-handle {
border: 0;
border-radius: 50%;
background-color: #00CCff;
width: 14px;
height: 14px;
}
.ui-resizable-nw {
top: -7px;
left: -7px;
}
.ui-resizable-ne {
top: -7px;
right: -7px;
}
.ui-resizable-e {
top: calc(50% - 7px);
right: -7px;
}
.ui-resizable-w {
top: calc(50% - 7px);
left: -7px;
}
.ui-resizable-sw {
bottom: -7px;
left: -7px;
}
.ui-resizable-se {
right: -7px;
bottom: -7px;
}
.ui-resizable-se.ui-icon {
display: none;
}
.ui-rotatable-handle {
background-size: 14px;
background-repeat: no-repeat;
background-position: center;
border: 0;
border-radius: 50%;
background-color: #00CCff;
margin-left: calc(50% - 9px);
bottom: -5px;
width: 18px;
height: 18px;
}
<link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet"/>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<link href="https://cdn.jsdelivr.net/gh/godswearhats/jquery-ui-rotatable@1.1/jquery.ui.rotatable.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/gh/godswearhats/jquery-ui-rotatable@1.1/jquery.ui.rotatable.min.js"></script>
<script src="https://html2canvas.hertzen.com/build/html2canvas.js"></script>
<form method="post" action="">
<input name="user_file[]" id="user_file" style="position: relative;overflow: hidden" multiple="" type="file">
<div class="new-multiple"></div>
<input type="submit" name="submit" class="user_submit" value="submit" />
</form>
请查看此代码。在下面的代码中,用户可以上传图片,他们可以移动、调整大小、旋转上传的图片等。
$(function() {
var inputLocalFont = $("#user_file");
inputLocalFont.change(previewImages);
function previewImages() {
var fileList = this.files;
var anyWindow = window.URL || window.webkitURL;
for (var i = 0; i < fileList.length; i++) {
var objectUrl = anyWindow.createObjectURL(fileList[i]);
var $newDiv = $("<div>", {
class: "img-div"
});
var $newImg = $("<img>", {
src: objectUrl,
class: "newly-added"
}).appendTo($newDiv);
$(".new-multiple").append($newDiv);
$newDiv.draggable();
$newDiv.rotatable();
$newDiv.resizable({
aspectRatio: true,
handles: "ne, nw, e, se, sw, w"
});
$newDiv.find(".ui-icon").removeClass("ui-icon ui-icon-gripsmall-diagonal-se");
window.URL.revokeObjectURL(fileList[i]);
}
$(".newly-added").on("click", function(e) {
$(".newly-added").removeClass("img-selected");
$(this).addClass("img-selected");
e.stopPropagation()
});
$(document).on("click", function(e) {
if ($(e.target).is(".newly-added") === false) {
$(".newly-added").removeClass("img-selected");
}
});
}
$(".user_submit").on("click",function(e){
e.preventDefault();
html2canvas($('.new-multiple'), {
allowTaint: true,
onrendered: function(canvas) {
document.body.appendChild(canvas);
}
});
});
});
.new-multiple {
width: 400px !important;
height: 400px !important;
background: white;
border: 2px solid red;
overflow: hidden;
}
.img-div {
width: 200px;
height: 200px;
}
.newly-added {
width: 100%;
height: 100%;
}
.img-selected {
box-shadow: 1px 2px 6px 6px rgb(206, 206, 206);
border: 2px solid rgb(145, 44, 94);
}
/*
.ui-resizable-handle.ui-resizable-se.ui-icon.ui-icon-gripsmall-diagonal-se {
background-color: white;
border: 1px solid tomato;
}
*/
.ui-resizable-handle {
border: 0;
border-radius: 50%;
background-color: #00CCff;
width: 14px;
height: 14px;
}
.ui-resizable-nw {
top: -7px;
left: -7px;
}
.ui-resizable-ne {
top: -7px;
right: -7px;
}
.ui-resizable-e {
top: calc(50% - 7px);
right: -7px;
}
.ui-resizable-w {
top: calc(50% - 7px);
left: -7px;
}
.ui-resizable-sw {
bottom: -7px;
left: -7px;
}
.ui-resizable-se {
right: -7px;
bottom: -7px;
}
.ui-resizable-se.ui-icon {
display: none;
}
.ui-rotatable-handle {
background-size: 14px;
background-repeat: no-repeat;
background-position: center;
border: 0;
border-radius: 50%;
background-color: #00CCff;
margin-left: calc(50% - 9px);
bottom: -5px;
width: 18px;
height: 18px;
}
<link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet"/>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<link href="https://cdn.jsdelivr.net/gh/godswearhats/jquery-ui-rotatable@1.1/jquery.ui.rotatable.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/gh/godswearhats/jquery-ui-rotatable@1.1/jquery.ui.rotatable.min.js"></script>
<script src="https://html2canvas.hertzen.com/build/html2canvas.js"></script>
<form method="post" action="">
<input name="user_file[]" id="user_file" style="position: relative;overflow: hidden" multiple="" type="file">
<div class="new-multiple"></div>
<input type="submit" name="submit" class="user_submit" value="submit" />
</form>
https://jsfiddle.net/s99kxydw/15/
上传图片后,旋转、移动然后用户将按下提交按钮。那个时候我们需要生成 window 的截图,这样用户和我们都可以了解用户做了什么更改。这是我们的要求。
How we can generate this screenshot ?
我们找到了一种解决方案。即html2canvas
https://html2canvas.hertzen.com/
但问题是 html2canvas 不支持 css transform
属性
因此屏幕截图中没有旋转。我们怎么能克服这个。请检查代码。
有没有不用html2canvas的其他方法?
我明白你的问题是什么,因为我用 html2canvas 做过类似的事情。它的问题。是它不能保存所有内容,所以它可能不完全准确,例如它不能进行 css 文本剪辑。这对我有用(我用它下载了图片,但你也可以很容易地保存它,看看这个 link 如何做到这一点):
html2canvas($('.classOfElementToSave'), {
allowTaint: true,
onrendered: function(canvas) {
var dataURL = canvas.toDataURL();
$.ajax({
type: "POST",
url: "script.php",
data: {
imgBase64: dataURL
}
}).done(function(o) {
console.log('saved');
// If you want the file to be visible in the browser
// simply return the url previously saved
});
}
});
然后在您的 script.php 或文件(或任何文件名称)中:
$img = $_POST['data'];
$img = str_replace('data:image/png;base64,', '', $img); //Because saved as a data image
$img = str_replace(' ', '+', $img);
$fileData = base64_decode($img);
//saving the image to server
$fileName = 'image.png';
file_put_contents($fileName, $fileData);
这只是一半的回答。正如我所说,另一半将取决于您使用什么类型的脚本来生成新图像。
这半部分展示了如何捕获所有各种细节。假设您的红色框是新图像的视口,这将在您进行更改时收集详细信息,以便您可以将它们传递给将构建图像的脚本。
我假定了捕获以下详细信息的选项:
- 文件名
- 文件大小
- 维度
- 位置
- 旋转
如果需要,您可以删除文件名并让用户指定名称值。
HTML
<form method="post" action="">
<button id="browse-btn">Browse Images</button>
<input name="user_file[]" id="user_file" style="display: none; position: relative;overflow: hidden" multiple="" type="file" />
<div class="new-multiple"></div>
<button id="submit-btn" type="submit">Submit</button>
<div class="meta-details">
<ul>
<li>
<label>Name:</label>
<span></span>
</li>
<li>
<label>Size:</label>
<span></span>
</li>
<li>
<label>Width:</label>
<span></span>
</li>
<li>
<label>Height:</label>
<span></span>
</li>
<li>
<label>Top:</label>
<span></span>
</li>
<li>
<label>Left:</label>
<span></span>
</li>
<li>
<label>Rotation:</label>
<span></span>
</li>
</ul>
</div>
</form>
CSS
form button {
margin: 3px;
}
.new-multiple {
width: 400px !important;
height: 400px !important;
background: white;
border: 2px solid #faa;
border-radius: 3px;
overflow: hidden;
}
.img-div {
width: 200px;
height: 200px;
}
.newly-added {
width: 100%;
height: 100%;
}
.img-selected {
box-shadow: 1px 2px 6px 6px rgb(206, 206, 206);
border: 2px solid rgb(145, 44, 94);
}
.ui-resizable-handle {
border: 0;
border-radius: 50%;
background-color: #00CCff;
width: 14px;
height: 14px;
}
.ui-resizable-nw {
top: -7px;
left: -7px;
}
.ui-resizable-ne {
top: -7px;
right: -7px;
}
.ui-resizable-e {
top: calc(50% - 7px);
right: -7px;
}
.ui-resizable-w {
top: calc(50% - 7px);
left: -7px;
}
.ui-resizable-sw {
bottom: -7px;
left: -7px;
}
.ui-resizable-se {
right: -7px;
bottom: -7px;
}
.ui-resizable-se.ui-icon {
display: none;
}
.ui-rotatable-handle {
background-size: 14px;
background-repeat: no-repeat;
background-position: center;
border: 0;
border-radius: 50%;
background-color: #00CCff;
margin-left: calc(50% - 9px);
bottom: -5px;
width: 18px;
height: 18px;
}
.meta-details ul {
padding: 0;
margin: 0;
list-style: none;
font-family: Arial, sans-serif;
font-size: 9px;
}
.meta-details ul li label {
display: inline-block;
width: 45px;
}
JavaScript
$(function() {
var inputLocalFont = $("#user_file");
inputLocalFont.change(previewImages);
function humanFileSize(bytes, si) {
var thresh = si ? 1000 : 1024;
if (Math.abs(bytes) < thresh) {
return bytes + ' B';
}
var units = si ? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] : ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
var u = -1;
do {
bytes /= thresh;
++u;
} while (Math.abs(bytes) >= thresh && u < units.length - 1);
return bytes.toFixed(1) + ' ' + units[u];
}
function logMeta(d) {
var $m = $(".meta-details ul li span");
$m.eq(0).html(d.name);
$m.eq(1).html(humanFileSize(d.size));
$m.eq(2).html(d.width + " px");
$m.eq(3).html(d.height + " px");
$m.eq(4).html(d.top + " px");
$m.eq(5).html(d.left + " px");
$m.eq(6).html(d.rotateDeg + " °");
}
function previewImages() {
var fileList = this.files;
var fileMeta = [];
$.each(fileList, function(key, val) {
fileMeta[key] = {
name: val.name,
size: val.size,
modified: val.lastModified
};
});
var anyWindow = window.URL || window.webkitURL;
for (var i = 0; i < fileList.length; i++) {
var $list = fileList[i];
var $meta = fileMeta[i];
var objectUrl = anyWindow.createObjectURL(fileList[i]);
var $newDiv = $("<div>", {
class: "img-div"
});
var $newImg = $("<img>", {
src: objectUrl,
class: "newly-added"
}).appendTo($newDiv);
$meta['width'] = $newImg.width();
$meta['height'] = $newImg.height();
$meta['rotateDeg'] = 0.000;
$meta['top'] = $newImg.position().top;
$meta['left'] = $newImg.position().left;
$(".new-multiple").append($newDiv);
$newDiv.draggable({
drag: function(e, ui) {
$meta['top'] = ui.position.top;
$meta['left'] = ui.position.left;
logMeta($meta);
$newImg.data("meta", $meta);
}
});
$newDiv.rotatable({
rotate: function(e, ui) {
$meta['rotateDeg'] = Math.round(ui.angle.degrees * 10000) / 10000;
$meta['rotateRad'] = ui.angle.current;
logMeta($meta);
$newImg.data("meta", $meta);
}
});
$newDiv.resizable({
aspectRatio: true,
handles: "ne, nw, e, se, sw, w",
resize: function(e, ui) {
$meta['width'] = ui.size.width;
$meta['height'] = ui.size.height;
logMeta($meta);
$newImg.data("meta", $meta);
}
});
$newDiv.find(".ui-icon").removeClass("ui-icon ui-icon-gripsmall-diagonal-se");
window.URL.revokeObjectURL(fileList[i]);
console.log($meta);
logMeta($meta);
$newImg.data("meta", $meta);
}
$(".newly-added").on("click", function(e) {
$(".newly-added").removeClass("img-selected");
$(this).addClass("img-selected");
e.stopPropagation();
});
$(document).on("click", function(e) {
if ($(e.target).is(".newly-added") === false) {
$(".newly-added").removeClass("img-selected");
}
});
}
$("button").button();
$("#browse-btn").click(function(e) {
e.preventDefault();
$("#user_file").trigger("click");
});
$("#browse-btn").click(function(e) {
e.preventDefault();
$(this).parent().submit();
});
$("form").submit(function(e) {
e.preventDefault();
console.log("Prepared Meta Data:");
$(".newly-added").each(function() {
console.log($(this).data("meta"));
});
// AJAX Post Code will be entered here
});
});
首先参考 @mpen here from converting file size in bytes to human-readable string 文件大小转换功能。
您可以看到我们创建了一个数组来存储与文件关联的相应详细信息。这会随着项目被拖动、调整大小或旋转而更新。您可以在提交表格时连同原始图像一起提交这些详细信息。所以至少你的用户界面现在已经构建好了。
您的下一步将是根据这些详细信息查看您希望如何构建和保存图像。因此,开始查看 Image Processing 以获得 PHP。查看您要使用哪个并从该后端脚本开始。
html2canvas 不 支持大多数 css 属性(基本属性除外),其中之一是您可能拥有的 transform
已经知道,不幸的是,也有没有解决方法(使用html2canvas)。
但是,您可以使用一个名为 FabricJS 的 JavaScript canvas 库,它似乎最适合您的目的,例如操纵 (移动、调整大小、旋转等) 用户上传的图片(s).
使用此库的最佳部分是,您无需使用 html2canvas 或任何其他附加库来截取屏幕截图。您可以直接将 canvas (截屏) 保存为图像,因为 FabricJS 本质上是一个 canvas 库。
这是一个 basic example 证明:
var canvas = new fabric.Canvas('myCanvas', {
backgroundColor: 'white'
});
function renderImage(e) {
var imgUrl = URL.createObjectURL(e.target.files[0]);
fabric.Image.fromURL(imgUrl, function(img) {
// set default props
img.set({
width: 150,
height: 150,
top: 75,
left: 75,
transparentCorners: false
});
canvas.add(img);
canvas.renderAll();
});
}
function saveOnPC() {
var link = document.createElement('a');
link.href = canvas.toDataURL();
link.download = 'myImage.png';
link.click();
}
function saveOnServer() {
$.post('https://your-site-name.com/save-image.php', {
data: canvas.toDataURL()
}, function() {
console.log('Image saved on server!');
});
/* use the following PHP code for 'save-image.php' on server-side
<? php
$img = $_POST['data'];
$img = str_replace('data:image/png;base64,', '', $img);
$img = str_replace(' ', '+', $img);
$fileData = base64_decode($img);
$fileName = 'myImage.png';
file_put_contents($fileName, $fileData);
*/
}
canvas{border:1px solid red}input{margin-bottom:6px}button{margin:10px 3px 0 0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.19/fabric.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="file" onchange="renderImage(event)">
<canvas id="myCanvas" width="300" height="300"></canvas>
<button onclick="saveOnPC()">Save on PC</button>
<button onclick="saveOnServer()">Save on Server</button>
要了解有关 FabricJS 库的更多信息,请参阅它 的 Official Documentation。
您尝试过 rasterizeHTML 吗?
我会引用它:
For security reasons rendering HTML into a canvas is severly limited... However it is possible by embedding the HTML into an SVG image as a and then drawing the resulting image via ctx.drawImage().
您可以在 Github 上找到该项目,他们在那里解释了如何使用它:
在@ValfarDeveloper 之后,您可以将 <img>
的 .src
的值分配给 data URI
而不是 Blob URL
并设置当前的 HTML 的 ".new-multiple"
在 <svg>
字符串中的 <foreignObject>
元素处。
$(function() {
var inputLocalFont = $("#user_file");
inputLocalFont.change(previewImages);
async function previewImages() {
var fileList = this.files;
var anyWindow = window.URL || window.webkitURL;
for (var i = 0; i < fileList.length; i++) {
var objectUrl = await new Promise(resolve => {
var reader = new FileReader;
reader.onload = e => resolve(reader.result);
reader.readAsDataURL(fileList[i]);
});
var $newDiv = $("<div>", {
class: "img-div"
});
var $newImg = $("<img>", {
src: objectUrl,
class: "newly-added"
}).appendTo($newDiv);
$(".new-multiple").append($newDiv);
$newDiv.draggable();
$newDiv.rotatable();
$newDiv.resizable({
aspectRatio: true,
handles: "ne, nw, e, se, sw, w"
});
$newDiv.find(".ui-icon").removeClass("ui-icon ui-icon-gripsmall-diagonal-se");
}
$(".newly-added").on("click", function(e) {
$(".newly-added").removeClass("img-selected");
$(this).addClass("img-selected");
e.stopPropagation()
});
$(document).on("click", function(e) {
if ($(e.target).is(".newly-added") === false) {
$(".newly-added").removeClass("img-selected");
}
});
}
$(".user_submit").on("click",function(e){
e.preventDefault();
let html = $(".new-multiple").html();
let svg = `<?xml version="1.0" standalone="yes"?>
<svg xmlns="http://www.w3.org/2000/svg" width="400px" height="400px" viewBox="0 0 400 300">
<foreignObject width="400px" height="300px"
requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<html xmlns="http://www.w3.org/1999/xhtml">
${html}
</html>
</foreignObject>
</svg>`;
$("body").append(svg);
});
});
.new-multiple {
width: 400px !important;
height: 400px !important;
background: white;
border: 2px solid red;
overflow: hidden;
}
.img-div {
width: 200px;
height: 200px;
}
.newly-added {
width: 100%;
height: 100%;
}
.img-selected {
box-shadow: 1px 2px 6px 6px rgb(206, 206, 206);
border: 2px solid rgb(145, 44, 94);
}
/*
.ui-resizable-handle.ui-resizable-se.ui-icon.ui-icon-gripsmall-diagonal-se {
background-color: white;
border: 1px solid tomato;
}
*/
.ui-resizable-handle {
border: 0;
border-radius: 50%;
background-color: #00CCff;
width: 14px;
height: 14px;
}
.ui-resizable-nw {
top: -7px;
left: -7px;
}
.ui-resizable-ne {
top: -7px;
right: -7px;
}
.ui-resizable-e {
top: calc(50% - 7px);
right: -7px;
}
.ui-resizable-w {
top: calc(50% - 7px);
left: -7px;
}
.ui-resizable-sw {
bottom: -7px;
left: -7px;
}
.ui-resizable-se {
right: -7px;
bottom: -7px;
}
.ui-resizable-se.ui-icon {
display: none;
}
.ui-rotatable-handle {
background-size: 14px;
background-repeat: no-repeat;
background-position: center;
border: 0;
border-radius: 50%;
background-color: #00CCff;
margin-left: calc(50% - 9px);
bottom: -5px;
width: 18px;
height: 18px;
}
<link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet"/>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<link href="https://cdn.jsdelivr.net/gh/godswearhats/jquery-ui-rotatable@1.1/jquery.ui.rotatable.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/gh/godswearhats/jquery-ui-rotatable@1.1/jquery.ui.rotatable.min.js"></script>
<script src="https://html2canvas.hertzen.com/build/html2canvas.js"></script>
<form method="post" action="">
<input name="user_file[]" id="user_file" style="position: relative;overflow: hidden" multiple="" type="file">
<div class="new-multiple"></div>
<input type="submit" name="submit" class="user_submit" value="submit" />
</form>