The height of html elements doesn't change - javascript

I have a little JavaScript / TypeScript problem.
I have a file uploader for images and when the user uploads the image, it will be printed in a canvas. I want to change the canvas height after the image upload with JavaScript / TypeScript, but it doesn't changes.
function ZeichneBildInCanvas(): void {
canvasBild.height = bild.height;
canvasBild.width = bild.width;
canvasBild.getContext("2d").drawImage(bild, 0, 0);
canvasWrapper.setAttribute("height", canvasBild.style.height);
canvasWrapper.style.height = canvasBild.style.height;
ListeMitRechtecken[aktivesRechteck].canvas.width = bild.naturalWidth;
ListeMitRechtecken[aktivesRechteck].canvas.height = bild.naturalHeight;
ListeMitRechtecken[aktivesRechteck].context.drawImage(bild, 0, 0);
}
canvasWrapper and canvasBild don't change their heights. I tried it with .style.height and setAttributes, but I don't know why its not working.
Thank you for your support.

Related

can't really resize a canvas image

When learning about HTML canvas, I found this
Example: Dynamically change images
Basically dynamically change image from colors to gray-scale and vice versa using HTML Canvas. This example select img elements by class names ('grayscale') so to be able to apply this process to multiple images at once.
HTML
<img class="grayscale" src="myPicture.png" alt="Description of my picture" />
JavaScript
window.addEventListener('load', removeColors);
function showColorImg() {
this.style.display = 'none';
this.nextSibling.style.display = 'inline';
}
function showGrayImg() {
this.previousSibling.style.display = 'inline';
this.style.display = 'none';
}
function removeColors() {
var aImages = document.getElementsByClassName('grayscale'),
nImgsLen = aImages.length,
oCanvas = document.createElement('canvas'),
oCtx = oCanvas.getContext('2d');
for (var nWidth, nHeight, oImgData, oGrayImg, nPixel, aPix, nPixLen, nImgId = 0; nImgId < nImgsLen; nImgId++) {
oColorImg = aImages[nImgId];
nWidth = oColorImg.offsetWidth;
nHeight = oColorImg.offsetHeight;
oCanvas.width = nWidth;
oCanvas.height = nHeight;
oCtx.drawImage(oColorImg, 0, 0);
oImgData = oCtx.getImageData(0, 0, nWidth, nHeight);
aPix = oImgData.data;
nPixLen = aPix.length;
for (nPixel = 0; nPixel < nPixLen; nPixel += 4) {
aPix[nPixel + 2] = aPix[nPixel + 1] = aPix[nPixel] = (aPix[nPixel] + aPix[nPixel + 1] + aPix[nPixel + 2]) / 3;
}
oCtx.putImageData(oImgData, 0, 0);
oGrayImg = new Image();
oGrayImg.src = oCanvas.toDataURL();
oGrayImg.onmouseover = showColorImg;
oColorImg.onmouseout = showGrayImg;
oCtx.clearRect(0, 0, nWidth, nHeight);
oColorImg.style.display = "none";
oColorImg.parentNode.insertBefore(oGrayImg, oColorImg);
}
}
So far so good, the example works well except that when I use a big image, it makes the horizontal scroll bar appears (image width is 2400px)
so I've opted to precise the width of the image in the img tag as in here:
<img class="grayscale" src="mypic3.jpg" width="698px" alt="Description of my picture" />
So that also works for the original colorful image, but for the modified one (gray-scale one) it seems to map only a portion of the image to the designed width. so instead of getting this image:
I'm getting only this one :
Notice that this happens even if oCanvas.width = nWidth;initialize canvas width with the offset of the img tag (that is 689)
Other useless things that I've tried :
oCtx.drawImage(oColorImg, 0, 0);
oCanvas.style.backgroundSize="70%";
oCanvas.style.width="689px";
oCtx.putImageData(oImgData, 0, 0, 0, 0, 698, 410);
I appreciate any help
Edit: for the marks as duplicate
- For the one who marked the question as duplicate of question answered by just setting the canvas width, I specifically declared that it didn't work and the code above include setting canvas width.
- For the last four ones, which use the extended form of drawimage(), I did try it but it didn't work unless I set an explicit global CSS rule setting the img tag width. So I'm not sure what is the mechanics behind that. But in this case, if I don't put this rule the problem persist. So in my humble opinion, adding this particular information my help people stuck in a similar problem. as well as any explanation on why or how this works. thanks
The answer consists of two steps :
The first (as Kaiido suggests) is making use of the extended syntax of drawImage() taking the canvas.width,canvas.height parameters into account
oCtx.drawImage(oColorImg, 0, 0, nWidth, nHeight);
The second is that you make a CSS rule setting images width
(notice that if you don't, the problem persists even if the image seems to have the width set normally both in display and by extracting image width with Javascript. So one way to improve this answer is to explain this strange behavior)
img{
width: 689px;
}

Capturing a screenshot using window.scroll with high DPI settings

I'm using CefSharp 55.0.0 WinForms.
In order to take screenshots in CefSharp, I scroll the webpage using window.scroll within JavaScript and take an image of the current viewport. Once that has completed, it is then stitched back together again. This works fine for monitors that have their DPI setting set to 100%. However, when the monitor has a DPI greater than 100% screenshots do not work as expected and miss content.
Image 1 - 100%
Image 2 - 150%
Compare Image 1 to Image 2. While they both (practically) have the same width and height, Image 2 is missing a large portion of the content, compared to a perfect Image 1.
When DPI settings are above 100%, how can I correctly scroll and capture a screenshot that ensures I obtain everything it would if settings were at 100%?
Other details
The application has the correct DPI aware settings in theapp.manifest file and Cef.EnableHighDPISupport(); has been called in the Main method within Program.cs.
Screenshot Code (abridged)
int scrollHeight = GetDocHeight(); //some javascript that calcs the height of the document
int viewportHeight = ClientRectangle.Size.Height;
int viewportWidth = ClientRectangle.Size.Width;
int count = 0;
int pageLeft = scrollHeight;
bool atBottom = false;
while (!atBottom)
{
if (pageLeft > viewportHeight)
{
await GetBrowser().MainFrame.EvaluateScriptAsync("(function() { window.scroll(0," + (count * viewportHeight) + "); })();"); //I think the issue lies here
count++;
await PutTaskDelay();
using (Bitmap image = GetCurrentViewScreenshot())
{
//just a class that saves the partial images to a disk cache
cache.AddImage(count, image);
}
}
else
{
await GetBrowser().MainFrame.EvaluateScriptAsync("(function() { window.scrollBy(0," + pageLeft + "); })();");
atBottom = true;
count++;
await PutTaskDelay();
Rectangle cropRect = new Rectangle(new Point(0, viewportHeight - pageLeft), new Size(viewportWidth, pageLeft));
using (Bitmap src = GetCurrentViewScreenshot())
using (Bitmap target = new Bitmap(cropRect.Width, cropRect.Height))
using (Graphics g = Graphics.FromImage(target))
{
g.DrawImage(src, new Rectangle(0, 0, target.Width, target.Height), cropRect, GraphicsUnit.Pixel);
cache.AddImage(count, target);
}
}
pageLeft = pageLeft - viewportHeight;
}
Current View Screenshot Method
private Bitmap GetCurrentViewScreenshot()
{
int width, height;
width = ClientRectangle.Width;
height = ClientRectangle.Height;
using (Bitmap image = new Bitmap(width, height))
{
using (Graphics graphics = Graphics.FromImage(image))
{
Point p, upperLeftDestination;
Point upperLeftSource = new Point(0, 0);
p = new Point(0, 0);
upperLeftSource = PointToScreen(p);
upperLeftDestination = new Point(0, 0);
Size blockRegionSize = ClientRectangle.Size;
graphics.CopyFromScreen(upperLeftSource, upperLeftDestination, blockRegionSize);
}
return new Bitmap(image);
}
}
While not a perfect solution, I found a workaround that involves setting the force-device-scale-factor flag to 1 in CefSettings. It's not perfect because the browser isn't scaled on high DPI displays, potentially making text hard to read for users. However, it does fix my more pressing issue of missing data in screenshots.
CefSettings settings = new CefSettings();
settings.CefCommandLineArgs.Add("force-device-scale-factor", "1");
Cef.Initialize(settings);
This question is still open for better suggestions, if there are any. :-)

How do I get the MIME type of an image/blob in javascript?

I'm working on a Chrome Extension in which I resize images (actually resize; not changing the browser display) that users right click on. When they right click on the image, I get access to the image's 'src'.
I can resize the images that aren't gifs fine; I'm using canvases to do this. You can see me do this here https://jsfiddle.net/cyqvacc6/6/.
img_url = 'https://i.imgur.com/SHo6Fub.jpg';
function get_image(image_url, emoji_name) {
var img_el = document.createElement('img');
img_el.onload = function () {
canvas = img_to_canvas(img_el);
emoji_sized_canvas = emoji_sized(canvas);
document.body.appendChild(emoji_sized_canvas);
};
img_el.src = image_url;
}
function img_to_canvas(img) {
canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
canvas_ctx = canvas.getContext('2d');
canvas_ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
return canvas;
}
function emoji_sized(canvas) {
var target_dim = emoji_dimensions(canvas.width, canvas.height);
var factor = 2;
var canvas_long_side = Math.max(canvas.width, canvas.height);
var target_long_side = Math.max(target_dim.width, target_dim.height);
new_canvas = document.createElement('canvas');
new_canvas_ctx = new_canvas.getContext('2d');
if ((target_long_side === canvas_long_side)) {
// Return the image.
return canvas;
} else if (target_long_side > canvas_long_side * factor) {
// Increase the size of the image and then resize the result.
new_canvas.width = canvas.width * factor;
new_canvas.height = canvas.height * factor;
new_canvas_ctx.drawImage(canvas, 0, 0, new_canvas.width, new_canvas.height);
return emoji_sized(new_canvas);
} else if (canvas_long_side > target_long_side * factor) {
// Half the size of the image and then resize the result.
var width = new_canvas.width = canvas.width / factor;
var height = new_canvas.height = canvas.height / factor;
new_canvas_ctx.drawImage(canvas, 0, 0, new_canvas.width, new_canvas.height);
return emoji_sized(new_canvas);
} else {
// Resize the image in one shot
new_canvas.width = target_dim.width;
new_canvas.height = target_dim.height;
new_canvas_ctx.drawImage(canvas, 0, 0, new_canvas.width, new_canvas.height);
return new_canvas;
}
}
function emoji_dimensions(width, height) {
const MAX_SIDE_LENGTH = 128;
// Get the larger side
long_side = Math.max(height, width);
// Determine the scale ratio
// If the image is between 95% to 100% of the target
// emoji size, don't adjust it's size.
var scale;
if ((long_side >= 0.95 * MAX_SIDE_LENGTH) && (long_side <= MAX_SIDE_LENGTH))
{
scale = 1;
} else {
scale = MAX_SIDE_LENGTH / long_side;
}
return {
'height': height * scale,
'width': width * scale
};
}
Unfortunately, I'm not seeing an easy way to resize gifs using canvases. When I try the same approach on gifs, the 'resized' image is no longer a gif; it's just the first frame of the gif resized.
I think I'm going to end up sending gifs to a server to resize them, but still, in order to do this, I need to know whether the image I'm working on is animated or not, which I don't know how to do.
So, how do I determine if an image is a gif? Also, is it possible to resize these gifs from the client, i.e. javascript?
For reference, I need to reduce the gifs in terms of byte size and pixel, i.e. the gif needs to be both below 128px in both height and width and less than 64k in total byte size.
Since your question actually contains multiple questions, it's quite hard to answer it, so I'll currently don't include code in here.
First, Canvas API can only draw the first frame of any animated image passed through an <img> element. According to specs.
Specifically, when a CanvasImageSource object represents an animated image in an HTMLOrSVGImageElement, the user agent must use the default image of the animation (the one that the format defines is to be used when animation is not supported or is disabled), or, if there is no such image, the first frame of the animation, when rendering the image for CanvasRenderingContext2D APIs.
So you won't natively be able to render all your gif's frames on the canvas.
For this, you'll have to parse the file and extract every frames of your file.
Here are is an untested library that do propose this functionality :
libgif-js.
If you don't like libraries, you could also write a script yourself.
edit: I tried this lib and it's awfull... don't use it, maybe you could fork it, but it's really not meant to do image processing
Once you've got the frames, you can resize these with canvas, and then reencode them all in a final gif file. Untested either gif.js seems to be able to do that.
Tested too, little bit less awfull but it doesn't like transparency and it needs to have the js files hosted, so no online demo... Would also probably need a fork...
And finally, to answer the title question, "How to check the MIME type of a file", check this Q/A.
Basically, the steps are to extract the 4 first bits of your file and checking it against magic-numbers. 'image/gif' magic-numbers are 47 49 46 38.

<img/> tag width and height not correct when getting it from $('img).width()/height()

I am currently trying to get RGB data for a texture image, while displaying a preview of the texture to the user.
The user drops an image file into the form, and it should show the preview of the image, while drawing the image to an canvas to get the RGB values for each pixel:
handleTextureImageDrop = (e) ->
e.stopPropagation()
e.preventDefault()
if e.dataTransfer.files.length >= 1
file = e.dataTransfer.files[0]
if file
reader = new FileReader()
reader.onload = (loadEvent) ->
img = $ '<img/>'
img.attr
src: loadEvent.target.result
$(e.target).html img
reader.onloadend = (loadendEvent) ->
img = $(e.target).children 'img'
width = img.width()
height = img.height()
canvas = $ '<canvas/>',
width: width
height: height
$('#wrapper').append canvas
context = $('canvas').get(0).getContext '2d'
context.drawImage img.get(0), 0, 0
rgb = (for x in [0...width]
for y in [0...height]
context.getImageData(x, y, 1, 1).data)
canvas.remove()
TEXTURE_FILES.push
image: file.name
rgb: rgb
reader.readAsDataURL file
As it stands it works about 50% of the time, but the rest of the time width and height are set to 0, so the iteration across the pixel data never happens.
This would suggest to me that there is some sort of race condition happening where the image hasn't loaded into the <img/> tag yet.
Is that what is happening? Or am I missing something silly and obvious?
Any help would be much appreciated.
You will get correct width and height only after the image has been loaded. Usually $(img).load is used for this.
$(img).load(function(e){
var w = $(img).width();
var h = $(img).height();
});
$(img).attr("src", "http://....");
I am not familiar with coffeescript, so I am not able to understand whether you are doing this in your current code. If not please try it.

How to save/export a DOM element to an image?

I have a web page which has a form element (with its ID known) and
inside the form there are multiple DIVs, and the position of each div
may be changed.
What I'd like to do is:
a) Save the current state of this form
// var currentForm=document.forms['myFrm'].innerHTML;
would probably suffice...
b) Save or export the entire form with the most current position of each DIV
to an image file.
// how to save/export the javascript var of currentForm to an image
file is the key question.
Any help/pointer would be appreciated.
After hours of research, I finally found a solution to take a screenshot of an element, even if the origin-clean FLAG is set (to prevent XSS), that´s why you can even capture for example Google Maps (in my case). I wrote an universal function to get a screenshot. The only thing you need in addition is the html2canvas library (https://html2canvas.hertzen.com/).
Example:
getScreenshotOfElement($("div#toBeCaptured").get(0), 0, 0, 100, 100, function(data) {
// in the data variable there is the base64 image
// exmaple for displaying the image in an <img>
$("img#captured").attr("src", "data:image/png;base64,"+data);
}
Keep in mind console.log() and alert() won´t generate an output if the size of the image is great.
Function:
function getScreenshotOfElement(element, posX, posY, width, height, callback) {
html2canvas(element, {
onrendered: function (canvas) {
var context = canvas.getContext('2d');
var imageData = context.getImageData(posX, posY, width, height).data;
var outputCanvas = document.createElement('canvas');
var outputContext = outputCanvas.getContext('2d');
outputCanvas.width = width;
outputCanvas.height = height;
var idata = outputContext.createImageData(width, height);
idata.data.set(imageData);
outputContext.putImageData(idata, 0, 0);
callback(outputCanvas.toDataURL().replace("data:image/png;base64,", ""));
},
width: width,
height: height,
useCORS: true,
taintTest: false,
allowTaint: false
});
}
There is a library called Domvas that should do what you want.
It gives you the ability to take arbitrary DOM content and paint it to
a Canvas of your choice.
After that exporting an image from a canvas element should be pretty easy:
var canvas = document.getElementById("mycanvas");
var img = canvas.toDataURL("image/png");
document.write('<img src="'+img+'"/>');
Do you want to do it completely in JavaScript? If so, one possible solution could be to transform the HTML to an SVG. Or maybe you can use the <canvas> tag and draw it manually.

Categories