image using cordova plugin looks horrible on canvas - html

i am using cordova for my ios app which captures the image
the code looks
navigator.camera.getPicture(onSuccessCamera, onFailureCamera, {
quality: 25,
destinationType: navigator.camera.DestinationType.DATA_URL,
correctOrientation: true,
allowEdit:false
});
function onSuccessCamera(imageURI) {
var imgData = "data:image/jpeg;base64," + imageURI;
uploadFile(imgData);
}
function uploadFile(file){
var c=document.getElementById("picture");
c.width = window.innerWidth-50;//offset to prevent image flowing out of frame
// window.alert(window.innerWidth+":"+ window.innerHeight);414:736
c.height = "330";//window.innerHeight;//this.height;
var ctx=c.getContext("2d");
var showImg = new Image();
showImg.onload = function(){
var ratio = 1;
if (this.height > c.height) {
ratio = c.height/this.height;
}
else if (this.width>c.width) {
ratio = c.width/this.width;
}
ctx.drawImage(this,0,0, this.width*ratio, this.height*ratio);
// window.alert(c.width + ':' + c.height);
};
showImg.src = file;
}
i dont know why the image looks so horrible

It's because of the retina screen.
Make the height and width of the canvas to be the double, but then style it to be half pixels
c.width = (window.innerWidth-50)*2;//offset to prevent image flowing out of frame
c.height = 330*2;//window.innerHeight;//this.height;
c.style.width = (c.width/2)+"px";
c.style.height = (c.height/2)+"px";
Also, you can consider using a higher value on quality camera option.

Related

HTML5 scale canvas to fit page but keep canvas image at specific size

I am creating specific size image of 1200W x 300H and when its done I pass the image back to my server. I have all that working.
However, when the image is created, that 1200x300 size blows off the page for many users - especially on a mobile device. Is there any method I can use that can create the image at the specific 1200x300 but then visually display the image on a smaller scale to fit the screen?
Currently the best I am able to do is use a DIV with overflow:hidden to keep the DIV correctly sized on the page, but that doesn't scale the actual image down. In fact the image is mostly off centered only seeing the left part of the image on the screen.
<div style="overflow:hidden;" >
<canvas id="canvas" width="1200" height="300">
Your browser does not support Canvas.
</canvas>
</div>
If I shrink the canvas to fit the page, then the created image is the smaller size and not the size I need passed back to the server.
Is it possible to do this?
============= UPDATE ================
<div style="overflow:hidden;" >
<canvas id="displayCanvas" width="1200" height="300">
Your browser does not support Canvas.
</canvas>
<canvas id="realCanvas" width="1200" height="300">
Your browser does not support Canvas.
</canvas>
</div>
#CSS
#realCanvas {
width:100vw;
height: 25vw ;
}
#JS
function buildBanner () {
Debugger.log("Drawing Canvas");
if(!canvasSupport()) {
return;
}
var wCanvas = 1200 ;
var hCanvas = 300 ;
var wImg = 400 ;
var hImg = 100 ;
var hRatio = wCanvas / wImg ;
var vRatio = hCanvas / hImg ;
var ratio = Math.min ( hRatio, vRatio );
var centerShift_x = ( wCanvas - wImg*ratio ) / 2;
var centerShift_y = ( hCanvas - hImg*ratio ) / 2;
var displayCanvas = document.getElementById('displayCanvas') ;
var displayContext = displayCanvas.getContext('2d');
var realCanvas = document.getElementById('realCanvas');
var realContext = realCanvas.getContext('2d');
var text1 = document.getElementById('textType1') ;
var text2 = document.getElementById('textType2') ;
if (text1.checked) {
var bannerText = document.getElementById('cVendor').value ;
console.log("Text1: "+ bannerText) ;
} else if (text2.checked) {
var bannerText = document.getElementById('cVendorName').value ;
console.log("Text2: "+ bannerText) ;
}
var textStrokeColor = "#000000";
var textBaseline = "middle";
var textAlign = "center";
// This is the event handler for listening for a key up event in the text box form
// It will call the textBoxChanged function to update the text in the canvas
var fontSize = document.getElementById("fontSize").value;
var fontFaceSelect = document.getElementById("fontFace");
var fontFace = fontFaceSelect.options[fontFaceSelect.selectedIndex].value ;
var fontWeightSelect = document.getElementById("fontWeight");
var fontWeight = fontWeightSelect.options[fontWeightSelect.selectedIndex].value ;
var fontStyleSelect = document.getElementById("fontStyle");
var fontStyle = fontStyleSelect.options[fontStyleSelect.selectedIndex].value ;
var fillTypeSelect = document.getElementById("fillType");
var fillType = fillTypeSelect.options[fillTypeSelect.selectedIndex].value ;
var strokeTypeSelect = document.getElementById("strokeType");
var strokeType = strokeTypeSelect.options[strokeTypeSelect.selectedIndex].value ;
var textFillColor = document.getElementById("textFillColor").value ;
var bgFillColor = document.getElementById("bgFillColor").value ;
var imageData = document.getElementById("createImageData");
realContext = drawScreen(realContext,wCanvas,hCanvas,4);
displayContext = drawScreen(displayContext,wImg,hImg,1) ;
var imageDataDisplay = document.getElementById("imageDataDisplay");
imageDataDisplay.value = realCanvas.toDataURL();
function drawScreen(thisContext,x,y,xSize) {
thisContext.clearRect(0, 0, x, y);
var metrics = thisContext.measureText(bannerText);
var textWidth = metrics.width;
var xPosition = x / 2
var yPosition = y / 2;
// Draws the Text Box
thisContext.globalAlpha = 1.0;
thisContext.fillStyle = bgFillColor ;
thisContext.fillRect(0,0,x,y);
// Draws the actual text
var xFontSize = fontSize * xSize ;
thisContext.font = fontWeight + " " + fontStyle + " " + xFontSize + "px " + fontFace;
thisContext.textBaseline = textBaseline;
thisContext.textAlign = textAlign;
var tempColor;
switch(fillType) {
case "colorFill":
Debugger.log("Color Fill");
tempColor = textFillColor;
break;
case "linearGradient":
Debugger.log("Linear Gradient");
var linGradient = thisContext.createLinearGradient(xPosition-textWidth/2, yPosition, xPosition+textWidth/2, yPosition);
linGradient.addColorStop(0, textFillColor);
tempColor = linGradient;
break;
case "radialGradient":
Debugger.log("Radial Gradient");
var radGradient = thisContext.createRadialGradient(xPosition, yPosition, 1, xPosition, yPosition, textWidth/2);
radGradient.addColorStop(0, textFillColor);
tempColor = radGradient;
break;
}
switch(strokeType) {
case "fill":
thisContext.fillStyle = tempColor;
thisContext.fillText(bannerText, xPosition, yPosition);
break;
case "stroke":
thisContext.strokeStyle = textStrokeColor;
thisContext.strokeText(bannerText, xPosition, yPosition);
break;
case "both":
thisContext.fillStyle = tempColor;
thisContext.fillText(bannerText, xPosition, yPosition);
thisContext.strokeStyle = textStrokeColor;
thisContext.strokeText(bannerText, xPosition, yPosition);
break;
}
return thisContext ;
}
}
This could be done by listening to a resize event and manipulating the CSS width & height properties accordingly but there's an easier way if your <canvas> element is always the same size.
To understand what's going on you need to know that the width & height set via the canvas' elements own attributes is the 'real' resolution of the canvas. What size is actually rendered on screen can be controlled by the CSS width & height properties.
What we want to do is scale the canvas to fill the browser's available vertical viewport and scale it's height while maintaining the canvas' original aspect ratio.
First we need to calculate it's aspect ratio: 300 / 1200 = 0.25 which means it's height is 1/4 of it's width. In plain english we want to make the canvas width 100% the viewport's width and it's height 25% the viewport's width.
Luckily this transfers directly to the CSS vw unit. e.g. 100vw==100% viewport width.
So all you have to do is setting the canvas CSS width to 100vw and it's height to 25vw.
Here's an example:
let image = new Image();
let canvas = document.getElementById('canvas');
let context = canvas.getContext('2d');
image.crossOrigin = 'anonymous';
image.onload = (e) => {
context.drawImage(e.target, 0, 0, canvas.width, canvas.height);
}
image.src = 'https://picsum.photos/id/10/1200/300';
#canvas {
background-color: black;
width: 100vw;
height: 25vw;
}
<div style="overflow:hidden;">
<canvas id="canvas" width="1200" height="300">
Your browser does not support Canvas.
</canvas>
</div>

Selenium - How to debug code in driver.ExecuteScript String

In my vb.net Project with Selenium, I have a set of JS statements to convert html to canvas to image and then download to file. The code so far is as follows:-
driver.ExecuteScript("
var url = '" + str + "';
var pages = [],
heights = [],
width = 0,
height = 0,
currentPage = 1;
var scale = 1.5;
PDFJS.disableWorker = true; // due to CORS
PDFJS.getDocument(url).then(function(pdf) {
pdf.getPage(currentPage).then(function(page) {
console.log('Printing ' + currentPage);
var viewport = page.getViewport({
scale: scale,
});
var canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d');
var renderContext = {
canvasContext: ctx,
viewport: viewport
};
canvas.height = viewport.height;
canvas.width = viewport.width;
page.render(renderContext).then(function() {
pages.push(ctx.getImageData(0, 0, canvas.width, canvas.height));
heights.push(height);
height += canvas.height;
if (width < canvas.width) width = canvas.width;
var canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d');
canvas.width = width;
canvas.height = height;
for (var i = 0; i < pages.length; i++)
ctx.putImageData(pages[i], 0, heights[i]);
document.body.appendChild(canvas);
var element = document.createElement('a');
element.setAttribute('href', document.getElementById('rakCanvas').toDataURL('image/png'));
element.setAttribute('download', '" + fileName + "');
console.log('Raky ========>' + url);
element.style.display = 'block';
document.body.appendChild(element);
element.click();
//document.body.removeChild(element);
return 'Done Rak';
});
});
});
Using jsfiddle, I found the JS code to be without any syntax errors. There are no errors during compiling and execution. And there is no file downloaded. To figure out the problem, I am looking for a way to monitor execution of each statement of above js code.
Alternatively, if there is a code chuck that could help in just converting the HTML canvas to Image to be downloaded as a file.

Pics are sideways on iOS (using HTML Input)

I have this HTML code to allow a user to upload a picture on my hybrid iOS app:
<input type="file" accept="image/*">
When selected, the web view gives the user 2 options.
1. Take a new picture 2. Choose an existing picture.
When the users selects 'Choose an existing picture' everything works fine. But if the user selects 'Take a new picture', when it uploads to Firebase Storage, it somehow uploads sideways.
How can I fix this? This is not ideal, but is there a way to only allow an 'existing picture' option?
Here is my code that processes the image and shows it in a <img>.
function fileUploaded(files) {
var file = files[0];
var reader = new FileReader();
reader.onload = function (e) {
var img = document.createElement("img");
img.src = e.target.result;
img.onload = function () {
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
canvas.width = 200;
canvas.height = 200;
var xStart = 0;
var yStart = 0;
var newHeight = 0;
var newWidth = 0;
var aspectRadio = img.height / img.width;
if (img.height < img.width) {
//horizontal
aspectRadio = img.width / img.height;
newHeight = 200;
newWidth = aspectRadio * 200;
xStart = -(newWidth - 200) / 2;
} else {
//vertical
newWidth = 200;
newHeight = aspectRadio * 200;
yStart = -(newHeight - 200) / 2;
}
var ctx = canvas.getContext("2d");
ctx.drawImage(img, xStart, yStart, newWidth, newHeight);
dataurl = canvas.toDataURL(file.type);
document.getElementById('img_element').src = dataurl;
}
}
reader.readAsDataURL(file);
}
Are you displaying the image before uploading? You might want to do that to see if it is already rotated by iOS (similar issue here). As for a fix, this might be what you will want to use.
Edit:
My previous response was somewhat vague. To be more precise, you're having a problem with the EXIF orientation. Here is a JSFiddle that will show you the orientation of the image and how it looks as an <img/> vs. as a <canvas>. The fix previously mentioned is still the path you will probably want to take. You should be able to use the library to correctly orient the image in a <canvas>. Here is an example of that library in use. Hope this helps!

Canvas Zoom out Image Quality Loss

I written a code for zooming and zoom-out the canvas image but if try to zoom the image more than once the quality of image is changing.
This is my code using canvas2image plugin i am converting canvas to normal image.
Can any body please suggest me is there any thing wrong way i am doing.
function imgZoom(operation) {
var zoomImageObj = document.getElementById("originalImage");
var zoomedCanvas = $("#zoomCanvasPreview")[0];
var zoomedContext = zoomedCanvas.getContext("2d");
var selectedImgWidth = $('#originalImage').width();
var selectedImgHeight = $('#originalImage').height();
$("#zoomCanvasPreview").attr("height", selectedImgHeight);
$("#zoomCanvasPreview").attr("width", selectedImgWidth);
var previewHeight = $("#zoomCanvasPreview").height();
var previewWidth = $("#zoomCanvasPreview").width();
var zoomFactor = $("#zoomFactor option:selected").val();
// Making the zoomfactor string as float point then parsing for addition
// zoomFactor values if user selected 5%(0.05), 10%(0.1), 15(0.15) &etc
var zoomPercent = 1 + parseFloat(zoomFactor);
if(operation == 'zoomIn') {
newZoomWidth = Math.round(previewWidth * zoomPercent) ;
newZoomHeight = Math.round(previewHeight * zoomPercent) ;
} else if(operation == 'zoomOut'){
newZoomWidth = Math.round( previewWidth / zoomPercent );
newZoomHeight = Math.round( previewHeight / zoomPercent );
}
if( (newZoomWidth >= 0) && (newZoomHeight >= 0) )
{
$("#zoomCanvasPreview").attr("width", newZoomWidth);
$("#zoomCanvasPreview").attr("height", newZoomHeight);
// Drawing the image to canvas
zoomedContext.drawImage(zoomImageObj, 0, 0, imgWidth, imgHeight, 0, 0, newZoomWidth, newZoomHeight );
//return canvas.toDataURL("image/png");
var zoomedCanvas = $("#zoomCanvasPreview")[0];
oImgConvertExt = Canvas2Image.saveAsPNG(zoomedCanvas, true);
$("#originalImage").attr("src", oImgConvertExt.src);
$("#originalImage").attr("style", "display: none; visibility: hidden; width: "+newZoomWidth+"px; height: "+newZoomHeight+"px;");
} else {
alert("Reached maximum zoom out limit");
}
}
Image quality will not get changed If you use Images of format .SVG
these image will never get distorted even if you zoom IN or zoom OUT
There is no way around quality loss if you use canvas.drawImage().
Just zoom by changing the CSS width and height values. There won't be any quality loss then.
It is also a lot simpler to code...

HTML5 canvas: is there a way to resize image with "nearest neighbour" resampling?

I have some JS that makes some manipulations with images. I want to have pixelart-like graphics, so I had to enlarge original images in graphics editor.
But I think it'd be good idea to make all the manipulations with the small image and then enlarge it with html5 functionality. This will save bunch of processing time (because now my demo (warning: domain-name may cause some issues at work etc) loads extremely long in Firefox, for example).
But when I try to resize the image, it gets resampled bicubically. How to make it resize image without resampling? Is there any crossbrowser solution?
image-rendering: -webkit-optimize-contrast; /* webkit */
image-rendering: -moz-crisp-edges /* Firefox */
http://phrogz.net/tmp/canvas_image_zoom.html can provide a fallback case using canvas and getImageData. In short:
// Create an offscreen canvas, draw an image to it, and fetch the pixels
var offtx = document.createElement('canvas').getContext('2d');
offtx.drawImage(img1,0,0);
var imgData = offtx.getImageData(0,0,img1.width,img1.height).data;
// Draw the zoomed-up pixels to a different canvas context
for (var x=0;x<img1.width;++x){
for (var y=0;y<img1.height;++y){
// Find the starting index in the one-dimensional image data
var i = (y*img1.width + x)*4;
var r = imgData[i ];
var g = imgData[i+1];
var b = imgData[i+2];
var a = imgData[i+3];
ctx2.fillStyle = "rgba("+r+","+g+","+b+","+(a/255)+")";
ctx2.fillRect(x*zoom,y*zoom,zoom,zoom);
}
}
More: MDN docs on image-rendering
I wrote a NN resizing script a while ago using ImageData (around line 1794)
https://github.com/arahaya/ImageFilters.js/blob/master/imagefilters.js
You can see a demo here
http://www.arahaya.com/imagefilters/
unfortunately the builtin resizing should be slightly faster.
This CSS on the canvas element works:
image-rendering: pixelated;
This works in Chrome 93, as of September 2021.
You can simply set context.imageSmoothingEnabled to false. This will make everything drawn with context.drawImage() resize using nearest neighbor.
// the canvas to resize
const canvas = document.createElement("canvas");
// the canvas to output to
const canvas2 = document.createElement("canvas");
const context2 = canvas2.getContext("2d");
// disable image smoothing
context2.imageSmoothingEnabled = false;
// draw image from the canvas
context2.drawImage(canvas, 0, 0, canvas2.width, canvas2.height);
This has better support than using image-rendering: pixelated.
I'll echo what others have said and tell you it's not a built-in function. After running into the same issue, I've made one below.
It uses fillRect() instead of looping through each pixel and painting it. Everything is commented to help you better understand how it works.
//img is the original image, scale is a multiplier. It returns the resized image.
function Resize_Nearest_Neighbour( img, scale ){
//make shortcuts for image width and height
var w = img.width;
var h = img.height;
//---------------------------------------------------------------
//draw the original image to a new canvas
//---------------------------------------------------------------
//set up the canvas
var c = document.createElement("CANVAS");
var ctx = c.getContext("2d");
//disable antialiasing on the canvas
ctx.imageSmoothingEnabled = false;
//size the canvas to match the input image
c.width = w;
c.height = h;
//draw the input image
ctx.drawImage( img, 0, 0 );
//get the input image as image data
var inputImg = ctx.getImageData(0,0,w,h);
//get the data array from the canvas image data
var data = inputImg.data;
//---------------------------------------------------------------
//resize the canvas to our bigger output image
//---------------------------------------------------------------
c.width = w * scale;
c.height = h * scale;
//---------------------------------------------------------------
//loop through all the data, painting each pixel larger
//---------------------------------------------------------------
for ( var i = 0; i < data.length; i+=4 ){
//find the colour of this particular pixel
var colour = "#";
//---------------------------------------------------------------
//convert the RGB numbers into a hex string. i.e. [255, 10, 100]
//into "FF0A64"
//---------------------------------------------------------------
function _Dex_To_Hex( number ){
var out = number.toString(16);
if ( out.length < 2 ){
out = "0" + out;
}
return out;
}
for ( var colourIndex = 0; colourIndex < 3; colourIndex++ ){
colour += _Dex_To_Hex( data[ i+colourIndex ] );
}
//set the fill colour
ctx.fillStyle = colour;
//---------------------------------------------------------------
//convert the index in the data array to x and y coordinates
//---------------------------------------------------------------
var index = i/4;
var x = index % w;
//~~ is a faster way to do 'Math.floor'
var y = ~~( index / w );
//---------------------------------------------------------------
//draw an enlarged rectangle on the enlarged canvas
//---------------------------------------------------------------
ctx.fillRect( x*scale, y*scale, scale, scale );
}
//get the output image from the canvas
var output = c.toDataURL("image/png");
//returns image data that can be plugged into an img tag's src
return output;
}
Below is an example of it in use.
Your image would appear in the HTML like this:
<img id="pixel-image" src="" data-src="pixel-image.png"/>
The data-src tag contains the URL for the image you want to enlarge. This is a custom data tag. The code below will take the image URL from the data tag and put it through the resizing function, returning a larger image (30x the original size) which then gets injected into the src attribute of the img tag.
Remember to put the function Resize_Nearest_Neighbour (above) into the <script> tag before you include the following.
function Load_Image( element ){
var source = element.getAttribute("data-src");
var img = new Image();
img.addEventListener("load", function(){
var bigImage = Resize_Nearest_Neighbour( this, 30 );
element.src = bigImage;
});
img.src = source;
}
Load_Image( document.getElementById("pixel-image") );
There is no built-in way. You have to do it yourself with getImageData.
Based on Paul Irish's comment:
function resizeBase64(base64, zoom) {
return new Promise(function(resolve, reject) {
var img = document.createElement("img");
// once image loaded, resize it
img.onload = function() {
// get image size
var imageWidth = img.width;
var imageHeight = img.height;
// create and draw image to our first offscreen canvas
var canvas1 = document.createElement("canvas");
canvas1.width = imageWidth;
canvas1.height = imageHeight;
var ctx1 = canvas1.getContext("2d");
ctx1.drawImage(this, 0, 0, imageWidth, imageHeight);
// get pixel data from first canvas
var imgData = ctx1.getImageData(0, 0, imageWidth, imageHeight).data;
// create second offscreen canvas at the zoomed size
var canvas2 = document.createElement("canvas");
canvas2.width = imageWidth * zoom;
canvas2.height = imageHeight * zoom;
var ctx2 = canvas2.getContext("2d");
// draw the zoomed-up pixels to a the second canvas
for (var x = 0; x < imageWidth; ++x) {
for (var y = 0; y < imageHeight; ++y) {
// find the starting index in the one-dimensional image data
var i = (y * imageWidth + x) * 4;
var r = imgData[i];
var g = imgData[i + 1];
var b = imgData[i + 2];
var a = imgData[i + 3];
ctx2.fillStyle = "rgba(" + r + "," + g + "," + b + "," + a / 255 + ")";
ctx2.fillRect(x * zoom, y * zoom, zoom, zoom);
}
}
// resolve promise with the zoomed base64 image data
var dataURI = canvas2.toDataURL();
resolve(dataURI);
};
img.onerror = function(error) {
reject(error);
};
// set the img soruce
img.src = base64;
});
}
resizeBase64(src, 4).then(function(zoomedSrc) {
console.log(zoomedSrc);
});
https://jsfiddle.net/djhyquon/69/