Openlayers 3 export map to png image size - openlayers-3

I am trying to export openlayers 3 map to PNG.
This example is working well http://openlayers.org/en/master/examples/export-map.html , but the export image width and height are double than the original map canvas.
If the map canvas is 1330x440, I get the exported png image as 2660x880 pixels.
Any idea how to get the export size same as canvas size ?

This is because your device pixel ratio is 2, because you have a HiDPI (Retina) display.
You can either configure your map with {pixelRatio: 1} and get a blurry map, or scale the exported image when ol.has.DEVICE_PIXEL_RATIO is not equal 1:
map.once('postcompose', function(event) {
var dataURL;
var canvas = event.context.canvas;
if (ol.has.DEVICE_PIXEL_RATIO == 1) {
dataURL = canvas.toDataURL('image/png');
} else {
var targetCanvas = document.createElement('canvas');
var size = map.getSize();
targetCanvas.width = size[0];
targetCanvas.height = size[1];
targetCanvas.getContext('2d').drawImage(canvas,
0, 0, canvas.width, canvas.height,
0, 0, targetCanvas.width, targetCanvas.height);
dataURL = targetCanvas.toDataURL('image/png');
}
});
map.renderSync();

Related

Cropping UIImage Using VNRectangleObservation

I'm using the Vision framework to detect rectangular documents in a captured photo. Detecting and drawing a path around the document is working perfectly. I then want to crop the image to be only the detected document. I'm successfully cropping the image, but it seems the coordinates don't line up and the cropped image is only part of the detected document and the rest is just the desk behind the document. I'm using the following cropping code:
private UIImage CropImage(UIImage image, CGRect rect, float scale)
{
var drawRect = new CGRect(rect.X, rect.Y, rect.Size.Width, rect.Size.Height);
using (var cgImage = image.CGImage.WithImageInRect(drawRect))
{
var croppedImage = UIImage.FromImage(cgImage);
return croppedImage;
};
}
Using the following parameters:
image is the same UIImage that i successfully drew the rectangle path on.
rect is the VNRectangleObservation.BoundingBox. This is normalized so i'm scaling it using the image.size. it's the same scaling i do when drawing the rectangle path.
scale is 1f, but i'm currently ignoring this.
The cropped image generally seems to be the right size, but it is shifted up and to the left which cuts off the lower and right side of the document. Any help would be appreciated.
for anyone else that finds this, the issue seemed to be CGImage rotating when cropping the image which caused the VNRectangleObservation to not line up anymore. I used this article, Tracking and Altering Images, to get a working solution using CIFilter. Cropping code follows:
var ciFilter = CIFilter.FromName("CIPerspectiveCorrection");
if (ciFilter == null) continue;
var width = inputImage.Extent.Width;
var height = inputImage.Extent.Height;
var topLeft = new CGPoint(observation.TopLeft.X * width, observation.TopLeft.Y * height);
var topRight = new CGPoint(observation.TopRight.X * width, observation.TopRight.Y * height);
var bottomLeft = new CGPoint(observation.BottomLeft.X * width, observation.BottomLeft.Y * height);
var bottomRight = new CGPoint(observation.BottomRight.X * width, observation.BottomRight.Y * height);
ciFilter.SetValueForKey(new CIVector(topLeft), new NSString("inputTopLeft"));
ciFilter.SetValueForKey(new CIVector(topRight), new NSString("inputTopRight"));
ciFilter.SetValueForKey(new CIVector(bottomLeft), new NSString("inputBottomLeft"));
ciFilter.SetValueForKey(new CIVector(bottomRight), new NSString("inputBottomRight"));
var ciImage = inputImage.CreateByApplyingOrientation(CGImagePropertyOrientation.Up);
ciFilter.SetValueForKey(ciImage, CIFilterInputKey.Image);
var outputImage = ciFilter.OutputImage;
var uiImage = new UIImage(outputImage);
imageList.Add(uiImage);
imageList is a List<UImage> since i'm handling multiple detected rectangles.
observation is a single observation of type VNRectangleObservation.
The cropped image generally seems to be the right size, but it is shifted up and to the left which cuts off the lower and right side of the document.
From Apple documentation CGImageCreateWithImageInRect , there is a discussion about the cropped size .
CGImageCreateWithImageInRect performs the following tasks to create the subimage:
It calls the CGRectIntegral function to adjust the rect parameter to integral bounds.
It intersects the rect with a rectangle whose origin is (0,0) and size is equal to the size of the image specified by the image parameter.
It reads the pixels within the resulting rectangle, treating the first pixel within as the origin of the subimage.
If W and H are the width and height of image, respectively, then the point (0,0) corresponds to the first pixel of the image data. The point (W–1, 0) is the last pixel of the first row of the image data, while (0, H–1) is the first pixel of the last row of the image data and (W–1, H–1) is the last pixel of the last row of the image data.
Then you can check in your local project with an image (size is : 1920 * 1080) as follow:
UIImageView imageView = new UIImageView(new CGRect(0, 400, UIScreen.MainScreen.Bounds.Size.Width, 300));
UIImage image = new UIImage("th.jpg");
imageView.Image = CropImage(image, new CGRect(0, 0, 1920, 1080), 1);
View.AddSubview(imageView);
The CropImage Method :
private UIImage CropImage(UIImage image, CGRect rect, float scale)
{
var drawRect = new CGRect(rect.X, rect.Y, rect.Size.Width, rect.Size.Height);
using (var cgImage = image.CGImage.WithImageInRect(drawRect))
{
if(null != cgImage)
{
var croppedImage = UIImage.FromImage(cgImage);
return croppedImage;
}
else
{
return image;
}
};
}
This will show the Original Size of Image :
Now you can modify the cropped size as follow :
UIImageView imageView = new UIImageView(new CGRect(0, 400, UIScreen.MainScreen.Bounds.Size.Width, 300));
UIImage image = new UIImage("th.jpg");
imageView.Image = CropImage(image, new CGRect(0, 0, 1920, 100), 1);
View.AddSubview(imageView);
Here I set x = 0 , y = 0 , that means from (0,0) to start , and width is 1920 ,height is 100 . I just crop the height of the original Image . The effect as follow :
Then if you modify the x/y ,the cropped image will move to other area to crop .As follow:
UIImageView imageView = new UIImageView(new CGRect(0, 400, UIScreen.MainScreen.Bounds.Size.Width, 300));
UIImage image = new UIImage("th.jpg");
imageView.Image = CropImage(image, new CGRect(0, 100, 1920, 100), 1);
View.AddSubview(imageView);
Then you will see it's different with the second effect :
So when cropping an image , you should understand the drawRect of image.CGImage.WithImageInRect(drawRect) clearly .
Note from doc :
Be sure to specify the subrectangle's coordinates relative to the original image's full size, even if the UIImageView shows only a scaled version.

PDF.js displays PDF documents in really low resolution/ blurry almost. Is this how it is?

I am trying to use PDF.js to view PDF documents. I find the display really low resolutions to the point of being blurry. Is there a fix?
// URL of PDF document
var url = "https://www.myFilePath/1Mpublic.pdf";
// Asynchronous download PDF
PDFJS.getDocument(url)
.then(function(pdf) {
return pdf.getPage(1);
})
.then(function(page) {
// Set scale (zoom) level
var scale = 1.2;
// Get viewport (dimensions)
var viewport = page.getViewport(scale);
// Get canvas#the-canvas
var canvas = document.getElementById('the-canvas');
// Fetch canvas' 2d context
var context = canvas.getContext('2d');
// Set dimensions to Canvas
canvas.height = viewport.height;
canvas.width = viewport.width;
// Prepare object needed by render method
var renderContext = {
canvasContext: context,
viewport: viewport
};
// Render PDF page
page.render(renderContext);
});
There are two things you can do. I tested and somehow it worked, but you will get a bigger memory consumption.
1 . Go to pdf.js and change the parameter MAX_GROUP_SIZE to like 8192 (double it for example) . Be sure to have your browser cache disable while testing.
You can force the getViewport to retrieve the image in better quality but like, I don't know how to say in English, compress it so a smaller size while showing:
// URL of PDF document
var url = "https://www.myFilePath/1Mpublic.pdf";
// Asynchronous download PDF
PDFJS.getDocument(url)
.then(function(pdf) {
return pdf.getPage(1);
})
.then(function(page) {
// Set scale (zoom) level
var scale = 1.2;
// Get viewport (dimensions)
var viewport = page.getViewport(scale);
// Get canvas#the-canvas
var canvas = document.getElementById('the-canvas');
// Fetch canvas' 2d context
var context = canvas.getContext('2d');
// Set dimensions to Canvas
var resolution = 2 ; // for example
canvas.height = resolution*viewport.height; //actual size
canvas.width = resolution*viewport.width;
canvas.style.height = viewport.height; //showing size will be smaller size
canvas.style .width = viewport.width;
// Prepare object needed by render method
var renderContext = {
canvasContext: context,
viewport: viewport,
transform: [resolution, 0, 0, resolution, 0, 0] // force it bigger size
};
// Render PDF page
page.render(renderContext);
});
enter code here
Hope it helps!
This code will help you, my issue was pdf was not rendering in crisp quality according with the responsiveness. So i searched , and modified my code like this. Now it works for rendering crisp and clear pdf according to the div size you want to give. `var loadingTask = pdfjsLib.getDocument("your_pdfurl");
loadingTask.promise.then(function(pdf) {
console.log('PDF loaded');
// Fetch the first page
var pageNumber = 1;
pdf.getPage(pageNumber).then(function(page) {
console.log('Page loaded');
var container = document.getElementById("container") //Container of the body
var wrapper = document.getElementById("wrapper");//render your pdf inside a div called wrapper
var canvas = document.getElementById('pdf');
var context = canvas.getContext('2d');
const pageWidthScale = container.clientWidth / page.view[2];
const pageHeightScale = container.clientHeight / page.view[3];
var scales = { 1: 3.2, 2: 4 },
defaultScale = 4,
scale = scales[window.devicePixelRatio] || defaultScale;
var viewport = page.getViewport({ scale: scale });
canvas.height = viewport.height;
canvas.width = viewport.width;
var displayWidth = Math.min(pageWidthScale, pageHeightScale);;
canvas.style.width = `${(viewport.width * displayWidth) / scale}px`;
canvas.style.height = `${(viewport.height * displayWidth) / scale}px`;
// Render PDF page into canvas context
var renderContext = {
canvasContext: context,
viewport: viewport
};
var renderTask = page.render(renderContext);
renderTask.promise.then(function() {
console.log('Page rendered');
});
});
}, function(reason) {
// PDF loading error
console.error(reason);
});`

KonvasJs: Image height and width lost when saving canvas stage to JSON string

I allow the user to upload an image to the canvas; when creating the Konvas.Image I set the height and width attributes based on the images naturalHeight and naturalWidth.
Upload Code:
function loadImageStep1(src) {
var imgKI = new Konva.Image({
x: 0,
y: 0,
name: 'step1-label',
id: 'step1-label'
});
layer1.add(imgKI);
stage.add(layer1);//Add layer to stage.
var layer1Img = stage.find('.step1-label');
var reader = new FileReader();
reader.onload = function(event) {
img = new Image();
img.onload = function() {
imgKI.image(img);
layer1.draw();
layer1Img.setAttr('width', this.naturalWidth);
layer1Img.setAttr('height', this.naturalHeight);
layer1.draw();
}
img.src = event.target.result;//event.target.result
layer1Img.setAttr('src', event.target.result);
}
reader.readAsDataURL(src);
return false;
}
When I save the canvas to a JSON string the image height and width is gone. I saved the Konva.Image object to a variable and added to the console log to verify that the attributes are present.
Screen Shot of Console Log
Here is the JSON string provided by the stage.toJSON() function; please note that the height and width for the "step1-label" image object is not present.
{"attrs":{"width":500,"height":667,"id":"label-maker","fill":"#ddd"},"className":"Stage","children":[{"attrs":{"id":"background","name":"background"},"className":"Layer","children":[{"attrs":{"width":500,"height":667,"fill":"#ffffff"},"className":"Rect"}]},{"attrs":{"id":"layer1","name":"layer1"},"className":"Layer","children":[{"attrs":{"x":100,"y":180,"name":"step1-label","id":"step1-label","src":"[REMOVED TO MAKE STRING SMALLER]","scaleX":"1.72","scaleY":"1.72"},"className":"Image"}]},{"attrs":{"id":"layer3","name":"layer3"},"className":"Layer","children":[{"attrs":{"id":"txtGroup1","name":"txtGroup1","draggable":true,"x":-5,"y":202},"className":"Group","children":[{"attrs":{"x":250,"y":333.5,"text":"Fine Dinning \nSpecial Preserve","fontSize":"50","fontFamily":"Great Vibes","fill":"#000000","name":"text1","id":"text1","align":"center","lineHeight":"1","fontStyle":"bold","offsetX":203.81988525390625},"className":"Text"}]}]}]}
Here is my work around for this issue. I had to get the image objects and add in the height and width to the JSON string. This is simple because we only allow two images to be added to the canvas.
function saveLabel($title, $continue) {
//Get current width, height and scale settings for the canvas. Use these values to reset once the canvas has beeen saved.
var currentWidth = stage.width();
var currentHeight = stage.height();
var currentXScale = stage.scaleX();
var currentYScale = stage.scaleY();
stage.setWidth(width);
stage.setHeight(height);
stage.scale({ x: 1, y: 1 });
stage.draw();
var $json = stage.toJSON();
//The Konvas library is dropping the height and width of the images when creating the json string, so we have to put them back in...
var layer1Img = stage.find('.step1-label');
var layer2Img = stage.find('.custom');
if (layer1Img.length) {
$json = $json.replace('"id":"step1-label"','"id":"step1-label","height":' + layer1Img[0]["attrs"].height + ',"width":' + layer1Img[0]["attrs"].width);
}
if (layer2Img.length) {
$json = $json.replace('"id":"custom"','"id":"custom","height":' + layer2Img[0]["attrs"].height + ',"width":' + layer2Img[0]["attrs"].width);
}
var $dataURL = stage.toDataURL('image/png');
//Set the canvas back to original settings now that it's been saved.
stage.setWidth(currentWidth);
stage.setHeight(currentHeight);
stage.scale({ x: currentXScale, y: currentYScale });
stage.draw();
saveLabelAjax($json, $dataURL, $title, $continue, label_maker, window.location.hash);
}
Is there something I'm missing in my code; am I setting the image attributes correctly?
I need the image height and width for a rotation function and when I load the canvas from the JSON the rotation functions doesn't work correctly because of this missing data.
I found why you have no width and height in JSON.
While converting a Konva.Node to JSON Konva is trying to make it as minimal as possible. For example, it does NOT save default values (for x and y in will be 0).
In you case width attribute of Konva.Image equals to the natural width of the native image you use. So it is useless in JSON.
When you restore a stage from JSON you will need just load native images and set them to Konva.Image instances.

Taking square photo with react native camera

By default the react-native-camera takes photos in standard aspect ratio of the phone and outputs them in Base64 png, if the Camera.constants.CaptureTarget.memory target is set.
I am looking for a way to create square photos - either directly using the camera, or by converting the captured imagedata. Not sure if something like that is possible with React Native, or I should go entirely for native code instead.
The aspect prop changes only how the camera image is displayed in the viewfinder.
Here is my code:
<Camera
ref={(cam) => {
this.cam = cam;
}}
captureAudio={false}
captureTarget={Camera.constants.CaptureTarget.memory}
aspect={Camera.constants.Aspect.fill}>
</Camera>;
async takePicture() {
var imagedata;
try {
var imagedata = await this.cam.capture();// Base64 png, not square
} catch (err) {
throw err;
}
return imagedata;
}
Use the getSize method on the Image and pass the data to the cropImage method of ImageEditor.
Looking at the cropData object, you can see that I pass the width of the image as the value for both the width and the height, creating a perfect square image.
Offsetting the Y axis is necessary so that the center of the image is cropped, rather than the top. Dividing the height in half, and then subtracting half of the size of the image from that number ((h/2) - (w/2)), should ensure that you're always cropping from the center of the image, no matter what device you're using.
Image.getSize(originalImage, (w, h) => {
const cropData = {
offset: {
x: 0,
y: h / 2 - w / 2,
},
size: {
width: w,
height: w,
},
};
ImageEditor.cropImage(
originalImage,
cropData,
successURI => {
// successURI contains your newly cropped image
},
error => {
console.log(error);
},
);
});

IOS drawing a simple image turns out blurry using Xamarin C#

I'm developing in Xamarin and would like to draw a simple circle with the text "CIRCLE" inside it and display that image in a UIImageView. The problem is that the circle and text appear very blurry. I've read a bit about subpixels but I don't think that's my problem.
Here's the blurry image and code, hoping someone has some ideas :)
UIGraphics.BeginImageContext (new SizeF(150,150));
var context = UIGraphics.GetCurrentContext ();
var content = "CIRCLE";
var font = UIFont.SystemFontOfSize (16);
const float width = 150;
const float height = 150;
context.SetFillColorWithColor (UIColor.Red.CGColor);
context.FillEllipseInRect (new RectangleF (0, 0, width, height));
var contentString = new NSString (content);
var contentSize = contentString.StringSize (font);
var rect = new RectangleF (0, ((height - contentSize.Height) / 2) + 0, width, contentSize.Height);
context.SetFillColorWithColor (UIColor.White.CGColor);
new NSString (content).DrawString (rect, font, UILineBreakMode.WordWrap, UITextAlignment.Center);
var image = UIGraphics.GetImageFromCurrentImageContext ();
imageView.Image = image;
The reason why it's blurry is because it was resized. That bitmap is not 150x150 (like the context you created), it's 333x317 pixels.
It could be because imageView is scaling it's image (there's no source code) or because of pixel doubling (for retina displays). In the later case what you really want to use is:
UIGraphics.BeginImageContextWithOptions (size, false, 0);
which will (using 0) automagically use the right scaling factor for retina (or not) display - and look crisp (and not oversized) on all types of devices.

Resources