I've web app running. And it uses ajax upload. The issue is recently users are uploading too big images. So it's taking a bit more time. Users are complaining about that. So what I was thinking is this, 'If I somehow crop and resize the image via js and then send it to the server via ajax upload then the time will be reduced'. So is there any way to do that? Any idea for it?
A solution is to use modern ways like FileReader and Canvas (But this works only on the latest modern browsers).
http://caniuse.com/filereader
http://caniuse.com/canvas
In this example i show how to let the client resize an image before uploading by setting a max width & height mantaining aspect ratio.
In this example max widthHeight = 64;
your final image is c.toDataURL();
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script>
var h=function(e){
var fr=new FileReader();
fr.onload=function(e){
var img=new Image();
img.onload=function(){
var MAXWidthHeight=64;
var r=MAXWidthHeight/Math.max(this.width,this.height),
w=Math.round(this.width*r),
h=Math.round(this.height*r),
c=document.createElement("canvas");
c.width=w;c.height=h;
c.getContext("2d").drawImage(this,0,0,w,h);
this.src=c.toDataURL();
document.body.appendChild(this);
}
img.src=e.target.result;
}
fr.readAsDataURL(e.target.files[0]);
}
window.onload=function(){
document.getElementById('f').addEventListener('change',h,false);
}
</script>
</head>
<body>
<input type="file" id="f">
</body>
</html>
In the canvas part of the code you can also add a cropping function.
Edit as asked in the comments
c.toDataURL();
is the image base64_string you can store it in a hidden input,append to a new FormData() or wherever you want.
on the server
$data=explode(',',$base64_string);
$image=base64_decode($data[1]);
write to file
$f=fopen($fileName,"wb");
fwrite($f,$image);
fclose($f);
or
$gd=imagecreatefromstring($image);
you can also store the whole base64 image string in the database and always use that.
Related
I have spent my entire day trying to delete EXIF data from images with React. I want to do this for try to solve another problem, when user uploads an image with XMP data, apparently AWS WAF blocks it (I didn't have problems with another kind of data, I dind't tried everything tho, but I used an image with camera information and blabla and it worked just fine. Plus, I deleted XMP data from problematic images with a software, and WAF didn't blocked it anymore). So, I want to delete XMP data (author, creator tool, etc.) before send it to server.
I'm using react-dropzone for upload the images, and today I tried different libraries for achieve this, without success. With exifr and exif-js I can see all the EXIF information (including XMP) and specificcaly the data that is causing the error in the upload, but I didn't find a way to remove that from the picture. On the other hand, I used piexifjs and worked fine for delete information, but I couldn't find XMP data!! Just gps, EXIF with camera and picture settings, plus a couple of thing not of my interest. What can I do? I'm able to see this information with exif-js and exifr, but I just can delete things with pixiefjs in which I can't see xmp data.
I do not provide code because it is not an error as such, I want library recommendations or, if exists, a way to configure piexifjs for find this kind of data. exif-js and exifr are for reading, not for removing.
Thanks a lot.
Here would be a sample code of mine:
With a right on the image you should be able to download the image and there should be no exif data included. But I am unsure if there is a better way to do that.
document.getElementById('upload').onchange = function() {
const img = new Image();
img.src = URL.createObjectURL(this.files[0]);
img.onload = function() {
//canvas
const canvas = document.createElement('canvas');
canvas.width = this.width;
canvas.height = this.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(this, 0,0);
//image in html
newImg = document.getElementById('img');
newImg.src = canvas.toDataURL();
newImg.style.width = this.width;
newImg.style.height = this.height;
};
img.onerror = function() {console.error("The file is not an image")};
};
<!doctype html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<input type="file" id="upload">
<img id="img"></img>
<script src="script.js"></script>
</body>
</html>
I'm unsure if it couldn't be simpler, but you could create a canvas with the size of the image, load the image into it, and write the image data from the canvas to a new image file.
I am using wix and in order to customize any html you need to use an embed object which creates a sandboxed iframe on the site. I have a decent grasp of how this works and posting messages to it but what I am having difficulties with is generating a pdf into this iframe.
I have done some reading and I think I get the overall concept. While traditionally you would just set the source to some document on a server somewhere I am generating the content dynamically based on user action. So it looks like something like pdfkit and creating a blob is the way to go.
I think I am able to generate the pdf without issues as well as a blob url no problem
[![console image][1]][1]
I can manually open the console and get that URL and paste it in the browser and the document opens exactly how I expect it. However I can't get it to display normally in the browser.
I have tried setting the src of various elements = to the blob url without luck.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
blah
<script src="https://github.com/foliojs/pdfkit/releases/download/v0.11.0/pdfkit.standalone.js"></script>
<script src="https://github.com/devongovett/blob-stream/releases/download/v0.1.3/blob-stream.js">
</script>
</head>
<body>
<script>
const doc = new PDFDocument
const stream = doc.pipe(blobStream())
doc.fontSize(25).text('Testing document', 100, 80);
console.log(doc);
doc.end();
stream.on('finish', function() {
window.src = stream.toBlobURL('application/pdf');
const a = document.createElement('a');
a.href = stream.toBlobURL('application/pdf');
a.download = 'ShoppingList' || 'download';
console.log("download IS",a)
});
</script>
</body>
</html>
In addition to setting the window.src I have tried document.src iframe.src which returns an error.
displaying isn't strictly necessary but a download link would be. Is there some other way I can do this to get this data? I feel I am missing something very simple.
I have had to change the examples as given on [http://pdfkit.org/docs/getting_started.html][2] but I don't think this is any issue as the package is working as expected and the document is being created.
Edit:
I have made some progress on this but am getting stuck in downloading it. What I did was these 2 things.
<input type="button" id = "dload" onclick="location.href='';" value="Download Shopping List" />
document.getElementById("dload").onclick = function(){location.href = stream.toBlobURL('application/pdf')};
the pdf actually shows in the iframe as expected with the full capabilities of a pdf preview however the download doesn't work at all it just says failed - network error and the filetype is not a pdf which makes sense. Is there something else I can add to get this working?
Edit2: Tried one more thing that doesn't work very well since popups are mostly blocked
window.open(stream.toBlobURL('application/pdf'), '_blank');
this, while it technically works is really messy and is causing a number of problems. Also it works differently on mobile vs desktop. There has to be some simple way to just show a pdf but it seems to just result in more questions the more I search.
[1]: https://i.stack.imgur.com/le6o9.png
[2]: http://pdfkit.org/docs/getting_started.html
I have partially solved my question and it is good enough for what I need. Here is what I did.
<html>
<head>
<script src="https://github.com/foliojs/pdfkit/releases/download/v0.11.0/pdfkit.standalone.js"></script>
<script src="https://github.com/devongovett/blob-stream/releases/download/v0.1.3/blob-stream.js"></script>
<script type="text/javascript">
window.onmessage = (event) => {
if (event.data) {
// create a document and pipe to a blob
var doc = new PDFDocument();
var stream = doc.pipe(blobStream());
doc.font('Helvetica');
doc.fontSize(20);
doc.text('Some Text',200,20);
// end and display the document in the iframe to the right
doc.end();
stream.on('finish', function() {
const blob = stream.toBlob('application/pdf')
const a = document.createElement('a');
a.href = window.URL.createObjectURL(blob);
a.download = "YourFileName";
a.style.position = 'fixed';
a.target = '_blank';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
});
};
};
</script>
</head>
<body>
</body>
</html>
while I can't see the pdf using this method it does download correctly which was the more important piece. Technically I could combine the two but since the download button on the iframe doesn't work I think it would be confusing for someone having a separate button to actually download it. So I have a separate button outside the frame that triggers the "onmessage" it is a function of wix. This triggers all document generation and download.
Is it possible to get a dataUrl (or simply the SVG source code) of an SVG image which is not inline SVG, but an external SVG file on the same domain?
I had a look at https://github.com/sampumon/SVG.toDataURL, but it only works for inline SVG, not for external SVG files.
To be clear, I am not looking to convert the SVG image to a PNG and then get the PNG's dataUrl, I need to get at the actual SVG code.
The solution would need to be open source and work in most modern browsers.
Here's a minimal version of what I'm trying to do:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function getSvgDataUrl(imgID) {
// FIXME!!!
return dataUrl;
}
function doTheThing() {
result = getSvgDataUrl('foo');
console.write(result);
}
</script>
</head>
<body onload='doTheThing()'>
<img src='myImage.svg' id='foo'>
</body>
</html>
I think the obvious thing to do here is to put the SVG image on a canvas and then get a dataURL from the canvas, like this:
source = new Image();
source.src = 'myImage.svg';
source.onload = function(event){
c = document.getElementById('canvas');
ctx = c.getContext('2d');
ctx.drawImage(source,0,0,116,23);
data = c.toDataURL('image/svg', 1.0);
alert(data);
};
But this gives me a PNG dataURL, not SVG.
I also looked at XMLSerializer, which seemed promising, but I can't work out how to get at the internal SVG. Doing this:
svgImg = document.getElementById('foo');
s = new XMLSerializer();
console.log(s.serializeToString(svgImg));
Just gives the following console output:
<img xmlns="http://www.w3.org/1999/xhtml" src="myImage.svg" id="foo" />
Justin Taddei gave the answer: it's fetch. I get the feeling it was dumb of me not to know this but on the other hand I bet I'm not the only one to get confused by this, so here's the code that worked:
async function getText(file) {
let x = await fetch(file);
let y = await x.text();
console.log(y);
}
getText("myImage.svg");
There's info about fetch here: https://www.w3schools.com/js/js_api_fetch.asp
I want to asynchronously download image, so first user sees a low resolution image, and higher resolution version is downloaded in the background. I have tried the following.
<html>
<head>
<script>
window.addEventListener('load', function () {
var kuvaEl = document.getElementById('kuva');
var r_src = kuvaEl.getAttribute('r-src');
var a_src = kuvaEl.getAttribute('a-src');
kuvaEl.setAttribute('src', r_src);
kuvaEl.setAttribute('src', a_src);
});
</script>
</head>
<body>
<img id="kuva" src="http://www.viikonloppu.com/wp-content/uploads/2014/04/lotoflaughters.com_-619x428.jpg?c3bc1b"
a-src="https://www.manitowoccranes.com/~/media/Images/news/2014/Potain-China-hi-res.jpg"
r-src="http://fuzyll.com/images/2016/angel_oak_panorama.jpg" />
</body>
</html>
But the problem is r_src download is aborted when src is change second time. I want to download both of these images in parallel, and show the r_src first (only if it downloads faster than a_src), and when the *a_src *is ready, show the a_src.
Also, is it possible to download these a_src and r_src images to the browser cache before the src is actually changed? Ideally I would like the the src change to either retrieve the image from the cache or join the pending download for that url.
I can also use jQuery. IE7 must support the implementation.
You just need to use javascript or jquery and load two version of the same image. the first will be your low res, but you will download a high res inside an hidden img tag.
When the download is complete, you just hide / delete the low res image and show the high res.
This link show some test and few way to do it. And it should support ie7 Load a low-res background image first, then a high-res one
You can use interlaced progressive JPEG format.
This method is the preferred method for handling high quality images and has been implemented by so many websites.the idea is that the compression of the image is made in such away that the when you send the image the receiver gets the image in finer and finer detail has the sending of the data progressed.
if you dont want to use the abouve technique
Have the low quality image in the src of the image. once the whole page loaded successfully,change the low quality image with high quality image
<img id="target-image" src="low-quality.jpg" data-src="high-quality.jpg" />
$(window).load(function(){
var imgSrc = $('#target-image').data('src');
$('#target-image').attr('src',imgSrc);
});
You should put your low res as default src. Then use JS to download the high res version and on download completion, change image src.
Also, good practice is to use data-* for custom attributes
If your really want a parallel download, you should replace "load" event for the "DOMContentLoaded" event. However, this will extend the time your user has to wait until page is ready. Your should keep the load event to prioritize critical assets loading (scripts and stylesheets)
window.addEventListener('load', function() {
// get all images
let images = document.getElementsByClassName("toHighRes");
// for each images, do the background loading
for (let i = 0; i < images.length; i++) {
InitHighResLoading(images[i]);
}
});
function InitHighResLoading(image) {
let hrSrc = image.dataset["hr"];
let img = new Image();
img.onload = () => {
// callback when image is loaded
image.src = hrSrc;
}
// launch download
img.src = hrSrc;
}
img {
/* only for code snippet */
max-height: 300px;
}
<img class="toHighRes"
data-hr="https://www.manitowoccranes.com/~/media/Images/news/2014/Potain-China-hi-res.jpg"
src="http://fuzyll.com/images/2016/angel_oak_panorama.jpg" />
I've run into an error that a lot of people seem to have gotten in the past but the explanations are not clear to me. After using the .getImageData() method in my javascript to get the pixel data of a picture that I have stored on my computer and inputed into an img tag in my HTML webpage I get the SecurityError: DOM Exception 18.
I'm simply running an HTMl file in my browser and it is preventing me from getting this stuff done. I've read about making a proxy to get around it or something or hosting the image on my own domain. I don't exactly understand what this means or how to go about doing it. So, it'd be greatly appreciated if anyone could help. I'll input my code here and leave a link to the image as well.
http://i.imgur.com/8UzWlWX.png
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Test</title>
<script>
function putimg() {
var img = document.getElementById('img');
var can = document.getElementById('C');
var ctx = can.getContext('2d');
ctx.drawImage(img, 0, 0);
var position = [];
var imgdata = ctx.getImageData(0,0, img.width, img.height);
var data = imgdata.data;
for (var i = 0; i < data.length; i += 4) {
if (data[i] == 255) {
var vertical = Math.floor((data.indexOf(data[i]) / 4) / 400);
var horizontal = Math.floor((data.indexOf(data[i]) / 4) % 400);
position.push(horizontal, vertical);
}
}
}
ctx.putImageData(imgdata, 0, 0);
}
</script>
</head>
<body onload="putimg()">
<h1>Test</h1>
<img id="img" src="circle-image-alone.png" style="display:none"></img>
<canvas id="C" width="600" height="600"></canvas>
</body>
</html>
EDIT: the file is now in the same folder as the html file, but the same error flag appears
The problem is that this is breaking Same-origin policy. You need to either have imgur relax their Cross-origin sharing or host the image yourself.
If you are running the HTML file directly from the file system on your computer then you can just download the image to the same folder as your html file is in, and reference it like
<img id="img" src="8UzWlWX.png" style="display:none"></img>
Here are the hoops you need to jump through to make it work through a foreign origin like imgur: https://developer.mozilla.org/en-US/docs/HTML/CORS_Enabled_Image
As you've discovered, your browser considers even your local file system to be a different domain.
So you’re still violating cross-domain even if your image and .html are in the same local directory.
You need a CORS compliant way of loading your image.
Here’s how:
Open up an account on dropbox.com and host your image there.
Be sure to put your image in the “public” folder they set up for you.
They allow cross-domain downloading of their images from your “public” folder.
To get the URL of your dropbox image:
Right-click the image in your public folder and select “copy public link”.
This will put the url into your clipboard where you can paste it into your code.
Then use this code to download your image into the browser in a CORS compliant way:
// download an image from dropbox.com
// in a CORS compliant way
var img=new Image();
img.onload=function(){
ctx.drawImage(img, 0, 0);
}
img.crossOrigin="anonymous";
img.src="dropbox.com/yourDropboxAccount/yourImage.png";
The result is an image that you can fully examine/change/save with:
ctx.getImageData
ctx.putImageData
ctx.toDataURL.