I am trying to develop a canvas element where users can drop uploaded images. However, I am running into trouble with this command
var canvas = new fabric.Canvas('canvasID');
The canvas element is somehow getting resized and I don't understand why. Can anyone help?
If you are finding the canvas is resizing to a size smaller than you expected, there is a good chance you haven't defined the height and width of the canvas itself when creating it with Fabric.
An example of doing this would be:
var id = 'c',
drawingMode = true,
w = 1024,
h = 768,
newCanvas = new fabric.Canvas(id, { isDrawingMode: drawingMode });
newCanvas.setWidth(w);
newCanvas.setHeight(h);
The variables w and h are just examples, but the last two lines ensure your canvas has a size set rather than default of 300 x 150.
Hope this helps.
Related
I have a shape rendered in with Konva, when set a fillPatternImage, this one is well rendered with Chrome and stretched with firefox.
Good rendering in Chrome
False rendering in Firefox*
The image file is a *.png.
Have somebody any reason why ?
MORE INFORMATIONS :
In the following code element is Konva.Rect() object, I set an image for filling in center of the element :
const imageObj = new Image();
const filename = zone.visual;
imageObj.onload = function() {
element.fillPatternImage(imageObj);
element.fillPatternRepeat('no-repeat');
element.fillPatternOffsetX((imageObj.width - zone.sizeX) / 2);
element.fillPatternOffsetY((imageObj.height - zone.sizeY) / 2);
element.draw();
};
imageObj.src = this.utils.getImgUrl(filename, 'configurator_zone');
I found a solution this afternoon.
In order to reproduce the problem, the edge of the image must be in contact with the cross. By reducing the size of the cross compared to the size of the image, the problem disappears.
Problematic cross : cross reproducing error
Correct cross : correct cross
In my UWP app we have images that users upload and they can be pretty much any size - so when I load these into in an Image control I resize them proportionally so they fit best into our image container (which is fixed at 112w x 152h) but as some images are wider than higher what I want to is find the background color of the image so I can set the Background of the image.
So to do this I am using the NuGet ColorThief package and the code below (taken from the sample I found there) is returning me the wrong dominant color in many cases:
var ct = new ColorThief();
QuantizedColor qc = await ct.GetColor(decoder); //BitmapDecoder containing image
Windows.UI.Color c = Windows.UI.Color.FromArgb(qc.Color.A, qc.Color.R, qc.Color.G, qc.Color.B);
setImageBackgroundColor(bgColour);
One image I tried it on was this one - now the dominant colour should clearly be black but it's returning some medium grey colour.... so is there something wrong with my code or my image or is there something else I need to do? I'm just not finding it reliable but I know others use it without issue.
According to the source code of the library, it seems it is actually averaging out the colors from the color palette of the picture
public async Task<QuantizedColor> GetColor(BitmapDecoder sourceImage, int quality = DefaultQuality,
bool ignoreWhite = DefaultIgnoreWhite)
{
var palette = await GetPalette(sourceImage, 3, quality, ignoreWhite);
var dominantColor = new QuantizedColor(new Color
{
A = Convert.ToByte(palette.Average(a => a.Color.A)),
R = Convert.ToByte(palette.Average(a => a.Color.R)),
G = Convert.ToByte(palette.Average(a => a.Color.G)),
B = Convert.ToByte(palette.Average(a => a.Color.B))
}, Convert.ToInt32(palette.Average(a => a.Population)));
return dominantColor;
}
In this particular case, I think setting ignoreWhite to true might return the actual black color, although it seems true is indeed the default setting.
I recommend using the other public method the library provides: GetPalette, to see what is the actual color palette of this image. This should explain why you are getting this particular color.
var palette = await GetPalette(decoder);
In my opinion you need to set quality from 5 to 10 and use GetPalette method with first color from palette.
QuantizedColor dominantColor = colorThief.GetPalette(tempBitmap, 5, 5, true)[0];
I am desperately searching for a good cropping tool. There are a bunch out there, for example:
Croppic
Cropit
Jcrop
The most important thing that I am trying to find is a cropping tool, that crops images without making the cropped image low in resolution. You can hack this by using the canvas tag by resizing the image. This way the image itself stays native, only the representation is smaller.
DarkroomJS was also something near the solution, but, unfortunately, the downloaded demo did not work. I'll try to figure out whats wrong. Does someone know some great alternatives, or how to get the cropped images in...let's say "native" resolution?
Thanks in advance!
You are relying on the cropping tool to provide an interface for the users. the problem is that the image returned is sized to the interface and not the original image. Rather than me sifting through the various API's to see if they provide some way of controlling this behaviour (I assume at least some of them would) and because it is such a simple procedure I will show how to crop the image manually.
To use JCrop as an example
Jcrop provides various events for cropstart, cropmove, cropend... You can add a listener to listen to these events and keep a copy of the current cropping interface state
var currentCrop;
jQuery('#target').on('cropstart cropmove cropend',function(e,s,crop){
currentCrop = crop;
}
I don't know where you have set the interface size and I am assuming the events return the crop details at the interface scale
var interfaceSize = { //you will have to work this out
w : ?,
h : ?.
}
Your original image
var myImage = new Image(); // Assume you know how to load
So when the crop button is clicked you can create the new image by scaling the crop details back to the original image size, creating a canvas at the cropped size, drawing the image so that the cropped area is corectly positioned and returning the canvas as is or as a new image.
// image = image to crop
// crop = the current cropping region
// interfaceSize = the size of the full image in the interface
// returns a new cropped image at full res
function myCrop(image,crop,interfaceSize){
var scaleX = image.width / interfaceSize.w; // get x scale
var scaleY = image.height / interfaceSize.h; // get y scale
// get full res crop region. rounding to pixels
var x = Math.round(crop.x * scaleX);
var y = Math.round(crop.y * scaleY);
var w = Math.round(crop.w * scaleX);
var h = Math.round(crop.h * scaleY);
// Assume crop will never pad
// create an drawable image
var croppedImage = document.createElement("canvas");
croppedImage.width = w;
croppedImage.height = h;
var ctx = croppedImage.getContext("2d");
// draw the image offset so the it is correctly cropped
ctx.drawImage(image,-x,-y);
return croppedImage
}
You then only need to call this function when the crop button is clicked
var croppedImage;
myButtonElement.onclick = function(){
if(currentCrop !== undefined){ // ensure that there is a selected crop
croppedImage = myCrop(myImage,currentCrop,interfaceSize);
}
}
You can convert the image to a dataURL for download, and upload via
imageData = croppedImage.toDataURL(mimeType,quality) // quality is optional and only for "image/jpeg" images
I am using the HTML5 canvas to draw an organisational structure. Each node includes an image, the URL of which is obtained form a database. I have a little function that handles the loading of the image, and that adds it to the canvas once loaded. It looks like this (note that the important bit is the onload listener added to the image):
(function (i, ctx, DrawId) {
var img = new Image();
img.src = REPORT.Structures[i].Managers[j].Employee.PhotoUrl; //get URL from object constructed elsewhere
img.onload = function () { //attach onload event
ctx.drawImage(img, x, y, width, height);//draw image on the canvas. x, y width and height are calculated inside the onload, but I have removed the calculations to improve readability
}
}
})(i, ctx, REPORT.DrawId);
This works great, except that the images all pop into existence at random as they finish loading. It looks very untidy.
I am looking for a way to make this look smoother. My first instinct is to try and create a fade in effect, but I can't think of how to do this without redrawing the canvas over and over.
I have thought of trying something like this:
img.onload = function () {
var counter = 1;
var width = 30 * REPORT.ZoomLevel;
var height = 30 * REPORT.ZoomLevel;
function fadeInImage(ctx, img, x, y, width, height) {
ctx.globalAlpha = 0.1 * counter;
ctx.drawImage(img, x, y, width, height);
counter++;
if (counter == 10)
clearTimeout(fadeInImageTimeout);
console.log(counter);
}
var fadeInImageTimeout = setInterval(function () { fadeInImage(ctx, img, x, y, width, height); }, 100);
}
This works, but I am also worried that if it does, it will be too processing heavy.
Has anyone tried doing something like this? Any suggestions would be much appreciated.
PS:
I am currently considering only having one interval that draws all images. Each image will be pushed into an array, and all elements in the array will be drawn once all images are loaded. Will keep you updated.
PPS:
I have managed to get it working as I mentioned in the PS above. It does not seem to affect the performance though. I guess the lag I am still experiencing is related to the image loading time. I'll try and strip out the code into a bare bones version and post it here a bit later, but if anyone can see a flaw in my approach, please do not hesitate to point it out. Again, any suggestions would be greatly appreciated.
I asked a question on SO about compiling an image file from HTML. Michaƫl Witrant responded and told me about the canvas element and html5.
I'm looked on the net and SO, but i haven't found anything regarding drawing a misc element's contents onto a canvas. Is this possible?
For example, say i have a div with a background image. Is there a way to get this element and it's background image 'onto' the canvas? I ask because i found a script that allows one to save the canvas element as a PNG, but what i really want to do is save a collection of DOM elements as an image.
EDIT
It doesn't matter what language, if it could work, i'm willing to attempt it.
For the record, drawWindow only works in Firefox.
This code will only work locally and not on the internet, using drawWindow with an external element creates a security exception.
You'll have to provide us with a lot more context before we can answer anything else.
http://cutycapt.sourceforge.net/
CutyCapt is a command line utility that uses Webkit to render HTML into PNG, PDF, SVG, etc. You would need to interface with it somehow (such as a shell_exec in PHP), but it is pretty robust. Sites render exactly as they do in Webkit browsers.
I've not used CutyCapt specifically, but it came to me highly recommended. And I have used a similar product called WkHtmlToPdf, which has been awesome in my personal experience.
After many attempts using drawWindow parameters, that were drawing wrong parts or the element, I managed to do it with a two steps processing : first capture the whole page in a canvas, then draw a part of this canvas in another one.
This was done in a XUL extension. drawWindow will not work in other browsers, and may not work in a non-privileged context due to security reasons.
function nodeScreenshot(aSaveLocation, aFileName, aDocument, aCSSSelector) {
var doc = aDocument;
var win = doc.defaultView;
var body = doc.body;
var html = doc.documentElement;
var selection = aCSSSelector
? Array.prototype.slice.call(doc.querySelectorAll(aCSSSelector))
: [];
var coords = {
top: 0,
left: 0,
width: Math.max(body.scrollWidth, body.offsetWidth,
html.clientWidth, html.scrollWidth, html.offsetWidth),
height: Math.max(body.scrollHeight, body.offsetHeight,
html.clientHeight, html.scrollHeight, html.offsetHeight)
var canvas = document.createElement("canvas");
canvas.width = coords.width;
canvas.height = coords.height;
var context = canvas.getContext("2d");
// Draw the whole page
// coords.top and left are 0 here, I tried to pass the result of
// getBoundingClientRect() here but drawWindow was drawing another part,
// maybe because of a margin/padding/position ? Didn't solve it.
context.drawWindow(win, coords.top, coords.left,
coords.width, coords.height, 'rgb(255,255,255)');
if (selection.length) {
var nodeCoords = selection[0].getBoundingClientRect();
var tempCanvas = document.createElement("canvas");
var tempContext = tempCanvas.getContext("2d");
tempCanvas.width = nodeCoords.width;
tempCanvas.height = nodeCoords.height;
// Draw the node part from the whole page canvas into another canvas
// void ctx.drawImage(image, sx, sy, sLargeur, sHauteur,
dx, dy, dLargeur, dHauteur)
tempContext.drawImage(canvas,
nodeCoords.left, nodeCoords.top, nodeCoords.width, nodeCoords.height,
0, 0, nodeCoords.width, nodeCoords.height);
canvas = tempCanvas;
context = tempContext;
}
var dataURL = canvas.toDataURL('image/jpeg', 0.95);
return dataURL;
}