I would like to be able to automatically rotate an image based off of its text content so that the text will be displayed properly (vertically). I would prefer the language to be either Javascript or PHP.
Bad Example
Proper Example
For instance, GIMP and PS do it when importing a picture like such:
Q
How can I accurately auto rotate images with JS/PHP so that the text shows up properly (vertically, if you would)?
--NOTE--
I do not want to rotate based off of the "EXIF orientation" data, but rather by the orientation of the text in the image. Apparently the EXIF data only tracks the orientation the picture was taken in respects to the ground.
One possible solution I thought of would be to use OCR to detect characters in an image and test the image in all 4 orientations (rotated 90 degrees 3 times, in addition to original orientation). Whichever position returns the highest matched characters is most likely the proper orientation for the text.
One could use the following library for PHP: https://github.com/thiagoalessio/tesseract-ocr-for-php. In coordination with imagerotate(), one could find out the best orientation for the image based off of the amount of characters returned from OCR.
In Theory
require_once '/path/to/TesseractOCR/TesseractOCR.php';
$filename='path/to/some/image.jpg';
$photo = // create photo from $filename
$results = array();
for ($i=0; $i<4; $i++) {
$new = imagerotate($photo, $i*90, 0);
$new_path = // save the new rotated photo and get path
$tesseract = new TesseractOCR($new_path);
$results[$i] = strlen($tesseract->recognize());
}
/* Highest output is the best orientation for the image in respects to the text in it */
echo "Original Orientation: " . $results[0];
echo "Rotated 90 degrees: " . $results[1];
echo "Rotated 180 degrees: " . $results[2];
echo "Rotated 270 degrees: " . $results[3];
Pros
- Utilizes existing libraries (Tesseract with PHP wrapper, imagerotate php function)
Cons
- Computationally intensive. One image needs to be rotated 3 times & OCR 4 times
The solution you are asking for is not quite the same as your example. At first I thought you wanted a smart function that detected the text, but it is simpler than that with your example.
You need to look at the EXIF data. Fortunately, I have doe this multiple times. To correct an image that has been rotated, you can use the following function, which I wrote for correcting images taken on tablets/phones but will be displayed on computers. The input must be a filename for a JPG image.
function fix_image($filename, $max_dimension = 0)
{
$exif = exif_read_data($filename, 0, true);
$o = $exif[IFD0][Orientation];
// correct the image rotation
$s = imagecreatefromjpeg($filename);
if ($o == 1) { }
if ($o == 3) { $s = imagerotate($s, 180, 0); }
if ($o == 6) { $s = imagerotate($s, 270, 0); }
if ($o == 8) { $s = imagerotate($s, 90, 0); }
// export the image, rotated properly
imagejpeg($s, $filename, 100);
imagedestroy($s);
if ($max_dimension > 0)
{
$i = getimagesize($filename);
// reopen image for resizing
// Use the known orientation to determine if it is portrait or landscape
if ($i[0] > $i[1])
{
// landscape: make the width $max_dimension, adjust the height accordingly
$new_width = $max_dimension;
$new_height = $i[1] * ($max_dimension/$i[0]);
} else {
// portrait: make the height $max_dimension, adjust the width accordingly
$new_height = $max_dimension;
$new_width = $i[0] * ($max_dimension/$i[1]);
}
$s = imagecreatefromjpeg($filename);
$n = imagecreatetruecolor($new_width, $new_height);
imagecopyresampled($n, $s, 0, 0, 0, 0, $new_width, $new_height, $i[0], $i[1]);
imagejpeg($n, $filename, 100);
imagedestroy($n);
imagedestroy($s);
}
}
If the exif rotation is not acceptable you will likely need to do some image processing. This will never be 100% accurate. I am not sure the tessaract solution proposed by karns will work very well though since tessaract needs a fair amount of training and you might always encounter fonts you have not trained. Additionally, a comment on how to detect orientation of a scanned document? suggests that tessarct autorotates the image for text detection so you might get similar results on the rotated images.
An alternative is to use opencv via a php wrapper, e.g. https://github.com/mgdm/OpenCV-for-PHP (I have not used the wrapper myself). You can then do a line histogram for example pictures see the accepted answer on word segmentation using opencv. This way you can determine if the picture is horizontally or vertically oriented. Afterwards (and after possible correction of vertically oriented pictures) you could try to determine whether or not the text is upside down, google for detect upside down text one of the results, for example, suggests counting the dots in the upper and lower parts of a line. Again, this will never be 100% accurate.
Related
I am trying to convert my HTML code to image using Html2Canvas Library. In order to get a high-quality image in the result, I am using scale property with value 2.
html2canvas(element, {
scale: 2
}).then(function(canvas) {
getCanvas = canvas;
var imageData = getCanvas.toDataURL("image/png", 1);
var newData = imageData.replace(/^data:image\/png/, "data:application/octet-stream");
});
Now this newData is sent to php using AJAX and to save I use below code -
define('UPLOAD_DIR', 'assets/output_images/');
$image_parts = explode(";base64,", $_POST['ImageUri']);
$image_type_aux = explode("image/", $image_parts[0]);
$image_base64 = base64_decode($image_parts[1]);
$file_name = uniqid().'.png';
$file = UPLOAD_DIR . $file_name;
$success =file_put_contents($file, $image_base64);
But it always gives me the same image as it was with the scale with value 1 and there is no improvement in the final image.
NOTE: My div dimension is 369 * 520 and generated image size is always 369*520 with scale value 1 or 2 or 3 etc.
Thanks in advance
this just can't be... if you use bitmap image multiply size won't be better quality, but lower. You'll create fake pixels as copy of originals pixels at best.
For a real scale with image(with no quality loss) you've to use scalar image such SVG who won't be in CANVAS who use bitmap image but in the DOM as regular Elements.
Obviously you can use optionals parameters with
context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
where width and height will be final width and height in pixels(so no higher quality image just a larger size and a lower quality because pixels are multiplicated with fake pixels cloned form original size).
I hope i'be got your question fine.
edit: notice that to draw in canvas you've to create a image object such new Image('imagename.png'); at least but you can add the alt attributes and other stuff like an id or such. for more example source W3schools.org canvas.drawImage(...)
I have a page that is basically a large canvas with a lot of small icons connected with lines, and the user needs to be able to pan/zoom around. I've got everything working, but its very choppy. It seems that the repaining is the problem (if I remove the icons it becomes very smooth), but if I run Chrome's profiler, none of my functions are taking up any significant time at all.
Are there any better approaches to panning, without having to repaint everything? For instance in WinAPI, there was a function that scrolled the window content and only invalidated the thin region that just scrolled into view. Is there any way to do something similar in Javascript/canvas, since all I really need is to move the entire window?
I have tried making a giant canvas with everything pre-painted on it, that is then moved around with scrollLeft/scrollTop, but that takes way too much memory (what else should I expect from a 4000x4000 image) and makes zoom very slow instead.
Here's the page if anyone is interested, the code is pretty readable I hope:
http://poe.rivsoft.net/
You will have to just put up with some slower parts. Consider creating dirty regions. These are areas that need to be redrawn when panning. Keep a back buffer the same size as the canvas. When panning copy from the back buffer to its self the area that remains visible and mark the newly visible area as dirty. Then every frame rerender only the dirty areas onto the back buffer. For zooming you can zoom the back buffer and re render when the user pauses or incrementally, this will create a pixelated view (like google maps) when zooming in or aliasing and dirty areas on the sides when zooming out, until you update it.
You can also limit the amount of dirty area redrawn each frame so maintaining a constant frame rate. It will not look as nice but it will improve the panning and zooming. On my machine it runs well (nice job BTW) so you may want to consider implementing optimisations only on machines that can not handle the load.
Also looking at the function DrawNode there is lots of room for optimisation as you have a lot of redundant code (especially once all assets have loaded)
This is just a suggestion as I do not know if nodes are unique or if the x, y coords change, but that can be accommodated as well. You have a lot of searching and checks that should be avoided. The use of strings instead of numbers or booleans to check for status and type is also slow.
function DrawNode(ctx, node, x, y, active) {
// Has this node got quick render information
if (node.qNode) {
// if so render the quick version
var qn = node.qNode; // creating the var qn and then qn.? is quicker than access node.qNode.?
ctx.drawImage(qn.image, qn.coords.x, qn.coords.y, qn.coords.w, qn.coords.h, qn.x, qn.y, qn.size, qn.size);
return;
}
var type = NodeTypes[node.type];
var frameType = "frame" + (active ? "Active" : "Inactive"); // active should be a boolean
if (type && type.size && node.type !== "jewel") { // should be !node.isJewel with isJewwl a boolean
var spriteType = node.type;
if (node.type !== "mastery") // Should be boolean
spriteType += (active ? "Active" : "Inactive");
var sprites = SkillTree.skillSprites[spriteType][3];
var image = GetImage("Assets/" + sprites.filename);
var coords = sprites.coords[node.icon];
if (image && image.loaded && coords) {
ctx.drawImage(image, coords.x, coords.y, coords.w, coords.h,
x - type.size * 0.5, y - type.size * 0.5, type.size, type.size);
// add the information to quickly render the node next time.
// You may want to add sub objects for Mastery Active,inactive
node.qNode = {
image : image,
coords : coords,
x : x - type.size * 0.5,
y : y - type - sise * 0.5,
size : type.size
}
} else if (!image || !image.loaded) {
return false;
}
}
// same deal for the other type.
}
When optimising you start at the slowest point and make that code as efficient as possible, then work your way out. It is well written code but it has no eye for speed so I would say there is lots more room for improvement in the code.
I'm still a beginner at javascript, and I'm making a game about dying the whole screen white while the paint brush becomes smaller and smaller until in completely disappears.
I wanted to know, is there a simple way to figure out if the whole canvas has been painted, so I can put a winning screen?
I'm using the processing.js library, here is my code, if it's of any use:
background(255,0,0);
var eight = 100;
var draw = function(){
strokeWeight(eight);
point(mouseX,mouseY);
eight -= 0.2;
if(eight<0){
noStroke();
}
Here's a modestly efficient way of determining if the user has whited every pixel
Create an array where each canvas pixel is represented by an array element.
var pixels=new Array(canvas.width*canvas.height);
Initially fill the array with all zeros.
Create a variable that hold the # of unique pixels whited out so far.
var whited=0;
When the user passes over a pixel, see if the pixel has already been whited. If it hasn't been whited, change its array value to 1 and increment the whited variable.
var n = mouseY * canvas.width + mouseX
if(pixels[n]=0){
pixels[n]=1;
whited++;
}
You have a winner if the value of whited equals the number of pixels on the canvas.
if(whited==pixels.length){
alert('You have won!');
}
A thought: Instead of making the user find every (tiny) missed pixel, you might consider making a grid so the user has an easier time finding that 1 (larger) missed grid cell instead of finding one missed pixel in a sea of white.
You can go over all the pixels and check if they are not white
for (var i=0;i<imgData.data.length;i+=4)
{
if(imgData.data[i]==0&&imgData.data[i+1]==0&&imgData.data[i+2]==0&&imgData.data[i]+3==0){alert("white pixel")}
}
http://www.w3schools.com/tags/canvas_getimagedata.asp
Since you're using Processing, just walk over the pixels:
void setup() {
...
}
void draw() {
...
}
void yourCheckFunction() {
loadPixels();
boolean allWhite = true;
for(int c: pixels) {
if(brightness(c) < 255) {
// we found a not-white pixel!
allWhite = false;
break;
}
}
if (allWhite) {
// the paint surface is entirely white.
} else {
// there are non-white patches left
}
}
There are lots of ways to optimize this (like chopping up the surface into distinct areas with their own administrative true/false value so you can first check if they were all-white on a previous run, and if so, you don't need to recheck them) but this covers the basics:
assume the canvas is all white pixels
try to invalidate that assumption by finding a not-white pixel
immediately stop checking if you do
if there are none, your loop will end "naturally"
Alternatively, you can track how many pixels your user's action have painted. Once that number of pixels is equal to width*height, all pixels must necessarily be white (see markE's answer for that)
I remove some pixel with clearRect on mouse move on my 200x200px canvas element.
Now, I would like to check if there are no pixels left to remove (all 40.000px are removed), then reset or load a new image.
canvas.onmousemove = function(e) {
x = e.clientX - e.target.offsetLeft;
y = e.clientY - e.target.offsetTop;
context.clearRect(x, y, 20, 20);
}
There are two ways to detect if the canvas is blank:
Compare data-uris
Initially grab a string from the blank canvas before starting to draw to it. If you change the size of the canvas you also need to update this string.
var blankCanvas = canvas.toDataURL('image/bmp');
This will get a BMP (uncompressed) image in browsers which support this format, or default to PNG if not. Obtaining an uncompressed image will increase memory use but also performance when obtaining the string (but slow down when comparing it, if large).
Then do the same when you want to compare:
var currentCanvas = canvas.toDataURL('image/bmp');
if (currentCanvas === blankCanvas) {
/* it's empty */
}
Compare pixels
The only way is to iterate through the pixels to see if all the values are black transparent.
Here is one way: call this method every time you need to check (typically on mouseup event) -
function hasPixels() {
var idata = context.getImageData(0, 0, canvas.width, canvas.height),
buffer = new Uint32Array(idata.data.buffer), // use 32-bit buffer
len = buffer.length,
i;
for(; i < len; i++) {
if (buffer[i] !== 0) return true;
}
return false;
}
This will return true if there are any pixels remaining on canvas.
The 32-bit buffer allows us to check one complete pixel at the time and will perform better that comparing each component.
Notes
Both approaches require CORS requirements in relation to the images be fulfilled for this to work. This is a security mechanism in browsers preventing extraction of pixels from canvas cross-origin.
Which approach is faster depends on various factors such as the size of the canvas, browser implementation and so forth. You would need to check for your scenario. I would perhaps add a coin to the second solution for general usage together with the benefit of low resource consumption. But for a 200x200 canvas both should work well.
I do know about the case of float/integer values for drawImage's x and y. But what I need is a smooth animation with an ability to cache my shapes.
Article on caching complex paths with backup canvas
Article on drawImage with float parameters
For example, I want to draw some complex shape (i.e. SVG-tiger, converted to canvas-commands) to canvas just once and then move it smoothly with ctx.translate and ctx.drawImage. I need the float values then, because instead I get a step-by-step moving:
Here's the examples at JSFiddle:
One: Fast speed, with Math.floor applied to translate parameters (x and y are equal to time in seconds multiplied by 10): Animation is weird (sequential, not smooth).
Two: Slow speed, with Math.floor applied to translate parameters (x and y are equal to time in seconds): Animation is weird (sequential, not smooth).
Three: Fast speed, no rounding, float values (x and y are equal to time in seconds multiplied by 10). Speed is fast, so animation looks good.
Four: Slow speed, no rounding, float values (x and y are equal to time in seconds). Speed is slow, so animation looks pulsating. Why?
The last case is the one that confuses me. Am I wrong in my tryings and there is a possibility to make this caching trick work nice?
In Firefox, there is a property of canvas named mozImageSmoothingEnabled (see), but there is no help from that in other browsers. And it also removes paths smoothing.
Code extract:
var shapeCanvas = null;
var w = 320, h = 240;
var startTime = 0;
function start() {
startTime = Date.now();
var docCanvas = document.getElementById('canvas');
. . .
shapeCanvas = document.createElement('canvas');
. . .
drawShape(shapeCanvas.getContext('2d'));
drawNext(docCanvas.getContext('2d'));
}
function drawNext(ctx) {
var msec = (Date.now() - startTime);
var time = msec / 1000; // seconds passed from start
ctx.clearRect(0, 0, w, h);
ctx.save();
// the lines to change: time | (time * 10) | Math.floor(time * 10)
ctx.translate((time < 500) ? Math.floor(time * 10) : 500,
(time < 500) ? Math.floor(time * 10) : 500);
ctx.drawImage(shapeCanvas, 0, 0);
ctx.restore();
__nextFrame(function() {
drawNext(ctx);
});
}
function drawShape(ctx) {
. . .
}
I wrote the tutorial in your first link.
Just to clear the air:
shapeCanvas.style.width = w + 'px';
shapeCanvas.style.height = h + 'px';
is not really worth doing. No point setting the style if its just a in-memory canvas, and you shouldn't really ever want to set the width and height style of a canvas anyway, it just confounds things.
What ellisbben said in the comment is pretty much what's happening.
It's possible to get around it in a few hackish ways I bet. One way might be to make sure its never drawn on an integer pixel. Another might be to use ctx.scale(.99,.99) before drawing anything so it is always anti-aliased. It's tough to get a consistent solution here because different browswer's implementations of anti-aliasing are different.
Here are a few experiments from myself:
http://jsfiddle.net/KYZYT/29/
The first two are the shape drawn from a canvas and also drawn from a PNG
The second two are the same pair but scaled by .99,.99
The last one is the real thing. It still blurs a bit but looks a lot sharper than using the images.
None of my experiments lead to an end of your pulsating, at least not on a microscopic level. I think this is just something you're going to have to live with if you want to animate pixel-perfect images onto half-pixel spaces.
If you really feel you can't just draw on perfect pixels then your (second) best bet for consistency is probably to find a way to force anti-aliasing at all times. Making sure you are always translated to a non-integer or scaling it ever so slightly are decent candidates, but there may be others.
To be honest, you best bet is to not cache these animated paths until you absolutely need the performance from them. Cache the stylized buttons and other static things you make, but if you've got animated paths that need to move slowly and precisely and look very good, you might as well stick with the true thing over my caching optimization unless you really need it for those too.
Bit shameless plug but: I've implement smooth animation in HTML5 slot game with bit hacky way. The generated cached Image is drawn on small canvas once and then I used translate3d() with -moz-transform / -webkit-transform styles for the canvas to move, mirror and scale the image around.
Pregeneration
Create Image
Draw image content
Create canvas object in DOM
Animation phase
Clear canvas
Draw the cached image to the canvas
Use CSS3 transforms (scale3d and translate3d) to move canvas around.