I have a transparent GIF image and I am trying to replicate the IE glow filter using the HTML5 Canvas (don't ask). I can do it by drawing the exact same image "underneath" the image that is on top with a shadowBlur filter.
The problem is that the image sometimes has to be flipped horizontally, and the shadowBlur doesn't fire if the image is flipped (still invisible under the img tag as it's the exact same dimensions).
Previous code:
if (flipped)
AddFilter('progid:DXImageTransform.Microsoft.BasicImage(mirror=1,rotation=0)');
AddFilter('progid:DXImageTransform.Microsoft.Glow(Color=" + glowColor + ",Strength=" + glowRank + ")"');
HTML5 Canvas code:
context.shadowBlur = glowRank * 2; // Canvas not as strong
context.shadowColor = glowColor;
if (flipped) {
context.translate(img[0].width, 0);
context.scale(-1, 1);
}
context.drawImage(img[0], img.position().left - 8, img.position().top - 8, img[0].width, img[0].height);
So, basically, we can flip the image or shadowBlur it, but not both. And this is in all browsers. Any way to do both? Pre-render the flipped image somehow and use that?
(And there are 1000s of images, so we can't flip them all ahead of time. It has to be done on the fly.)
What I ended up doing is making a tiny canvas for each image instead of 1 large one that was the whole playfield. I then positioned/flipped the tiny canvases instead.
Related
I am using Fabric JS to allow the user to have an interactive experience on my React app. Is it possible to apply a frame around a Fabric JS that is taken from an image? For instance, if the canvas is 400x400 px I can resize an image of a frame that is transparent in the middle to 410x410px and apply it on top of the canvas for the user to see? I have attached two images for reference.
Edit: This is the code I am using for zooming in
const zoomIn = useCallback(() => {
// Get original height of canvas
const canvasDimensions = getInitialCanvasSize()
let zoom = HTML5Canvas.getZoom()
zoom += 0.2
if (zoom >= 2) zoom = 2
HTML5Canvas.setZoom(zoom)
HTML5Canvas.setWidth(canvasDimensions.width * HTML5Canvas.getZoom());
HTML5Canvas.setHeight(canvasDimensions.height * HTML5Canvas.getZoom());
}, [HTML5Canvas])
There is no option for canvas's border in fabricjs canvas docs
But you can still achieve this easily using following steps.
PART 1: Creating the Illusion of border
CSS Method
First one can easily create CSS border around the canvas.
Best way to do this is to create div around canvas, as fabricjs split canvas in 2 while running.
You can create slider to control width and color/image for div's border.
This will looks like exactly your second image with customization.
OR
Another Canvas Method
Behind current canvas put this second canvas and control its width and image.
I don't recommend this one, as this will make it more complex to implement.
PART 2: Making Illusion real
If you used CSS METHOD
Now you get what your canvas looks like. You have width of border, image/color of border.
Steps:
Create new canvas (lets' call it 2nd Canvas) of 410px if canvas's width 400px with border of 5px.
Export main canvas as image and put it over 2nd Canvas. And now you can export this as final image.
For 2nd step check my answer on this stack
If you used Another Canvas Method
Directly follow above 2nd step
Export main canvas as image and put it over 2nd Canvas. And now you can export this as final image.
For 2nd step check my answer on this stack
I am building a retro styled game, that uses pixelated images. I have not yet created these images, because I wanted to know the best way of doing things.
These images will probably be a 16 or 32 PX square, but I would like to be able to scale the images as big as I like, just without any blur/distortion.
What format should I use? And how should I import them to my canvas. as well?
EDIT#1: Fixed typo & put Q back on topic. (Thank you Spence for pointing it out)
Try "Inkscape", its free
https://inkscape.org/en/
it uses SVG format (scalar vector graphics) so you will be able to scale the images as big as you like, just without any blur/distortion.
The only way to enlarge without any blur or distortion is turn each 1 pixel into a set of 2x2, 3x3, ... pixels.
For example, a single blue pixel in the top-left of the image would become a set of 4 blue pixels at [0,0], [1,0], [0,1] & [1,1]. And the same for every other pixel on the original image. The resulting image would be twice the width & height of the original image.
Since your graphics style is pixelated images, this adjustment would preserve your pixilation while also enlarging the original image.
You can code a function that uses an in-memory html5 canvas to "resize-by-multiplying" your original images as needed. This will use canvas's ability to set the RGBA values every pixel using context.getImageData and context.putImageData.
CanvasContext2d does have an option to disable the image smoothing : imageSmoothingEnabled which is set to true by default.
According to the specs, if set to false,
The image [drawn by drawImage() method] must be rendered using
nearest-neighbor interpolation.
This algorithm is the same as the one proposed by #markE in his answer.
Unfortunately, browsers still use vendor-prefix for this attribute and it wasn't implemented in both IE9 and IE10...
var img = document.querySelector('img'),
canvas = document.querySelector('canvas'),
ctx = canvas.getContext('2d');
// draw the image
img.onload = function(){
canvas.width = img.width*50;
canvas.height = img.height*50;
// disable smoothing after we change canvas' width/height
ctx.mozImageSmoothingEnabled = false;
ctx.webkitImageSmoothingEnabled = false;
ctx.msImageSmoothingEnabled = false;
ctx.imageSmoothingEnabled = false;
ctx.drawImage(img, 0,0, canvas.width, canvas.height);
}
//32x32px image taken from https://stackoverflow.com/q/31910043/3702797
img.src="http://i.stack.imgur.com/3Sp5x.png"
canvas{border:.5px solid}
<img/>
<canvas></canvas>
Scroll to see the resized image in canvas
Create large icon images to which you apply a 16x16 or 32x32 tile effect. Then when you write them to the canvas (after loading the images of course) scale them down to the size you want using
context.drawImage(img,x,y,width,height);
File sizes are unlikely to jump greatly since each tile should compress fairly easily.
When the canvas element is resized (via the style changing) I also want to scale the canvas' drawn image as well. I cannot just change the height/width as this causes the canvas to clear itself, so I do:
Create a temporary canvas element
Draw the current canvas' image onto that temporary canvas
Resize the current canvas
Draw the temp canvas' image back to the current canvas but scaled to the new size
This results in some blurring - very noticeable after many resizes (example: when dragging to resize). How would I do this without any blurring?
EDIT: Turning off image smoothing (context.webkitImageSmoothingEnabled = false;) does not fix the problem, it simply makes it redraw it more and more jagged until the image looks nothing like the original after a number of resizes.
Called on resize event:
var tmpCanvas = null;
//Make a temporary canvas
tmpCanvas = document.createElement( "canvas" );
//Set its size to be equal
tmpCanvas.height = originalCanvas.height;
tmpCanvas.width = originalCanvas.width;
//Draw our current canvas onto it
tmpCanvas.getContext( "2d" ).drawImage( originalCanvas, 0, 0 );
//Set new dimensions
originalCanvas.width = originalCanvas.offsetWidth;
originalCanvas.height = originalCanvas.offsetHeight;
var originalContext = originalCanvas.getContext( "2d" );
//Set background and colors
originalContext.fillStyle = "#ffffff";
originalContext.strokeStyle = "#000000";
//Set paintbrush
originalContext.lineWidth = 4;
originalContext.lineCap = "round";
//Fill background as white
originalContext.fillRect( 0, 0, originalCanvas.width, originalCanvas.height );
//We have a saved signature
if ( SignatureCanvas.hasSignature === true )
{
//Draw it back but scaled (results in blurred image)
originalContext.drawImage( tmpCanvas, 0, 0, tmpCanvas.width, tmpCanvas.height, 0, 0, originalCanvas.width, originalCanvas.height );
/**
* This results in a blurred image as well
//Draw it back but scaled
originalContext.scale( originalCanvas.width / tmpCanvas.width, originalCanvas.height / tmpCanvas.height );
originalContext.drawImage( tmpCanvas, 0, 0, tmpCanvas.width, tmpCanvas.height, 0, 0, tmpCanvas.width, tmpCanvas.height );
*/
}
Is there a way to get the strokes and "scale" all those points and redraw?
Instead of taking the rendered image from the original canvas, actually redraw the image. By that, I mean execute the same logic you executed against the original canvas, but with the points involved scaled to the new size.
If you can, think about using SVG instead. It scales well by its nature.
Edit: Another option I've thought of is to simply use a gigantic canvas to start with. Sizing down tends to look better than sizing up, especially with smoothing on.
Edit II: The original answer was irrelevant, though the comment I had made is relevant, and am now promoting it and editing it to be an answer...and the answer I had given was not all that great anyway **.
Of course if you scale up raster graphics, that is, from an image with a smaller pixel dimensions of pixels, create an image with higher pixel dimensions, you are going to get blurred images. By scaling up, you're making a low resolution picture high resolution, but without the high resolution details.
There's absolutely no way around that blurriness unless you make multiple additional assumptions about your raster image like the only gray you'd see is at an image edge, or corners can only occur at apparent inflection points where the angle between the tangents of the joined curves must be 100 degrees or less. Essentially, you'd have to give additional information so that your higher resolution image can have detail "filled in". It's not all that terribly different from reverse engineering an SVG from a raster.
So, you appear to want to emulate is scaling vector graphics, in which the only solution is to save the commands, draw a SVG, or draw to a bigger canvas like Stuart Branham suggested.
** I had originally proposed that invoking drawImage would distort the pixels even if it were not scaled, and that it would be better to work with the actual pixel data. If that's true, I can't find proof, but that's irrelevant, as he wanted his image scaled up, without blurring...which is impossible, as I just mentioned.
For a Project I want to take the content of a canvas (Called SAVE_CV) and display it in another, smaller canvas.
Some things that I am aware of so far that could be causing me problems: resizing a canvas clears its content, the JS-size of a canvas is different from the CSS-size.
I want the smaller canvas to be 500px wide and appropriately high.
function restoreTaggingCV() {
var cv = document.getElementById( 'taggingCV' );
var ctx = cv.getContext( "2d" );
var styleHeight = SAVE_CV.height * 500 / SAVE_CV.width;
ctx.drawImage(SAVE_CV, 0, 0, cv.width, cv.height);
}
This is my Code so far. Whenever I try to resize the smaller canvas appropriately it only gives me a blank canvas with nothing in it. I tried to set the size with "cv.height = X" and "cv.style.height = styleHeight + 'px'" but neither worked. Also I would love to set the width of the canvas using CSS.
Appreciate any help.
EDIT
I want the image in a picture because later I want the user to mark areas in the smaller version which I then want to use to create individual imaged from the big version. I want to visualise thise area to the user. I probably could do all this by using an image and putting divs over it or something but I just fell more comfident using a canvas since I am pritty new to HTML and CSS.
Try using the CanvasRenderingContext2d.prototype.scale method. It sets the scale factor of the canvas and renders anything in the current state with it's dimensions multiplied by the factor.
So before you use the drawImage function, you scale the context appropriately (in this case, down). For example:
context.save();
context.scale(0.5, 0.5);
context.drawImage(canvas, 0, 0);
context.restore();
This would render the canvas on the context at 0.5 times it's current size. See in this fiddle how I used it to mirror a larger canvas onto a smaller, separate one.
Canvas objects don't like to be resised. After drawing Your image simply convert it toDataURL() and set as image source. They You may resize image as you want.
$img.attr('src',canvas.toDataURL());
I have a canvas on which the user can draw with some sort of pen.
The canvas height is slightly larger than the width. The actual size depends on several variables.
I want to give the user the ability to rotate his/her drawing.
I'm creating a new canvas on which i draw the old canvas rotated.
Below is how i did 180 degrease.
if(rotation==180){
ctx.translate(canvas.width/2, canvas.height/2);
ctx.rotate(Math.PI);
ctx.translate(-canvas.width/2, -canvas.height/2);
ctx.drawImage(drawing,0,0);
}
Now for the 90 degrease I also have to do a resize because otherwise it won´t fit anymore.
I'm not even sure where to start. Any ideas on how to do this?
See this posts
HTML5 canvas image rotate left rotate right
http://phptechworld.blogspot.in/2012/10/html5-canvas-image-rotation.html
u can use CSS3 for rotation:like
h1
{
rotation-point:50% 50%;
rotation:180deg;
}