Read a text in canvas, identify a location of text in canvas - javascript

I am working on a process flow. I have used vis library to show the flow. It shows the flow in canvas.
The flow is long and dynamically generated based on user input, so I have provided scroll inside canvas.
So to go to particular step, user has to scroll down. I want to provide search functionality in canvas to make it more user friendly.
Is there any way to provide search functionality in Canvas?

Do you mean character-recognition on existing canvas content (as in your image)?
It would be much easier to modify your vis library to emit {x:,y:,text:} objects for each step.
Character-recognition is possible but not practical.
I did a verrrrry simple proof-of-concept demo where:
The font-size and font-face is known.
The background is transparent except for the text.
Each character is surrounded by transparency.
The process went like this:
fillText a random "unknown" character on a "main" canvas.
On the main canvas, find the top-left set of opaque pixels which are surrounded by transparency. This set of pixels is the unknown character.
Copy only that unknown character on a second canvas.
Set compositing mode to destination-out.
Draw an 'A' onto the second canvas over the unknown character. The compositing mode will erase the opaque pixels of the unknown character.
Count the remaining opaque pixels on the second canvas.
If there are "very few" opaque pixels remaining then 'A' is likely the unknown character.
If there are "many" opaque pixels remaining then 'A' is probably not the unknown character. So repeat steps#3+ using the 'B' character (and then 'C, D, etc').
Refinements that helped recognition:
Remove any anti-aliasing on both the original main canvas and on each 'A, B, ...' character over-drawn.
When drawing the 'A, B, ...' to erase the original unknown character, draw the 'A' multiple times with a 1 pixel offset vertically, horizontally and diagonally. The offsets: [x+0,y+0], [x-1,y], [x+1,y], [x,y-1], [x,y+1], [x-1,y-1], [x-1,y+1], [x+1,y-1], [x+1,y+1].
Results
The darned thing worked fairly well -- he says with genuine self-surprise! :-O
Using 36 pixel Verdana font, the code recognized all of the characters from ! through ~ (most of the non-Unicode characters).
But ... The double-quote character was not recognized because it's the one Verdana character that is broken into 2 parts. Visually the double-quote looks like two single quotes separated by space. Step#2 found the left part of the quote but not the right part because of the transparent space.
This is not an effective OCR system ... it's barely a proof-of-concept!!
The font-size & font-face must be exactly known. Since font faces may differ between browsers (and even versions of browsers), the technique probably won't work well across browsers.
The recognition is only for text written on html5 canvas. If given a paper image, the "noise" in the paper will likely cause the technique to fail.
However, it was the basis for a fairly good pattern-matching algorithm where other clues help with the identification process.

Related

Is there an efficient way to make part of a text a different style on Canvas?

Some aspects of HTML5 and especially Canvas seem to have remain in the pre-word-processor software era, in the 60's when only typewriters existed.
(This issue) For one, you can't make a word or a sentence bold, or underline it inside a text on the same pass, simply and efficiently.
Filltext just fills canvas with a single piece of text and a single style and that's it.
(BTW, a second one is the lack of text-justifying function on both sides for canvas, so I had to made such a function myself using JavaScript.
A third, is a bug that prevents changing multiple custom fonts on subsequent canvas operations unless you have pre-use them(!) after initiation (I discovered that workaround after a lot of struggle).
So I'm thinking of two workarounds:
Locate the set of words you want to change the style, calculate the start x,y position and the total length using 'measureText', do the first pass replacing them with spaces, then do a second pass and only write those words with a different style inside the empty space.
Embed 2 or more styles on the same custom font and same language, like they were different languages in Unicode.
Is there another workaround?
I'm asking in case I'm missing something, or someone out there has a decent idea.

Are there W3C specifications for line wrapping behavior in an HTML <textarea>?

I'm working on a project to generate an image that replicates user-entered text input in a <textarea>. The best approach I've found is to read the <textarea>'s value and draw it on a <canvas>, from which I can read a blob and save to a file.
Here is a very naive example, just to give an idea of what I'm trying to do:
https://codepen.io/troywarr/pen/wmbMVq
Note that when the text that you enter in the <textarea> exceeds the length of the first line, the text in the <textarea> wraps, but the text on the <canvas> does not. That's the crux of the code that I still need to write, but first I need to fully understand <textarea>'s line wrapping behavior so that I can recreate it with a JavaScript algorithm.
By playing around with a <textarea> in Google Chrome, I've determined some basic behavior when a word exceeds the line width (as set by the rendered width of the <textarea>):
Words that are preceded by a space will wrap, and the width of the preceding space is not factored into the rendered width of the previous line.
Words that are hyphenated with a figure dash (‒, U+2012), en dash (–, U+2013), or em dash (—, U+2014) will wrap after the last hyphen that fits on the current line. I'm still exploring if there are other characters that hyphenate.
Words that exceed the total line width will be broken mid-word, with subsequent characters overflowing to the next line(s).
However, experience tells me that there are likely to be some edge cases and cross-browser functional differences that I haven't considered. I searched for specifications that describe how exactly <textarea>s should wrap text, but I haven't found any. The closest I've gotten is the spec for the wrap attribute, but it doesn't offer much help.
Is this behavior just dictated by different rendering engines (i.e., not W3C-specified), or am I just missing the W3C specification? If the former, what behavior have I missed, and what do I need to be aware of in terms of cross-browser functional differences?

Antialiasing text on canvas

I have to create .pngs for a lot of clients that are printed by an industrial inkjet (ads on back of a children's magazines).
Unfortunately, all browsers seem to switch on antialiasing - no matter what I try. Neither CSS nor ctx.mozImageSmoothingEnabled=false; seem to work.
Does anyone have any idea to get text displayed on canvas WITHOUT any grey-scaled pixels trying to make the font sharper?
The canvas will anti-alias everything drawn to it, with the exception of images when imageSmoothingEnabled is set to false (and then only for resampling purposes).
There are various options though -
SVG
Using SVG would be ideal as it is vectors and can be easily converted to postscript. If the printer supports postscript it will rasterize the vectors into the optimal raster-mask and make sharp edges.
Large bitmap
You can reduce the effect of anti-aliasing by using a very large bitmap, but from my own experience, and probably yours as well, it won't eliminate the gray points.
There is also the risk of meeting the limitation of canvas element itself which in some browsers is limited to 6k. Depending on the printer's DPI this may or may not be enough.
A combination of a large bitmap and threshold (see below) can perhaps get you around this though.
The Deep Dive implementation
Another way, but more advanced, to get around this is to load the font manually and draw the paths of it using Bresenham or similar algorithm. An additional aspect is that you would need to use polygon fill-algorithms as well (ie. even-odd or non-zero winding).
All this is doable without too much effort:
To load fonts and get the path data you can use f.ex. opentype.js
Use Bresenham or EFLA for rendering vectors to lines (if needed)
Use a polygon fill algorithm even-odd or non-zero winding to fill the polygons (you may get away with normal canvas fill if you can cover the edges with the Bresenham/EFLA lines).
As you are in print industry Open-Type may not be sufficient as Adobe fonts are more common from the typical repository. You can probably get the path data via other means or find the equivalent in an Open Type version or even a SVG font type.
Threshold
Another approach is to quantize the gray-levels. You can iterate over the bitmap and use a threshold value to set the pixel either transparent or solid color.
The result may not be so good as you will end up with some sharp transitions around some edges. You may however be able to reduce these artifacts depending on the print-resolution as well as the chosen threshold value.

How might I calculate the terminal column width of various characters?

I'm looking to calculate the number of terminal columns various printing and non-printing ascii/unicode characters will occupy in a terminal view.
For example, horizontal tab (\t) occupies 8 columns, color codes (i.e. \x1b32m) occupy 0 columns, and fixed-size wide-character strings (i.e. 한) might occupy 2 columns. Of course there are many in the primary ASCII set that only occupy 1 column (ie. a-Z/0-9, punctuation etc.).
I've come across the node.js module, wcwidth, that seems to help calculate wide-character strings, but doesn't do what I'd expect for other characters, like color codes, and tabs.
For example:
var wcwidth = require('wcwidth');
console.log("TAB WIDTH", wcwidth('\t'));
console.log("한 WIDTH", wcwidth('한'));
console.log("Color Code WIDTH", wcwidth('\x1b32m'));
console.log("X WIDTH", wcwidth('X'));
Outputs:
TAB WIDTH 0
한 WIDTH 2
Color Code WIDTH 3
X WIDTH 1
I can't seem to find any information about this anywhere, though I'd imagine it would be a common thing people have had to solve in the ancient past.
If there might be a way using a bash script, or any library, application or tool, I'm totally open to that as well.
Any help much appreciated! :)
Thanks
A tab does not occupy 8 columns. It outputs a single space and then enough spaces to ensure that the next character will be output at the next column whose index is 0 mod 8 (Or 1 mod 8 if you count from 1.) In other words, you cannot tell how wide a tab is unless you know where you are on the line.
A color code (\x1b[32m) might occupy zero space, but it also might not; it depends on the nature of the terminal emulator for the console. Most terminal emulators will recognize the CSI[Pm code but there are other codes which are quite a bit more idiosyncratic. For example,
printf $'\x1b]2;A window\x1b\\'
will set the window title in xterm, and hence will produce no output. But in a Linux console, the text ;A window will be displayed, occupying 9 characters.
In short, it is not so easy a problem, and you can only answer it with a lot of context because there is no absolute answer.
This is indeed an issue for any program that needs to know where the cursor is on screen, from tabular output in ls through editable command lines to full-screen applications. As you've noticed, it's not solved by wcwidth or wcswidth, which are defined only for (strings of) printable characters. (Even that is not well defined for many characters.) Also, control sequences can not only change colours but also cursor positioning and even, where supported, font size effects.
Instead, terminal control libraries such as ncurses [npm search] are sometimes used. These don't seem to tell you string widths either, but because they track text attributes such as colour separately, and generate control sequences themselves to position and style text, they provide some assistance in putting things on screen in given locations.
Unfortunately I don't believe there's much available beyond that, with applications either ignoring the complexities or handling them in ad hoc ways.
To clear up a common misconception: Horizontal Tab (HT, \t) doesn't have a width as such; it's a 'format effector', like Carriage Return or Form Feed, that repositions the cursor according to certain rules.
HT (Horizontal Tabulation): A format effector which controls the
movement of the printing position to the next in a series of
predetermined positions along the printing line. (Applicable also to
display devices and the skip function on punched cards.)
— USA Standard Code for Information Interchange [ASCII], 1968, as reprinted in RFC 20
The most common implementation is to have fixed tab stops every eight columns:
1 2
1.......9.......7.......5.....
1\tXYZ 1 XYZ
12\tXYZ 12 XYZ
1234567\tXYZ 1234567 XYZ
12345678\tXYZ 12345678 XYZ
123456789\tXYZ 123456789 XYZ
though some systems support control sequences or other ways to set the positions of the tab stops at arbitrary distances, like the ruler bar in some word processors.

how can I modify browser word wrap behavior?

I notice that when the browser (firefox, safari) wraps text, the space where it breaks to wrap (the last space of a line) gets turned into a zero-width space, i.e, when you create a mouse selection across multiple lines in a paragraph, the space where it breaks does not visibly show. Is it possible to change this behavior so that the breaking space retains its width?
Thanks!
It's a guess but I would say no. This is a fundamental way in which the browser works.
Yes, this is possible using a font where the zero-width space character is designed having the width of a normal space. You may use Fontforge to create own fonts or to modify existing fonts. It is free and mighty, but takes some time to get used too.

Categories