How Do You Render a Portion of an SVG in Canvas? - javascript

Core Problem:
The goal is to render a portion of an SVG to a fixed size Canvas element on a web page.
My Attempted Solution:
Seeing as CanVG seems to be the most straight-forward way to render an SVG image in Canvas I figured I could leverage the viewBox attribute to crop the image prior to CanVG's rendering. I've been having trouble on this point.
The Question:
Provided an SVG image, how can one render a portion of that image to a Canvas element?

Create an offscreen canvas and render to it using CanVG:
var full = document.createElement('canvas');
full.width=800; full.height=600;
canvg(full, '<svg>…</svg>');
Copy a portion of this canvas-as-image to a region on another canvas using drawImage (see link for parameter details):
var ctx = myVisibleCanvas.getContext('2d');
ctx.drawImage(full,10,20,80,60,92,16,80,60);
Edit: However, the above is not necessary if you have access to the SVG source (either directly in JS or via an XMLHTTP request) and can modify the viewBox attribute before rendering. See this demo which shows an SVG file rendered directly to one canvas, and then changes the viewBox attribute and renders the clipped region to another canvas.

Which exactly is the problem you get?
The context.drawImage function has a nice cropping feature built in. Instead of the standard 3 parameters (image object, x position, y position) you just pass to it 9 parameters and it will crop the image. These are the parameters:
context.drawImage(
imageObject,
original image x crop position,
original image y crop position,
original image crop width,
original image crop height,
canvas image x crop position,
canvas image y crop position,
canvas image crop width,
canvas image crop height
)
I have no idea if this works with CanVG but, as long as you can pass an image object to the function drawImage(), you will be able to crop it as mentioned in the code.

Related

Apply frame image on top of Fabric JS Canvas

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

HTML5 Canvas bitmaps

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.

Hi I would like to copy content of a canvas in another canvas with zoom

Actually. I have created two canvas one containing some static content & over that another canvas containing some dynamic content. Now I have show snap of both the canvas with zoom in a separate canvas where the snap will change according to the moving object. I am using getImage & putImage but unable to zoom the image content. Even getImage is not working for the canvas contating dynamic content because security error is showing.
context.drawImage can use another canvas as its source image.
context.drawImage can scale the source image when drawing.
context.drawImage does not run afoul of CORS security like getImageData does.
For example, assume sourceCanvas has the original image located at coordinate[20,30] sized at 100x140.
If you have a context to the destination canvas, you can scale it 2X and draw it on the destination canvas at [50,60] like this:
context.drawImage(
sourceCanvas,
20,30,100,140, // grabs 100x140 pixels from sourceCanvas at [20,30]
50,60,200,280 // scale the grabbed pixels to 200x280 and draw it at [50,60]
);

Drawing a Canvas into a smaller Canvas not working

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());

HTML5 canvas image scaling to a smaller size and back to original

A situation I'm trying to solve. I'm loading an image onto a canvas, then making some edits(resize, crop etc.) to it and saving the resultant image to a folder. Now if the original image is larger than the canvas dimensions, the resultant image is cropped. Hence I'm trying to scale the image to a smaller size that fits in the canvas, apply the effects, and then scale it back to the original dimensions and save it. Is there a way to do this?
My JS pseudo code is somewhat like this:
//load the image using drawimage
//compare image dimensions with canvas dimensions, scale down the image if large
//apply the effects
(I have done till here)
//scale it back to original size
//save
How do I scale it to and fro using canvas scale method? I'm assuming I have to calculate a widths ratio for scaling down and up like so:
scale_down_width = image_orig_width / canvas_width
scale_down_height = image_orig_height / canvas_height
//For scaling down
scale(1*scale_down_width, 1*scale_down_height)
//For scaling up
scale(1/scale_down_width, 1/scale_down_height)
Am I doing this correct?
Scale down works fine, but scale up doesn't, how do I do it right?

Categories