Selecting Text In Images - Pure SVG, No JavaScript
Recently, I wanted to embed an photograph of a book page. I thought it would be nifty if the text from the page could be selected.
If you hover your mouse over this image, you should be able to select part of the text.
Ideally, it will look something like this...
It even works on Android (tried on Chrome, Opera, FireFox) and iOS 7.
So, how did I do it?
Originally, I was pointed to Project Naptha - it seems to do everything I want but is very JavaScript heavy and requires modern browser support.
I then turned to SVG - Scalable Vector Graphics.
The way I've done this is almost certainly wrong and I'd appreciate any advice about the proper way to render text in an SVG.
The first part is easy - displaying a PNG as the background to the SVG. In this case, I've taken the image and Base64 encoded it.
SVG<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns="http://www.w3.org/2000/svg"
version="1.1"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="566"
height="166"
>
<image xlink:href="data:image/png;base64,iVBORw0KGg...."
x="0"
y="0"
width="566"
height="166" />
The X & Y co-ordinates are from the top left. I've manually added in the height and width of the image.
Next, we add the text.
SVG <g fill-opacity="0">
<text
x="70"
y="45"
font-size="14"
font-family="serif"
textLength="415"
lengthAdjust="spacingAndGlyphs">
For nearly three years, between 1960 and 1963, MI5 and GCHQ
</text>
<text
x="42"
y="62"
font-size="14"
font-family="serif"
textLength="440"
lengthAdjust="spacingAndGlyphs">
read the French high grade cipher coming in and out of the French
</text>
...
</g>
</svg>
As you can see, I've grouped the text together in a <g> element. I've set the opacity to zero - so while they are on top of the image, they cannot be seen unless selected. I've also manually split the lines and placed them on the image. I've set a "textLength" so that they'll fit across the page and automatically adjust themselves if they're too long.
This is very imprecise and quite time consuming. To get a better idea of how accurate (or not) it is, here's the same image, with the opacity set to 0.5.
Close enough, but not brilliant.
Finally, I've had to reference the images via an iframe. Without doing that, I wasn't able to select the text. I'm not sure if that's a browser fault, or expected functionality.
If you can suggest a quicker and more accurate way of doing this - I'd love for you to leave a comment below.
Hong Xu says:
I think it is not necessary to use "iframe"---you can use "object" to achieve the goal.
Fraser Smith🏴 said on octodon.social:
@Edent Works in Wavebox which is a Chrome based client. That said, the text was black on a blue background so not particularly readable when selected.
stfn :raspberrypi: :python: said on fosstodon.org:
@Edent on iOS 15.7.8, both Safari and Firefox, I can only select the first line of text
Simon Brooke said on mastodon.scot:
@Edent It's a good idea and it works, but it's clearly a lot of work to set it up. It would be great to automate it!
Mike Coats 🏴🇪🇺🌍♻️ said on mikecoats.social:
@Edent It’s working grand in Safari on iOS 16.6.
You’d never guess there’s trickery in play unless you spotted the invisible character widths slightly diverging from the image’s text.
Shaun McDonald said on mastodon.green:
@Edent I just tried in Chrome on my Fairphone and it is unreliable selectable. The oil handles to change the selection are missing out elsewhere in the page.
Denny said on boing.world:
@Edent In Brave on Android, I can press and hold to select a single word, but not across a word boundary... except the one time it did, and (a) I can't work out how I did that and (b) it made the selection handles visually disappear (but I could still ask my phone to read the selection). Whut.
Simon Li said on hachyderm.io:
@Edent Android Firefox allows selecting text, but the start/end markers are misplaced