Converting image to jpg Angular 4 - image

I am using Angular 4 with TypeScript for a web application. I am allowing users to upload a thumbnail profile photo from their device as either a png, jpeg, or jpg, and I want to convert that photo to a jpg on the frontend. I am looking for some way to do this, as the file type is readonly.
The reason that I am doing this is so that when users load the profile page, they don't have to download large images so the page is quick. I think that converting to a jpg might be the best bet because when tested with a sample image, a png of an image was 35.4KB while a converted jpg of the same image was 6.7KB. If there is a better solution, I would love to hear it!
Thank you in advance!

I just wrote some code like your requirements, here is what I did:
load a local image by FileReader and add a listener to its onload event
in the onload listener, create an "Image" object by new Image(), and set "src" attribute by the loaded image "src" (Data URL format)
create a "Canvas" element, and draw the image on this canvas
use Canvas.toDataURL() to fetch the converted image data (in base64)
post the image data to server
After you draw an image to canvas, call Canvas.toDataURL() will get the canvas content in Data URL string, please note that it's the canvas data not original image data, for example, if image size is 100 x 100 and canvas size is 50 x 50, you'll get an image in 50 x 50 pixel with this function, so if you want a full size image, you need to resize the canvas to the certain size.
this function has two parameters:
canvas.toDataURL(type, encoderOptions);
type - A DOMString indicating the image format. The default format type is image/png. in your code, set to "image/jpeg" in your case
encoderOptions - A Number between 0 and 1 indicating image quality if the requested type is image/jpeg or image/webp.
Here is my "preview and upload" function write in TypesScript for reference:
preview(input: HTMLInputElement) {
if (input.files.length) {
let reader = new FileReader();
reader.onload = (e) => {
if (!this.img) {
this.img = new Image();
}
this.img.src = (e.target as any).result;
this.img.onload = () => {
// omit code of setting 'dx', 'dy', 'width', 'height'
let ctx = <CanvasRenderingContext2D>this.canvas.nativeElement.getContext('2d');
ctx.drawImage(this.img, dx, dy, width, height);
let dataUrl = (<HTMLCanvasElement>this.canvas.nativeElement).toDataURL('image/jpeg', 0.7);
this.uploadService.upload(dataUrl).then((resp: any) => {
if (resp.key) {
this.asset.image = resp.key;
}
});
};
}
reader.readAsDataURL(input.files[0]);
}
}
I omitted some variables: dx, dx, width, height in the above code, I use these variables to adjust image position (for clipping purpose).
This is JavaScript example:
function _elm(id) {
return document.getElementById(id);
}
_elm('fileInput').onchange= function(event) {
if (event.target.files.length) {
var fileReader = new FileReader();
fileReader.onload = function(event) {
var img = new Image();
img.src = event.target.result;
_elm('sizeRaw').innerText = '+ data-url size ' + event.target.result.length;
img.onload = function() {
var canvas = _elm('canvas');
var context = canvas.getContext('2d');
context.drawImage(img, 0, 0, 200, 200);
var dataUrl = canvas.toDataURL('image/jpeg', 0.5);
_elm('output').innerText = dataUrl;
_elm('sizeNew').innerText = '+ data-url size ' + dataUrl.length;
}
};
fileReader.readAsDataURL(event.target.files[0]);
}
};
#canvas {
border: 1px solid blue;
}
#output {
word-break: break-all;
}
<h3>Input file <span id="sizeRaw"></span>: </h3>
<input id="fileInput" type="file" accept="image/*">
<h3>Canvas</h3>
<div>
<canvas id="canvas" width="200" height="200"></canvas>
</div>
<h3>Output <span id="sizeNew"></span>: </h3>
<div id="output">
</div>

Related

Jcrop Image Intervention Laravel 5

i am using Image Intervention and jcrop to crop and resize image in laravel, but having problems. The issue which i think is that , when i save the file width and height is correct according to the selection, but the x & y is not correct, I am completely lost here, dont know what to do , Please help.
I have made but cropping area is wrong.
here is the code example.
// convert bytes into friendly format
function bytesToSize(bytes) {
var sizes = ['Bytes', 'KB', 'MB'];
if (bytes == 0) return 'n/a';
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i];
}
// check for selected crop region
function checkForm() {
if (parseInt($('#w').val())) return true;
$('.setting-image-error').html('Select area').show();
return false;
}
// update info by cropping (onChange and onSelect events handler)
function updateInfo(e) {
$('#x1').val(e.x);
$('#y1').val(e.y);
$('#x2').val(e.x2);
$('#y2').val(e.y2);
$('#w').val(e.w);
$('#h').val(e.h);
}
// clear info by cropping (onRelease event handler)
function clearInfo() {
$('#w').val('');
$('#h').val('');
}
// Create variables (in this scope) to hold the Jcrop API and image size
var jcrop_api, boundx, boundy;
function fileSelectHandler() {
// get selected file
var oFile = $('#picture')[0].files[0];
// hide all errors
$('.setting-image-error').hide();
// check for image type (jpg and png are allowed)
var rFilter = /^(image\/jpeg|image\/png)$/i;
if (!rFilter.test(oFile.type)) {
$('.setting-image-error').html('Select only jpg, png').show();
return;
}
// check for file size
if (oFile.size > 10000000) {
$('.setting-image-error').html('Too Big file ').show();
return;
}
// preview element
var oImage = document.getElementById('preview');
// prepare HTML5 FileReader
var oReader = new FileReader();
oReader.onload = function (e) {
// e.target.result contains the DataURL which we can use as a source of the image
oImage.src = e.target.result;
oImage.onload = function () { // onload event handler
// display step 2
$('.setting-image-cropping-stage').fadeIn(500);
// display some basic image info
var sResultFileSize = bytesToSize(oFile.size);
$('#filesize').val(sResultFileSize);
$('#filetype').val(oFile.type);
$('#filedim').val(oImage.naturalWidth + ' x ' + oImage.naturalHeight);
// destroy Jcrop api if already initialized
if (typeof jcrop_api !== 'undefined') {
jcrop_api.destroy();
jcrop_api = null;
$('#preview').width(oImage.naturalWidth);
$('#preview').height(oImage.naturalHeight);
}
//Scroll the page to the cropping image div
$("html, body").animate({scrollTop: $(document).height()}, "slow");
// initialize Jcrop
$('#preview').Jcrop({
minSize: [32, 32], // min crop size
aspectRatio: 1, // keep aspect ratio 1:1
bgFade: true, // use fade effect
bgOpacity: .3, // fade opacity
onChange: updateInfo,
onSelect: updateInfo,
onRelease: clearInfo
}, function () {
// use the Jcrop API to get the real image size
var bounds = this.getBounds();
boundx = bounds[0];
boundy = bounds[1];
// Store the Jcrop API in the jcrop_api variable
jcrop_api = this;
});
}
}
// read selected file as DataURL
oReader.readAsDataURL(oFile);
}
and Controller code is below.
public function image_crop_resize_and_upload($file, $user_id,$width,$height,$x1,$y1)
{
$filename = $user_id . '.jpg';// image file name
$target_path = User::PICTURE_PATH . $filename;//path where to create picture with new dimensions
$img = \Image::make($file->getRealPath());// create the instance of image with the real path of the image
$filetype = $img->mime();//get file mime type
$filetypes = ['image/jpg', 'image/jpeg', 'image/png']; //allowed files types
//if file exists in the target folder, system will delete the file and next step will create new one.
if (File::exists($target_path)) {
File::delete($target_path);
}
if (in_array($filetype, $filetypes, true)) {
$img->crop($width, $height,$x1,$y1);
$img->encode('jpg', 85);
$img->resize($width,$height);
$img->save('uploads/' . $user_id . '.jpg');
return true;
} else {
return false;
}
}
When i have the file the file width and height is correct, but the selection area, x & y is not correct.
Yes , I have got the answer. The problem is very simple the x and y position of image are wrong because it is inside a bootstrap responsive class. the proper solution is just to remove the class . So the image actually dimension will be shown. and than select the are. Thats it.
<img id="preview" name="preview" class="img-responsive"/>
this should be
<img id="preview" name="preview"/>

Canvas ctx.drawImage is not working with a transparent PNG

ctx.drawImage() is not working when I use a transparent PNG, but does work when I use a regular PNG.
var context = document.getElementById("canvas").getContext('2d');
....
function draw(img, x, y){
context.drawImage(img, x, y);
}
//actulaly there is loop here, but for simplicity I put only this.
var img = new Image();
img.src = "images/a.png";
img.onload = draw(img, 10, 10);
If I use a regular PNG image it works, but with a PNG with transparency that has the background deleted, it is not working.
Do you guys have any idea why? Thank you.
img.onload takes a function reference rather than a function call.
So do this:
img.onload=function(){draw(img,10,10);}
If you need to load many images, here is an image preloader that fully loads all images before calling the start() function:
// image loader
// put the paths to your images in imageURLs[]
var imageURLs=[];
// push all your image urls!
imageURLs.push("");
imageURLs.push("");
// the loaded images will be placed in images[]
var imgs=[];
var imagesOK=0;
loadAllImages(start);
function loadAllImages(callback){
for (var i=0; i<imageURLs.length; i++) {
var img = new Image();
imgs.push(img);
img.onload = function(){
imagesOK++;
if (imagesOK>=imageURLs.length ) {
callback();
}
};
img.onerror=function(){alert("image load failed");}
img.crossOrigin="anonymous";
img.src = imageURLs[i];
}
}
function start(){
// the imgs[] array now holds fully loaded images
// the imgs[] are in the same order as imageURLs[]
}

Dynamic Image Loading in processing

In a processing drawing loop, I have an algorithm that uses face detection to trigger a picture being taken. However so far I cannot get the image to display in my drawing loop. Does anyone know how to halt a drawing loop until an image is loaded and displayed? Here's the section of my drawing loop:
if (faces.length > 0) {
save("Source/face.jpg");
PImage img = loadImage("Source/face.jpg");
image(img,0,0);
} else {
println("not seeing anything");
}
Obviously this isn't working, how do I dynamically load and display images in processing?
I have this function in javascript
loadimage: function(image, i) {
var img = new Image();
$(img).load(function () {
$(this).hide();
$('#loader'+i).append(this);
$('#loading'+i).removeClass('image-container-loading');
$(this).fadeIn();
}).error(function () {
// notify the user that the image could not be loaded
}).attr('src',image).css('width','50px').css('height','50px').css('position','absolute');
}
Called:
self.loadimage('http://www.test.com/files/images/hi.jpg,ide);
html:
<li class='promotion'><span class='image-container' id='loader"+ide+"'>
<span class='units'></span>
<span style='border: solid 0px' class='image-container-loading' id='loading'>
</span></li>

How do I convert blob to imagedata?

I want to stream an image to webpage via websocket. the data is in RGBA. how do I change the blog into image data?
this is my current code, it doesn't work and it will be slow. is there a direct way of assigning event.data to canvas' image data?
void onMessage(MessageEvent event)
{
print("received!");
var imgData = canvas.getImageData(0, 0, 100, 100);
var j = 0;
for (var i=0;i<imgData.data.length;i+=4)
{
imgData.data[i+0]=event.data[j];
imgData.data[i+1]=event.data[j+1];
imgData.data[i+2]=event.data[j+2];
imgData.data[i+3]=255;
j+=3;
}
canvas.putImageData(imgData,0,0);
}
On Firefox you can use the toBlob method. Put the image data on a temporany canvas and call toBlob method. Proof of concept example:
var canvas = document.createElement('canvas');
canvas.width = imageData.width;
canvas.height = imageData.width;
me._dstCanvas.getContext('2d').putImageData(a.dstImgData, 0, 0);
me._dstCanvas.toBlob(function(blob) {
blob// this is yout file
}, 'image/png', 1);
For more have a look at Moz Dev:
https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob

detecting "we have no imagery" of google maps street view static images

I'm generating street view static images like so:
https://maps.googleapis.com/maps/api/streetview?size=1080x400&location=%s&fov=90&heading=235&pitch=0&key=%s
If you visit that link you see an image that says, "Sorry, we have no imagery for this..."
Is there any way to detect this "sorry" state so that I can fall back to another image?
One quick solution would be to load the image file using xmlrpc and check that its md5sum is 30234b543d5438e0a0614bf07f1ebd25, or that its size is 1717 bytes (it's unlikely that another image can have exactly the same size), but that's not very robust since I have seen Google change the position of the text in the image. Though it's a very good start for a prototype.
You could go for image processing instead. Note that it's still not perfectly robust since Google could decide to change the looks of the image anytime. You'll have to decide whether it's worth it.
Anyway, here is how I would do it using jQuery:
load the image and open a 2D context for direct pxiel access (see this question for how to do it)
analyse the image:
sample groups of 2×2 pixels at random locations; I recommend at least 30 groups
a group of 2×2 pixels is good if all the pixels have the same value and their R/G/B values do not differ by more than 10% (ie. they're grey)
count the ratio of good pixel groups in the image
if there are more than 70% good pixel groups, then we are pretty sure this is the “no imagery” version: replace it with another image of your choice.
The reason I do not recommend testing directly for an RGB value is because JPEG decompression may have slightly different behaviours on different browsers.
this situation is already build in in the 3.0 version due
the boolean test status === streetviewStatus.Ok, here is a snippet from my situation solving
if (status === google.maps.StreetViewStatus.OK) {
var img = document.createElement("IMG");
img.src = 'http://maps.googleapis.com/maps/api/streetview?size=160x205&location='+ lat +','+ lng +'&sensor=false&key=AIzaSyC_OXsfB8-03ZXcslwOiN9EXSLZgwRy94s';
var oldImg = document.getElementById('streetViewImage');
document.getElementById('streetViewContainerShow').replaceChild(img, streetViewImage);
} else {
var img = document.createElement("IMG");
img.src = '../../images/ProfilnoProfilPicture.jpg';
img.height = 205;
img.width = 160;
var oldImg = document.getElementById('streetViewImage');
document.getElementById('streetViewContainerShow').replaceChild(img, streetViewImage);
}
As of 2016, you can use the new Street View Image Metadata API.
Now you just need the status field to know if a panorama is found.
Example requests:
https://maps.googleapis.com/maps/api/streetview/metadata?size=600x300&location=78.648401,14.194336&fov=90&heading=235&pitch=10&key=YOUR_API_KEY
{
"status" : "ZERO_RESULTS"
}
https://maps.googleapis.com/maps/api/streetview/metadata?size=600x300&location=eiffel%20tower,%20paris,%20france&heading=-45&pitch=42&fov=110&key=YOUR_API_KEY
{
...
"status" : "OK"
}
You can use the getPanoramaByLocation function (see http://code.google.com/apis/maps/documentation/javascript/services.html#StreetViewService).
try something like this:
function handleMapClick()
{
var ll= new google.maps.LatLng(latitude,longitude);
sv.getPanoramaByLocation(ll, 50, processSVData);
}
function processSVData(data, status) {
if (status==google.maps.StreetViewStatus.ZERO_RESULTS)
{
<DO SOMETHING>
}
}
Request a google street view image and if it has a specific file size it is a 'Not street view avaible'. I did the follwing:
var url = 'google street view url';
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.onload = function (e) {
if (this.status == 200) {
try {
var image = new Blob([this.response], {type: 'image/jpeg'});
if (image.size) {
if (url.indexOf('640x640') > -1 && image.size === 8410) {
// Not street view
}
if (url.indexOf('400x300') > -1 && image.size === 3946) {
// Not street view
}
}
} catch (err) {
// IE 9 doesn't support blob
}
}
};
xhr.send();
Another way is to load the image and then compare some pixels colors. The "no streetview" image from google is always the same. Here is how you would compare 2 pixels:
var url = STREETVIEWURL
var img = new Image();
// Add some info to prevent cross origin tainting
img.src = url + '?' + new Date().getTime();
img.setAttribute('crossOrigin', '');
img.crossOrigin = "Anonymous";
img.onload = function() {
var context = document.createElement('CANVAS').getContext('2d');
context.drawImage(img, 0, 0);
//load 2 pixels. I chose the first one and the 5th row
var data1 = context.getImageData(0, 0, 1, 1).data;
var data2 = context.getImageData(0, 5, 1, 1).data;
console.log(data1);
// google unknown image is this pixel color [228,227,223,255]
if(data1[0]==228 && data1[1]==227 && data1[2]==223 && data1[3]==255 &&
data2[0]==228 && data2[1]==227 && data2[2]==223 && data2[3]==255){
console.log("NO StreetView Available");
}else{
console.log("StreetView is Available");
}
};
Some potential issues:
I've seen some errors with CrossOrigin tainting. Also, if google changes the image returned this code will break.

Resources