QML canvas drawImage does not work properly with AA_EnableHighDpiScaling - qt

I create a qml application where is drawing on Wacom tablet to qml canvas.
After drawing, I send the base64 image to the server and if I need it, I read it and draw it back.
Drawed image look good. When i looked image on server, it is in good quality. But when i draw it again into canvas is little blurry. If i save and redraw image repeatly, it is more and more blurry.
On HD screen it is not so visible, but when i use 4K screen, image quality is terrible.
When i don't use Qt::AA_EnableHighDpiScaling is still in good quality. But without Qt::AA_EnableHighDpiScaling is application gui too small on 4k screen.
When i disable smooth and antialising in canvas, image is not blurry but it not looks good.
this i am use for save image:
var loadedImage = canvas.toDataURL("image/png")
this is for loading image :
canvas.loadImage(loadedImage)
Canvas{
id: canvas
onImageLoaded:{
var ctx = canvas.getContext("2d");
ctx.drawImage(loadedImage,canvas.x,canvas.y,canvas.width,canvas.height);
canvas.requestPaint();
}
and part of drawing function:
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.moveTo(canvas.prevX, canvas.prevY);
ctx.lineTo(newPoint.x, newPoint.y);
ctx.stroke();
ctx.closePath();
canvas.prevX = newPoint.x;
canvas.prevY = newPoint.y;
canvas.requestPaint();
How to fix drawImage when is AA_EnableHighDpiScaling enabled? I use Qt 5.9.

I found a solution;
onImageLoaded:{
var ctx = canvas.getContext("2d");
ctx.scale(1/Screen.devicePixelRatio,1/Screen.devicePixelRatio);
ctx.drawImage(loadedImage,canvas.x,canvas.y);
ctx.scale(Screen.devicePixelRatio,Screen.devicePixelRatio);
canvas.requestPaint();

Related

Enlarge Image Canvas

Is there a quick way using System.Drawing to quickly enlarge the image canvas of an .png image? (see example below). The caveat is the background might be transparent and I want to keep it transparent.
Edit: Needs to be in ASP .Net CORE
Alternatively, is there a way of putting the image on a white background that is slightly larger than the image?
After a few days of trial and error, I think I found something that works
Image overlayImage = //get your image here from file or url.
xloc = //x coord where to start overlay image.
yloc = //y coord where to start overlay image.
canvasWidth = //width of background canvas
canvasHeight = //height of background canvas
Bitmap baseImage = new Bitmap(canvasWidth, canvasHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
using (Graphics graphics = Graphics.FromImage(baseImage))
{
using (System.Drawing.SolidBrush myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.White))
{
graphics.FillRectangle(myBrush, new Rectangle(0, 0, canvasWidth, canvasHeight)); // white rectangle
}
graphics.CompositingMode = CompositingMode.SourceOver;
graphics.DrawImage(overlayImage, xloc, yloc);
} // graphics will be disposed at this line

How to save a high DPI snapshot of a JavaFX Canvas

I have created an image on a Canvas which is scaled down for display using a transformation. It is also in a ScrollPane which means only a part of the image is visible.
I need to take a snapshot of the entire canvas and save this as a high-resolution image. When I use Canvas.snapshot I get a Writable image of the visible part of the image after scaling down. This results in a low-res partial image being saved.
So how do I go about creating a snapshot which includes the entire canvas (not only the viewport of the scrollpane) and with the resolution before the transformation downwards?
I am not doing anything fancy currently, just this:
public WritableImage getPackageCanvasSnapshot()
{
SnapshotParameters param = new SnapshotParameters();
param.setDepthBuffer(true);
return packageCanvas.snapshot(param, null);
}
I did the following to get a canvas snapshot on a Retina display with a pixelScaleFactor of 2.0. It worked for me.
public static WritableImage pixelScaleAwareCanvasSnapshot(Canvas canvas, double pixelScale) {
WritableImage writableImage = new WritableImage((int)Math.rint(pixelScale*canvas.getWidth()), (int)Math.rint(pixelScale*canvas.getHeight()));
SnapshotParameters spa = new SnapshotParameters();
spa.setTransform(Transform.scale(pixelScale, pixelScale));
return canvas.snapshot(spa, writableImage);
}

Scaling a canvas nicely with css

I'm trying to draw an image on a canvas, then use css to fit the canvas within a certain size. It turns out that many browsers don't scale the canvas down very nicely. Firefox on OS X seems to be one of the worst, but I haven't tested very many. Here is a minimal example of the problem:
HTML
<img>
<canvas></canvas>
CSS
img, canvas {
width: 125px;
}
JS
var image = document.getElementsByTagName('img')[0],
canvas = document.getElementsByTagName('canvas')[0];
image.onload = function() {
canvas.width = image.width;
canvas.height = image.height;
var context = canvas.getContext('2d');
context.drawImage(image, 0, 0, canvas.width, canvas.height);
}
image.src = "http://upload.wikimedia.org/wikipedia/commons/thumb/0/00/Helvetica_Neue_typeface_weights.svg/783px-Helvetica_Neue_typeface_weights.svg.png"
Running in a codepen: http://codepen.io/ford/pen/GgMzJd
Here's the result in Firefox (screenshot from a retina display):
What's happening is that both the <img> and <canvas> start at the same size and are scaled down by the browser with css (the image width is 783px). Apparently, the browser does some nice smoothing/interpolation on the <img>, but not on the <canvas>.
I've tried:
image-rendering, but the defaults seem to already be what I want.
Hacky solutions like scaling the image down in steps, but this didn't help: http://codepen.io/ford/pen/emGxrd.
Context2D.imageSmoothingEnabled, but once again, the defaults describe what I want.
How can I make the image on the right look like the image on the left? Preferably in as little code as possible (I'd rather not implement bicubic interpolation myself, for example).
You can fix the pixelation issue by scaling the canvas's backing store by the window.devicePixelRatio value. Unfortunately, the shoddy image filtering seems to be a browser limitation at this time, and the only reliable fix is to roll your own.
Replace your current onload with:
image.onload = function() {
var dpr = window.devicePixelRatio;
canvas.width = image.width * dpr;
canvas.height = image.height * dpr;
var context = canvas.getContext('2d');
context.drawImage(image, 0, 0, canvas.width, canvas.height);
}
Results:
Tested on Firefox 35.0.1 on Windows 8.1. Note that your current code doesn't handle browser zoom events, which could reintroduce pixelation. You can fix this by handling the resize event.
Canvas is not quite meant to be css zoomed : Try over-sampling : use twice the required canvas size, and css scaling will do a fine job in down-scaling the canvas.
On hi-dpi devices you should double yet another time the resolution to reach the
same quality.
(even on a standard display, X4 shines a bit more).
(Image, canvas 1X, 2X and 4X)
var $ = document.getElementById.bind(document);
var image = $('fntimg');
image.onload = function() {
drawAllImages();
}
image.src = "http://upload.wikimedia.org/wikipedia/commons/thumb/0/00/Helvetica_Neue_typeface_weights.svg/783px-Helvetica_Neue_typeface_weights.svg.png"
function drawAllImages() {
drawImage(1);
drawImage(2);
drawImage(4);
}
function drawImage(x) {
console.log('cv' + x + 'X');
var canvas = $('cv' + x + 'X');
canvas.width = x * image.width;
canvas.height = x * image.height;
var context = canvas.getContext('2d');
context.drawImage(image, 0, 0, canvas.width, canvas.height);
}
img,
canvas {
width: 125px;
}
<br>
<img id='fntimg'>
<canvas id='cv1X'></canvas>
<canvas id='cv2X'></canvas>
<canvas id='cv4X'></canvas>
<br>
It's not good idea to scale canvas and think that you solved the image scale problem.you can pass your dynamic value to canvas,and then draw with that size whatever you want.
here is link of canvas doc: http://www.w3docs.com/learn-javascript/canvas.html
Simple answer, you can't do it. The canvas is just like a bitmap, nothing more.
My idea:
You should redraw the whole surface on zooming, and make sure you scale the image you're drawing to the canvas. As it is a vector graphic, this should work. But you're going to have to redraw the canvas for sure.

Jaggies text when fillText in canvas in chrome

I am trying to draw text in canvas but the drawn text has jaggies especially in chrome 31.0.1650.
I have tried -webkit-font-smoothing:antialiased,text-shadow but all go in vain.
How to tackle this problem?
Thanks in advance.
Here is the style code:
<style>
#my_canvas{
-webkit-font-smoothing: antialiased;
text-shadow: 1px 1px 1px rgba(0,0,0,0.004);
text-indent: -9999px;
}
</style>
The code in body:
<canvas id="my_canvas" height="300" width="2200"></canvas>
<script>
var canvas = document.getElementById("my_canvas");
var context = canvas.getContext("2d");
context.imageSmoothingEnabled =true;
context.fillStyle = "BLACK";
context.font = "bold 100px Arial";
context.fillText("A quick brown fox jumps over the lazy dOg", 50, 200);
</script>
This is an issue with the Chrome text engine.
There is a technique you can use to get around this though:
Setup an off-screen canvas double the size of the on-screen canvas
Draw the text to the off-screen canvas in scale: font size and position
Draw the off-screen canvas to main canvas scaled down (half in this case).
Live demo here
The difference is subtle (as expected) but improves the quality. Here is an enlargement:
Sidenotes: CSS does not affect content of the canvas, only elements. Image smoothing is enabled by default and affects only images but not text or shapes (we will use this though for this technique).
var scale = 2; // scale everything x2.
var ocanvas = document.createElement('canvas');
var octx = ocanvas.getContext('2d');
ocanvas.width = canvas.width * scale; // set the size of new canvas
ocanvas.height = canvas.height * scale;
// draw the text to off-screen canvas instead at double sizes
octx.fillStyle = "BLACK";
octx.font = "bold " + (100 * scale) + "px Arial";
octx.fillText("A quick brown fox jumps over the lazy dOg", 50*scale, 200*scale);
// key step is to draw the off-screen canvas to main canvas
context.drawImage(ocanvas, 0, 0, canvas.width, canvas.height);
What happens is that we are introducing interpolation in the mix here. Chrome will draw the text very rough also to the off-screen canvas, but after the text becomes rasterized we can deal with it as an image.
When we draw the canvas (aka image) to our main canvas at half the size, interpolation (sub-sampling) kicks in and will low-pass filter the pixels giving a smoother look.
It will of course take more memory but if result is important that is a small price to pay nowadays.
You will probably notice that other values than 2 doesn't work so well. This is because the canvas typically uses bi-linear interpolation rather than bi-cubic (which would allow us to use 4). But I think 2x serves us well in this case.
Why not using transform, ie. scale() ? Chrome's text engine (or the way it's used) does not rasterize the text at 1x and then transforms it. It takes the vectors, transforms them and then rasterize the text which will give the same result (ie. scale 0.5, draw double).

How to increse performance of raster scrolling on Mac?

I have a game with a big raster map
Now we are using jpeg (4900x4200)
And durring the game we need to scroll through this map.
We use the following:
Class Map extends mx.containers.Canvas
and mx.controls.Image on it
In constructor we have:
public function Map() {
super();
image.source = ResourceManager.interactiveManager.map;//big image
addChild(image);
......
}
for scrolling we are use:
if(parentAsCanvas==null){
parentAsCanvas = (parent as Canvas);
}
parentAsCanvas.verticalScrollPosition = newX;
parentAsCanvas.horizontalScrollPosition = newY;
In windows, we have very good performance.
In Linux and Mac in flashplayer we have a good performance too.
But in browsers performance is quite slow!
What can we do to resolve it?
It's slow because you're rendering a large image all the time.
Here are a few things that cross my mind:
Try using the scrollRect property in a Bimtap object holding your image BitmapData to display just the visible area then use the scrollRect x and y to move to a new region
Try using a BitmapData the size of the viewable area and use copyPixels() to get the right area to display, again using a rectangle
Try using BitmapData.scroll()
Here are a few snippets:
scrollRect:
//assuming map is BitmapData containing your large image
//100x100 is a test scroll area
var scroll:Rectangle = new Rectangle(0,0,100,100);
var bitmap:Bitmap = new Bitmap(map);
bitmap.scrollRect = scroll;
addChild(bitmap);
this.addEventListener(Event.ENTER_FRAME, update);
function update(event:Event):void{
scroll.x = mouseX;
scroll.y = mouseY;
bitmap.scrollRect = scroll;
}
copyPixels:
var scroll:Rectangle = new Rectangle(0,0,100,100);
var scrollPoint:Point = new Point();
var map:BitmapData = new Map(0,0);
var bitmap:Bitmap = new Bitmap(new BitmapData(100,100,false));
bitmap.bitmapData.copyPixels(map,scroll,scrollPoint);
addChild(bitmap);
this.addEventListener(Event.ENTER_FRAME, update);
function update(event:Event):void{
scroll.x = mouseX;
scroll.y = mouseY;
bitmap.bitmapData.fillRect(scroll,0xFFFFFF);
bitmap.bitmapData.copyPixels(map,scroll,scrollPoint);
}
Not perfect, but it should give you an idea
HTH,
George
I've read the following acrticle http://www.insideria.com/2008/04/flex-ria-performance-considera.html
I and i found the resolve of my problem.
If i open my SWF in browser as "http://host/myswf.swf" I have huge performance lose in browser as the reason work LaoyoutManager, that recalculates positions and sizes of all canvases in the application. And it process eats more than 60% of performance capacity.(Yep, we have a lot of Canvases in our application).
And when i putted my application in contant-size html block in html page, all problems were go away! I've got 80% performance increase!

Resources