Printing a multi-page HTML5 canvas element - image

This is the first question I've ever asked on here, as normally I can find an answer that will solve all my problems. However, this week I've hit quite the wall.
I'm using a canvas on my page that's working great and can be saved as an image file. I've also created a button that will open the canvas in a new window for printing after using toDataURL. I'm using the code below:
function printable() {
var dataUrl = document.getElementById("mainCanvas").toDataURL("image/png");
var windowContent = '<!DOCTYPE html>';
windowContent += '<head><title>Print Map</title></head>';
windowContent += '<body>';
windowContent += '<img src = "' + dataUrl + '">';
windowContent += '</body>';
windowContent += '</html>';
var printWin = window.open('', '', width = 340, height = 260);
printWin.document.open();
printWin.document.write(windowContent);
printWin.document.close();
printWin.focus();
printWin.print();
}
This works great and opens the print dialogue to print my canvas image. My issue is that my image is larger than a single page and only the first page of my image prints. Is there any way to print my canvas across multiple pages, or should i just chalk this up to bad browser to printer functionality and get my users who need to print to use a different program after saving their canvas locally?
Thanks

there is a stupid solution, but definitely work.
use a script to split canvas, and put contents to several separate canvases.
use these functions:
ImageData getImageData(in float x, in float y, in float width, in float height);
void putImageData(in ImageData imagedata, in float dx, double dy, in float dirtyX Optional , in float dirtyY Optional , in float dirtyWidth Optional , in float dirtyHeight Optional );

Related

How to achieve high quality cropped images from canvas?

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

Finding size of images imported at runtime

I am currently loading images at runtime from directories stored in an XML file, and assigning them to RawImage components via the WWW class. While this is working fine, the image is skewed to fit into the new texture size.
I am wondering how to get an image’s original size or aspect ratio so that I can change the size of the image rect to suit. The images to be imported are at varying sizes and therefore the approach used needs to be responsive to the original size of imported images.
Any suggestions would be much appreciated. [Scripting in uJS]
Many thanks in advance, Ryan
function loadContextImage(texLocation : String)
{
if (!imageView.activeSelf)
{
imageView.SetActive(true);
}
var wwwDirectory = "file://" + texLocation; //this will probably need to change for other OS (PC = file:/ [I think?]) - **REVISE**
var newImgTex = new Texture2D(512, 512);
while(true){
var www : WWW = new WWW(wwwDirectory);
yield www;
www.LoadImageIntoTexture(newImgTex);
if (www.isDone){
break; //if done downloading image break loop
}
}
var imageRender : UI.RawImage = imageView.GetComponent.<RawImage>();
imageRender.texture = newImgTex;
}
If you cannot use an Image (for nay valid reasons), you can get the width and height of the texture:
WWW www = new WWW(url);
yield return www;
Texture2D tex = www.texture;
float aspectRatio = tex.height / tex.width;
rawImage.width = width;
rawImage.height = width * aspectRatio;
This should make the rect of the image of the appropriate ratio of the texture.
If you can use Image and preserveAspectRatio, you get it done by Unity. The result is not necessarily the same since it will keep the dimensions of the box and make the Sprite occupies as much space while keeping ratio.

iTextSharp: align image and text

I am using iTextSharp to export reports in PDF format. Reports' headers should have following format:
The problem is to align report header by center of the page, while there is an image on the left of the page. When I use a table, report header is aligned by center of its cell, not by center of the page. Is there a better approach?
EDIT:
Code for adding header is following:
var doc = new Document(pageSize, margins.Width, margins.Width, margins.Height, margins.Height);
using (PdfWriter.GetInstance(doc, destination))
{
doc.Open();
var headerTable = new PdfPTable(1){ WidthPercentage = 100 };
RenderHeader(headerTable); // adds several lines to headerTable
doc.Add(headerTable);
}
Do you really need a PdfPTable?
Why not add a Paragraph with the data that is right-aligned, followed by a couple of Paragraphs that are centered.
Then add the image at an absolute position, for instance:
Image img = Image.GetInstance(path_to_image);
img.SetAbsolutePosition(36, PdfWriter.getVerticalPosition(true));
document.Add(Image);
Another option is to add the Image in a table or a cell event instead of adding it straight to the table. Suppose that your PdfPTable consists of a single row and a single column, then you could define a cell event like this:
public class ImageCell : IPdfPCellEvent {
public void CellLayout(
PdfPCell cell, Rectangle position, PdfContentByte[] canvases
) {
float x1 = position.Left + 2;
float y1 = position.Top - 2;
float y2 = position.Bottom + 2;
PdfContentByte canvas = canvases[PdfPTable.LINECANVAS];
Image img = Image.GetInstance(path_to_image);
img.scaleToFit(10000, y1 - y2);
img.SetAbsolutePosition(x1, y2);
canvas.AddImage(img);
}
}
Suppose that cell is the PdfPCell with the date and the title, then you can do this:
cell.CellEvent = new ImageCell();
Note that in this case, the image will be scaled to the height of the cell.
Forgive me if the code doesn't compile right away, I'm writing this by heart (based on experience), I didn't test the actual code.

Fade in image when adding it to HTML5 canvas - Processing time concern

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.

How to tell if an image is 90% black?

I have never done image processing before.
I now need to go through many jpeg images from a camera to discard those very dark (almost black) images.
Are there free libraries (.NET) that I can use? Thanks.
Aforge is a great image processing library. Specifically the Aforge.Imaging assembly.
You could try to apply a threshold filter, and use an area or blob operator and do your comparisons from there.
I needed to do the same thing. I came up with this solution to flag mostly black images. It works like a charm. You could enhance it to delete or move the file.
// set limit
const double limit = 90;
foreach (var img in Directory.EnumerateFiles(#"E:\", "*.jpg", SearchOption.AllDirectories))
{
// load image
var sourceImage = (Bitmap)Image.FromFile(img);
// format image
var filteredImage = AForge.Imaging.Image.Clone(sourceImage);
// free source image
sourceImage.Dispose();
// get grayscale image
filteredImage = Grayscale.CommonAlgorithms.RMY.Apply(filteredImage);
// apply threshold filter
new Threshold().ApplyInPlace(filteredImage);
// gather statistics
var stat = new ImageStatistics(filteredImage);
var percentBlack = (1 - stat.PixelsCountWithoutBlack / (double)stat.PixelsCount) * 100;
if (percentBlack >= limit)
Console.WriteLine(img + " (" + Math.Round(percentBlack, 2) + "% Black)");
filteredImage.Dispose();
}
Console.WriteLine("Done.");
Console.ReadLine();

Resources