[HN Gopher] It's always been you, Canvas2D
___________________________________________________________________
It's always been you, Canvas2D
Author : rikroots
Score : 367 points
Date : 2022-03-04 12:09 UTC (10 hours ago)
(HTM) web link (developer.chrome.com)
(TXT) w3m dump (developer.chrome.com)
| est31 wrote:
| One canvas limitation I ran into was obtaining the _height_ of a
| given piece of text. Width is available, but height is not, so
| you can 't center some text vertically. Stack overflow tells you
| to use an "M" character as it has roughly the same width and
| height...
| slmjkdbtl wrote:
| Depends on your use case, in my case I'm using the font size as
| the height just fine, m.actualBoundingBoxAscent +
| m.actualBoundingBoxAscent or m.fontBoundingBoxAscent +
| m.fontBoundingBoxDescent also works for some cases.
| Matheus28 wrote:
| You can set the textBaseline if your intent is vertically
| centering it
| xemdetia wrote:
| This is actually a hard problem even for most font libraries as
| it requires 'execution' of the font and kerning to actually
| know the parameters. I'm not saying this is a good answer but
| this is a tricky problem outside just Canvas2D. E.g. sour,
| soup, slip, and shin are four words with different heights, how
| do each in turn play out? Most of the time this is external to
| the font library and is in the layout engine which is talking
| to the font rendering context the same way you are in a raw
| font library/canvas.
|
| To be honest this is one of the things that made web browsers
| and html so good is because it solves this problem really well
| compared to having to figure this out in native apps across
| languages the hard way.
| dvh wrote:
| Is there an easy way to make canvas always fill parent while
| retaining 1:1 pixel size (no blur). Currently I need to use
| various hacks.
|
| Basically just like normal div, it currently cannot be done in
| canvas because once you set c.width=c.clientWidth it starts
| interfering, so the only solution is extra div (relative, canvas
| absolute) and on resize update width and height). Also it should
| work in flexbox.
| MildlySerious wrote:
| I am not entirely sure if this is what you mean, on
| resize/orientationchange you set canvas.width and canvas.height
| to its clientWidth/clientHeight and redraw. Is that what you
| mean by hacks?
| rikroots wrote:
| The CSS Painting API[1] shows some promise in this area - it
| adds a (restricted) canvas to elements which always maintains
| the same size as the div element it's attached to.
|
| [1] https://developer.mozilla.org/en-
| US/docs/Web/API/CSS_Paintin...
| esprehn wrote:
| There's two ways (one which you mentioned):
|
| - Use a ResizeObserver and observe a wrapper element, then
| resize and redraw your canvas when it notifies you.
| https://developer.mozilla.org/en-US/docs/Web/API/ResizeObser...
|
| - Use a Paint Worklet. It hooks directly into the browser
| painting system, but has some limitations on what you can draw
| with the canvas today. https://developer.mozilla.org/en-
| US/docs/Web/API/PaintWorkle...
|
| You could also consider SVG instead of Canvas.
|
| There's no way to automatically resize and replay draw commands
| but scaled up like you're asking though.
| etimberg wrote:
| In chart.js we have a very complex solution for dealing with
| this. We've gone through a number of iterations, but settled on
| a using ResizeObserver. You also need to listen to
| `window.resize` to get notified about DPR changes which can
| happen when a browser window is dragged from one screen to
| another.
|
| https://github.com/chartjs/Chart.js/blob/master/src/platform...
| dvh wrote:
| >we have a very complex solution
|
| This is my experience as well, to do it correctly, it needs
| to get many minute details exactly right.
|
| They still developing canvas so my proposal is to forget
| about these extremely complex solutions and add new property
| to canvas that would make width/height same as client
| width/height (perhaps with one event to let canvas know it
| was resized).
| torginus wrote:
| Canvas2D is awesome, but generally speaking, when I built
| interactive stuff(in 2D), I either used SVG, or some library that
| used WebGL as a backed (even for 2D stuff), like PixiJS. That was
| the most reliable way to get the best performance across the
| largest amount of devices.
| throw_m239339 wrote:
| How about a native DOM Diff algorithm in the browser instead? I
| mean something actually useful for most front-end developers?
| This canvas2D stuff isn't, in the era of WebGL.
| leeoniya wrote:
| one [more] thing i want is to be able to retain canvas context
| settings when resizing the canvas. e.g. it's unreasonably _very_
| expensive to re-sync the lost ctx.font on every dragged pixel -
| this operation alone dominates my perf profiles. i have no idea
| why it should be so expensive once the font is already loaded /
| cached in mem.
|
| ctx.fillText() is the next perf killer :(
|
| maybe i can sacrifice some quality for speed during resize with
| the new ctx.textRendering, though.
|
| ...and one more thing. why is there no easy inverse of
| ctx.clip(), e.g. ctx.mask()? currently i think it requires
| resorting to awkward Path2D composition/cloning + evenodd
| ctx.fill() hacks:
|
| https://github.com/leeoniya/uPlot/issues/628
| Camillo wrote:
| Do you have a link to a Chrome bug report?
| leeoniya wrote:
| like a perf-related bug for ctx.font mutation? no.
|
| the actual behavior of context being reset during resize
| works as specced, AFAIK.
| Sawamara wrote:
| I am irrationally happy about this.
| contravariant wrote:
| Now hang on for a bit, I can vaguely understand what is going
| wrong with the ClearRect (though why it draws a line to the
| bottom right when the code just moves the pencil and draws a
| horizontal line is beyond me) but what on earth is with:
| canvas.width = canvas.width;
|
| That's worse than a code smell, that _reeks_. Adding a new
| function to clear the state is nice, but what on earth is going
| on?
| recursive wrote:
| I'd hate to hear what you think of the way I usually do it. On
| second thought, no check this out.
| canvas.width ^= 0;
|
| It's shorter and easier to type, and just as "clear".
| l30n4da5 wrote:
| > That's worse than a code smell, that reeks.
|
| Welcome to webdev.
| [deleted]
| ArtWomb wrote:
| I always avoided the canvas.width clear hack as well. It's just
| too weird.
|
| I simply fillRect with the background color in a method defined
| "clear".
|
| 2D games will forever be playable. A single round of SNES Super
| Ghouls & Ghosts is enough to humble even the top esports
| players of the day ;)
| mysteryDate wrote:
| Yup, we're aware and we're all ashamed
| bschwindHN wrote:
| I would guess that when a dimension is "changed" (in this case
| it's not changed, but it is assigned), the canvas is recreated,
| along with all its internal state.
| proto-n wrote:
| I was curious also, so went looking. Here are some relevant
| stackoverflow questions: [1], [2]. Basically, setting the width
| of the canvas to any value different than the current width
| clears the canvas, because it forces the browser to re-allocate
| the relevant bitmap. Current implementations don't check if the
| width value is different, just re-allocate the bitmap anyways.
| Hence the trick.
|
| [1] https://stackoverflow.com/questions/17522134/how-does-
| canvas...
|
| [2] https://stackoverflow.com/questions/2142535/how-to-clear-
| the...
| resonious wrote:
| Makes sense but smells like a massive oversight in the API
| design. Really? No "clear the bitmap" function?
| greggman3 wrote:
| there is clearRect
| SQueeeeeL wrote:
| Web dev is full of this kind of oversight (not defending
| it, it just has a lot of precedence)
| jakelazaroff wrote:
| There is now! Why it took so long is anyone's guess.
| jdashg wrote:
| Look first to the spec! The spec says don't check if
| different for canvas2d: https://html.spec.whatwg.org/multipag
| e/canvas.html#concept-c...
|
| > Whenever the width and height content attributes are set,
| removed, changed, or redundantly set to the value they
| already have, then the user agent must perform the action
| from the row of the following table that corresponds to the
| canvas element's context mode.
|
| > | 2d | Follow the steps to set bitmap dimensions to the
| numeric values of the width and height content attributes. |
|
| > When the user agent is to set bitmap dimensions to width
| and height, it must run these steps: > 1. Reset the rendering
| context to its default state. > 2. Resize the output bitmap
| to the new width and height.
|
| There's opportunity to reuse the previous surface and just
| clear the contents, but I'm not sure if this is done. (But
| the reset of state and clear are both mandatory for
| `.width=.width`)
| shadowgovt wrote:
| > Current implementations
|
| Yikes on a bike. Shit like this is how we end up with `typeof
| null === 'object'` forever baked into the spec.
| easrng wrote:
| and things like > typeof document.all
| < "undefined" > document.all.constructor <
| HTMLAllCollection
| Matheus28 wrote:
| That's a neat one! Never knew about it
| ninkendo wrote:
| Things like this are to be expected if you truly value
| "never break anyone, ever, even if everyone unanimously
| agrees something is bad" as an immutable goal of your
| software. Programming languages are especially important
| for this sort of philosophy... If you make a mistake and
| people rely on it, your mistake is now part of the way the
| language works, always and forever.
|
| My hot take: Software that doesn't take this approach isn't
| truly serious in the same way as software that does.
| Personally I'm glad for this level of discipline because at
| some point, there has to be a "bottom"... software that we
| have to rely on in order to make our own code work. Not
| everything gets to enforce deprecation/removal cycles,
| sometimes it just has to Always, Always Work.
| shadowgovt wrote:
| Totally agree. I think it's way too late to change out
| the behavior of `typeof`, but Canvas2D is young enough
| that it might be great if one or more browsers removed
| that optimization and _didn 't_ cause width = width to
| blank the canvas contents, so that people didn't come to
| rely on a bad API to solve a problem that has nothing to
| do with canvas width.
|
| ... of course, that would require extending the API with
| an _actual_ blanking function...
| beardyw wrote:
| Setting the width or height clears the canvas, so I guess it's
| just an ugly hack.
| greggman3 wrote:
| It's not really. The code smell is people using it to clear
| rather than using clearRect but the fact that setting
| canvas.width or canvas.height resets the canvas and even does
| so if the size is the same is good engineering IMO.
|
| It's consistent and so your code can know if it sets the size
| things will reset. It doesn't have to special case when you
| happen to set it to the same size.
| MatmaRex wrote:
| There are some getters and setters in the web APIs with cheeky
| side effects. Presumably this one causes the canvas to be re-
| created, or something. Here's another good one, try it in your
| browser console: location.href =
| location.href;
| tentacleuno wrote:
| Your trick doesn't work for me in Firefox 96 :)
|
| One more: If you set an image's src attribute to the same
| thing, it'll still reload the image. const
| image = new Image("/img.png");
| document.body.append(image); image.src = image.src;
| greggman3 wrote:
| It might not actually reload the image but it has to fire
| all the events as though it did otherwise code would hang.
| mysteryDate wrote:
| Yup. It's awful. We are aware and ashamed
| danielvaughn wrote:
| These are nice additions, but what I've _always_ wanted is proper
| a proper font measurement API. Right now, in order to measure the
| width of a line of text (for wrapping purposes), you have to
| render it offscreen and measure the pixels.
| deckard1 wrote:
| yes! I went through this a few years back. My god, what a pain
| in the ass. According to MDN, the TextMetrics API is fully
| supported by all modern browsers. Chrome added the necessary
| height support in version 87 it looks like. But the entire API
| is still marked as experimental. Maybe them moving Google Docs
| to canvas helped that out.
|
| Chrome also introduced the Local Font Access API. Which sounds
| like a privacy nightmare. You can get access to the font's
| actual byte data and render it yourself, bypassing the browser
| entirely. Sounds insane to me. Imagine trying to beat your
| browser or OS at font rendering, but doing it in JavaScript. I
| guess Adobe or Figma have deep enough pockets to try though.
| danielvaughn wrote:
| The TextMetrics thing is so confusing because the docs
| clearly say that it's supported, but I tried to use it as
| recently as last year, and it's definitely not working.
|
| edit: getting access to the font bits sounds enticing to me
| actually, because I'm kind of a masochist :)
| didip wrote:
| Say what you will about Canvas, but it is the only way to draw
| multiple million of points in a time series chart on a browser.
|
| SVG ain't gonna cut it.
| rikroots wrote:
| I'll add some of my thoughts about this article's take on latest
| Canvas2D developments.
|
| 1. ctx.roundRect() - is a nice addition to the 2D stable of
| shapes, fitting alongside other recent additions like
| ctx.ellipse(). I was a little disappointed that the example of
| how to achieve this using existing functionality relied on a set
| of .moveTo, .lineTo and .arcTo instructions; the article misses a
| trick by not mentioning that we can also use an SVG path.d string
| to define a Path2D object and use that to fill/stroke the shape.
| Note: I can't find mention of .roundRect() in the MDN
| documentation.
|
| 2. Canvas Conic gradients have been supported in both Firefox and
| Safari for a while now. Good to see it arriving in Chrome. To
| complete the set of gradients, it would also be nice to see
| support for ports of the CSS repeating-linear-gradient() and
| repeating-radial-gradient() into the Canvas API.
|
| 3. Text modifiers - text has always been an over-simplistic mess
| in the Canvas2D API. In theory a user should be able to use
| ctx.font to load a valid CSS font string (including all the
| supported font size lengths, etc) and have the text rendered as
| expected; sadly the implementations between various browsers are
| all over the place. In my dreams I hope that one day we will be
| able to set a width/justification and have the text string broken
| into lines while respecting those requirements. Browsers do it
| already for DOM/CSS layout and rendering - I wonder how difficult
| it would be to tap into that functionality rather than having to
| reinvent it for 2D canvases?
|
| 4. context.reset() - nice!
|
| 5. Filters - SVG filters are massively powerful, yet also
| difficult to master. We can already build some really complex
| filters in SVG and reference them in the Canvas2D context; I also
| like the way we can add CSS filter strings to the context (eg for
| a nice, easy-to-understand and performant blur effect). The
| article mentions a `ctx.filter = new CanvasFilter([])`
| construction, but I can't find CanvasFilter in the MDN
| documentation.
| jfk13 wrote:
| > 1. ctx.roundRect() ... Note: I can't find mention of
| .roundRect() in the MDN documentation.
|
| https://github.com/mozilla/standards-positions/issues/519#is...
| raised some questions about the addition of .roundRect(); I
| don't know if any firm decisions have been made.
| mysteryDate wrote:
| CanvasFilter is coming to MDN documentation, it's been a
| struggle... I promise it's part of the spec:
| https://html.spec.whatwg.org/multipage/canvas.html#filters
| mattdesl wrote:
| This is great to hear! I'm an artist and much of my work builds
| on Canvas2D, it's a simple API and provides a nice balance of
| features and constraints.
|
| I'd love to see more development on Canvas2D API and standards.
| There's a few things that are missing and/or not yet
| standardized:
|
| - Advanced text metrics and more reliable text loading
|
| - More robust high-resolution rendering, for example using
| Canvas2D to generate large 300 DPI prints
|
| - More control over line rendering, such as placement on polygons
| ("inside" / "center" / "outside"), stippling, variable thickness
| noelwelsh wrote:
| What I want to know (but am too lazy to look up (-: ) is do the
| text metrics return the width _and_ height of the text 's
| bounding box, or is still just one of them? Can't believe this
| oversight has existed for so long, but that's the way the web
| works.
|
| That said, I'm happy that canvas is getting some improvements.
| It's one of the more accessible ways to do fun things in a web
| browser.
| fatih-erikli wrote:
| It might be off-topic but it's worth to mention, there's a Path2d
| API which allows you to create a path and apply it to a canvas or
| check whether a specified point inside that path or not. It's
| useful when you want to do a collision detection. Point in
| polygon is a well-known problem and it might be a good idea to
| move it to the browser's context and trust.
|
| https://developer.mozilla.org/en-US/docs/Web/API/Path2D
| https://en.wikipedia.org/wiki/Point_in_polygon
| intrasight wrote:
| Does Flutter do it's rendering with Canvas2D?
| inDigiNeous wrote:
| Flutter uses Skia, which is also the actual 2D graphics
| implementation behind canvas functionality in Chrome and
| possibly in Firefox and Safari IIRC.
| atum47 wrote:
| I use Canvas constantly and I love it. Thanks for the hard work
| maintaining it.
| theK wrote:
| What I am curious about is, is this part of a spec or are these
| APIs part of the proprietary Chrome Web?
| robertoandred wrote:
| > This feature has been in Firefox for a while and we're finally
| making it part of the canvas spec.
|
| The Chrome team still doesn't understand that they do not define
| the web.
| mysteryDate wrote:
| The spec defines the web
|
| https://html.spec.whatwg.org/multipage/canvas.html#the-canva...
|
| The "we" in the statement is the maintainers of the spec, which
| includes engineers from Chromium, Firefox, Safari, Edge, Opera
| and many other stakeholders.
| robin_reala wrote:
| Shame there was no mention of enhanced fingerprinting protection.
| But a nice set of Chrome improvements regardless, even if some of
| it is catchup.
| ninkendo wrote:
| Are there any easy ways to try out drawing on a canvas in
| TypeScript, with full type annotations for the Canvas2D API so
| that I can get nice autocompletion and an easy ability to browse
| the API?
|
| I like the idea of creating drawings directly in javascript even
| for my own purposes, but it'd be great if I had a type system to
| help me get my code right the first time...
| robinduckett wrote:
| https://kernhanda.github.io/tutorial-typescript-canvas-drawi...
| lloydatkinson wrote:
| I was wondering the same
| moron4hire wrote:
| It's in lib.dom.d.ts already.
| FpUser wrote:
| >"Surprisingly, SpaceX Senior Software Engineer Sofian Hnaide
| revealed that all of the user interfaces on the Dragon Capsule
| run using Chromium, the open source backbone of the ever-popular
| Google Chrome internet browser."
|
| Wow, I would never expect something like this. But I guess they
| know better about reliability of their particular solution.
| mateo1 wrote:
| >But I guess they know better about reliability of their
| particular solution.
|
| I wouldn't be as sure as you are.
| stupendousyappi wrote:
| I assume these are all currently non-standard APIs that Firefox
| will nonetheless be expected to implement? Does Firefox ever
| force work on the Blink team, or it is it only ever the other way
| around?
| dmitriid wrote:
| and Safari.
|
| Cue in "bad browsers don't implement APIs" in 3... 2... 1...
| mysteryDate wrote:
| These are all part of the official spec:
| https://html.spec.whatwg.org/multipage/canvas.html#the-canva...
|
| Getting the features into the spec is the vast majority of the
| work. Though some features are not yet implemented in Firefox
| or Safari, they have both indicated their intention to do so.
| funstuff007 wrote:
| when people look back at the 2020's, will they be like "Ew
| gradients?"
|
| That's not to say I don't like them, but I find them to be
| extremely overused, and making them even easier to use...
| swalls wrote:
| And then in 2040, people will rediscover gradients and for a
| while they will be overused. It's just design trends.
| khalby786 wrote:
| >canvas.reset()
|
| took you long enough
| etimberg wrote:
| Great to see conic gradients! Otherwise, you need to do solutions
| like https://everttimberg.io/blog/js-circular-gradient/
| samwillis wrote:
| Can we use these yet?
|
| ctx.createConicGradient() - 15.15% of users (Firefox since 90 and
| Safari since 15, not yet in Chromium/Blink without `new-
| canvas-2d-api` flag)
|
| https://caniuse.com/?search=createConicGradient
|
| Not found on "Can I Use":
|
| - All text modifiers
|
| - ctx.roundRect()
|
| - context.reset()
|
| - CanvasFilter
|
| - contextlost/contextrestored
|
| Anyone know when these will be available in browsers?
|
| Looks like in chrome they are all under the `new-canvas-2d-api`
| flag:
|
| https://chromestatus.com/feature/6051647656558592
| JKCalhoun wrote:
| _New_ is always frustrating.
|
| Instead I'll write my own _context.reset_bogus()_ that simply
| calls _canvas.width = canvas.width_
|
| Same for round rect. Some of the other features though ... not
| so simple, ha ha.
| mysteryDate wrote:
| These are all available as of Chrome M99! Thanks for reminding
| me to update caniuse!
| geewee wrote:
| What about all the other browsers?
| mysteryDate wrote:
| So, these functions are are now currently part of the
| whatwg spec, so other browsers have stated their intention
| to implement them and this is underway.
| geewee wrote:
| Wonderful!
| brightffw wrote:
| jiripospisil wrote:
| The old fart in me just wants a way to turn all of this off.
| danShumway wrote:
| :) Good to see web news that appears to be at first glance just
| straightforwardly good news and uncontroversial. In particular,
| I'm really excited to see `willReadFrequently` on this list.
| Particularly for games, canvas caching is a huge deal.
|
| And holy crud, rounded rectangles! It doesn't fundamentally
| change anything, it just means I don't need to write a helper
| method for literally every project I make that uses them. It's a
| tiny thing, but I'm grateful for the people working on that.
| mwcampbell wrote:
| > Rounded rectangles: the cornerstone of the internet, of
| computing, nigh, of civilization.
|
| That isn't wildly exaggerated if this story is true:
|
| https://www.folklore.org/StoryView.py?story=Round_Rects_Are_...
| tannhaeuser wrote:
| You laugh, but actually in the 90s rounded rectangles were a
| must to portray your site/app as "modern" (and signify you
| didn't bother to give it basic usability like desktop apps have
| so you could spare that part for your MVP).
| tonyedgecombe wrote:
| The funny thing is as soon as CSS supported them directly
| they went out of fashion.
| btown wrote:
| Say that to practically every interface element in iOS,
| Slack, and WhatsApp! They're just out of fashion in other
| parts of the web!
| Nadya wrote:
| Same thing with gradients in forum design. The moment we
| could use CSS instead of a gradient handcrafted with a
| pirated version of Photoshop - gradients stopped being
| commonly used in forum skins.
| DonHopkins wrote:
| I would love to have a CanvasFilter that makes your
| smooth 24 bit procedurally generated gradients look like
| they've been error-diffusion dithered to an 8 bit web
| safe color palette. And with a FatBits option to
| compensate for retina displays. Now THAT would be
| fashionable!
| rikroots wrote:
| > makes your smooth 24 bit procedurally generated
| gradients look like they've been error-diffusion dithered
| to an 8 bit web safe color palette
|
| Do you mean the gradient's output should look like it's
| been put through a risograph printer? I created a CodePen
| demo a while back which attempts to recreate that sort of
| effect - https://codepen.io/kaliedarik/pen/RwgwpyG
|
| When it comes to reducing a palette from (potentially)
| millions of colors down to a set of 8 bit web safe colors
| - I'm not convinced such a process can generate decent
| output for a wide range of different inputs. I get much
| better results by generating a "commonest colors" palette
| with a minimal distance (in LAB color space) between each
| selected color to generate the most pleasing dithered
| output, whereas restricting the palette to web-safe
| colors limits the output to just a handful of those
| commonest colors. See an interactive example of the
| filter here:
| https://scrawl-v8.rikweb.org.uk/demo/filters-027.html
| DonHopkins wrote:
| Oh I wasn't looking for decent output, I LOVE the
| pixelated error-diffusion dither effect, especially with
| an ugly garish color map that brings out all the jiggly
| artifacts. ;)
|
| https://donhopkins.com/home/CAM6/
| rikroots wrote:
| Oh, nicely done! Trying to code up cellular automata
| simulations are pretty much guaranteed to push my brains
| through my nostrils - I've never progressed far beyond
| classic Conway. Your CAM6 library[1] may be about to
| steal my weekend from me!
|
| [1] - https://github.com/SimHacker/CAM6
| keithalewis wrote:
| Like triangular wheels are an improvement over square wheels,
| one less bump!
| agys wrote:
| A very annoying part of the Canvas API is that colors are
| represented as (CSS) strings, except for the pixel array,
| obviously. This forces to write code like this:
| const fillColor = `rgb(${r},${g},${b})`
|
| For the rest: long live the Canvas! <3
| mysteryDate wrote:
| TypedOM CSSColor is coming soon!
| batterylow wrote:
| Canvas is great - I've been using it as a fallback for those who
| don't want to use webgl (regl) on some of the plots on PlotAPI
| and PlotPanel, e.g.
| https://plotpanel.com/explore/view/0568f7a0-8ef8-4ef3-8bd4-b...
| seanalltogether wrote:
| Is this standard coordinate ordering for canvas functions?
| ctx.roundRect(upper, left, width, height, borderRadius);
|
| Every graphics framework I've ever worked with uses (x, y, width,
| height) ordering, not (y, x, width, height)
| mysteryDate wrote:
| Oh, this is just yet another mistake we didn't catch. It's
| totally x before y. facepalm
| mcintyre1994 wrote:
| These changes look really nice! Out of interest does anyone know
| what the most common use cases for canvas are? The article says
| "30-40% of web pages have a <canvas> element" which is way higher
| than I'd guess. Is it used by ad networks or something like that
| that could increase the percentage a lot?
| mattdesl wrote:
| Probably the majority of these would use Canvas2D for a mix of:
| fingerprinting, tracking/ad tech, feature detection, font
| metrics, CPU rasterization & pixel manipulation. Occasionally
| it will be used for specific elements, games, artworks,
| animations, font rendering, video effects, image resizing, and
| sometimes entire applications (Figma, Google Docs, Google Maps,
| although they likely all use WebGL Canvas for performance &
| control).
| ewalk153 wrote:
| > Is it used by ad networks[...]?
|
| It's gotta be this. This article is about increasing awareness
| of canvas. It wouldn't be needed if 30-40% of sites were
| knowingly using the tag.
| mysterydip wrote:
| I'd like if there was a "mode 7" style affine transformation
| available, but I understand my needs are niche. Still, nice to
| see some of the performance improvements and that reset function.
| JKCalhoun wrote:
| Had to look that one up.
|
| Seems like you could implement your own in code. It would not
| be fast though -- having to walk each pixel in the canvas
| buffer, apply the transform to grab a pixel from another
| buffer, then assign the transformed buffer back to the canvas.
| rikroots wrote:
| I, too, had to look it up. This is about adding a (pseudo)
| perspective effect to the 2D canvas yes? There is an open
| issue in the whatwg/html repo[1] asking for this
| functionality - I have no idea whether the request will be
| taken forward by any browsers.
|
| The current solution is to "roll your own" functionality. It
| is doable - for instance I've added such functionality to my
| canvas library[2]. The results work, but are slower than
| ideal.
|
| [1] - https://github.com/whatwg/html/issues/5620
|
| [2] - https://scrawl-v8.rikweb.org.uk/demo/dom-015.html
| mysterydip wrote:
| yes correct. I've seen a couple done but like you and the
| other poster said they're slower than ideal.
| mysteryDate wrote:
| AHHHHHH! We wanted to add this so badly! Wrote the code and the
| spec and everything!
|
| Unfortunately Safari said it would be too much effort on their
| end to change the 2x3 matrices on the backend to 4x4 matrices
| to support this.
| mysterydip wrote:
| glad to see I'm not alone. Sucks to hear the outcome, thanks
| for trying. Maybe someday :)
| mysteryDate wrote:
| Look the proposal's still here!
|
| https://github.com/fserb/canvas2D/blob/master/spec/perspect
| i...
|
| If you raise an army of angry webdevs to yell at other
| browser implementers, I would be so very happy.
| whywhywhywhy wrote:
| Still no way to properly turn off antialiasing?
|
| (All the ways you find via google don't actually work and you
| need to write your own drawing engine to do it properly)
| rikroots wrote:
| Have you tried ctx.imageSmoothingEnabled (boolean) and
| ctx.imageSmoothingQuality (string: 'low' | 'medium' | 'high')?
| From my experiments the iSE value seems to be respected across
| modern browsers, but the iSQ appears to be ignored.
|
| There's also the ctx.smoothFont (boolean) value but I've not
| yet discovered a browser that cares about implementing it.
|
| Demo: https://scrawl-v8.rikweb.org.uk/demo/canvas-058.html
| whywhywhywhy wrote:
| You need that as well but it won't make canvas draw lines and
| circles fully aliased.
|
| Have to completely reimplement those algorithms last time I
| tried.
| amelius wrote:
| > 30-40% of web pages have a <canvas> element
|
| Yes, for fingerprinting /s
| neverartful wrote:
| Can you name a website that uses canvas for fingerprinting? I'm
| not doubting it's use for that, but would like to see a real
| example.
| GlitchMr wrote:
| Google, Facebook, Reddit, Amazon, TikTok. I entered main
| pages of those websites, and they tried reading pixels of an
| invisible canvas for whatever reason.
| [deleted]
| mysteryDate wrote:
| A legitimate point! Unfortunately from our end it's also
| impossible to tell what canvases are being used for. Somewhat
| reassuringly, the vast majority canvases that are being created
| are much larger than would be necessary for fingerprinting, so
| we have some reason to believe that most uses are legitimate.
| There's also the fact that the vast majority of canvases never
| perform `getImageData`, which is an essential part of every
| fingerprinting technique I've ever seen.
|
| At this point it's possible to fingerprint with CSS alone, no
| javascript: https://css-tricks.com/css-based-fingerprinting/
|
| So to say that canvas is an element "for fingerprinting" I
| think is an outdated notion that's the result of some bad PR
| the element got like 10 years ago.
|
| So, yes, fingerprinting is an issue and we all wish it would go
| away. Unfortunately there is a ton of work to do. A lot of very
| smart people are working on this and I wish them the best of
| luck.
| rasz wrote:
| > Unfortunately from our end it's also impossible to tell
| what canvases are being used for.
|
| you mean trivial, right? calling getImageData toBlob
| toDataURL means fingerprinting.
| willbudd wrote:
| I guess it didn't occur to you that retrieving and setting
| image data with getImageData()/putImageData() actually turn
| out to be indispensable features when generating complex
| multi-layer canvases. Your trivial heuristic would flag a
| lot of false positives.
| gruez wrote:
| >At this point it's possible to fingerprint with CSS alone,
| no javascript: https://css-tricks.com/css-based-fing
|
| Fingerprinting isn't a boolean state. The more fingerprinting
| vectors you have the more reliably you can identify users.
| Therefore having CSS fingerprinting (or any other
| fingerprinting vector) doesn't really make canvas
| fingerprinting less bad.
| mysteryDate wrote:
| True. Any data the user leaks is data the user leaks and we
| should work to prevent this. However I don't think people
| realize just how easy it is to reliably fingerprint users
| who are blocking javascript and canvas and other web
| features.
| gruez wrote:
| >how easy it is to reliably fingerprint users who are
| blocking javascript and canvas and other web features.
|
| The key difference is that most of the fingerprinting
| attributes listed in the article, most are very innocuous
| and/or easy to change (ie. unreliable for
| fingerprinting). That includes:
|
| 1. pointer type
|
| 2. prefers-color-scheme
|
| 3. window size
|
| 4. @supports
|
| The only other one (local fonts) is interesting, but is
| still easily changeable and conceivably be mitigated by
| removing all non-default fonts. This is in contrast to
| canvas/webgl fingerprinting which fingerprints both the
| software and hardware parts of your rendering stack, and
| is nearly impossible to change.
| MomoXenosaga wrote:
| Oh I realize. I also realize literally nobody is going to
| bite the hand that feeds and that this industry is never
| going to regulate itself.
| VikingCoder wrote:
| In the future, everyone is using a 640x480 window into a
| browser that's completely software stack in a VM that
| runs at a regulated frequency with a specifically
| allocated amount of RAM and hard drive space, doesn't
| accept cookies, and clears cache after every page load.
| azangru wrote:
| Pardon my ignorance, but how do you do this with canvas? I
| heard of using a 1x1px image for tracking purposes, but not of
| canvas.
| square_usual wrote:
| https://en.wikipedia.org/wiki/Canvas_fingerprinting
| azangru wrote:
| Thanks
| [deleted]
| Etheryte wrote:
| The canvas element is great for basic fingerprinting because
| it's practically impossible to stop it without breaking
| legitimate use cases. Shortly explained, there's differences
| between text rendering in different operating systems,
| browsers, and between browser versions as well. A simple
| fingerprint would be then to render some text, convert the
| canvas to an image and then hash it. Modern fingerprinting
| approaches combine this with a number of other sources of
| data (such as WebGL, available fonts, etc) to uniquely
| identify users.
| brightball wrote:
| Reminds me of evercookie.
| seanw444 wrote:
| So stupid. You know what would be nice? If my processor
| _didn 't_ attempt to do a bunch of rendering and extra
| computation, costing more energy and wear, to spy on me.
| Without eliminating legitimate use cases.
|
| For now, eliminating legitimate use cases will have to do.
| neverartful wrote:
| How would you prevent use of canvas? Browser plugin?
| Proxy filter?
| shadowgovt wrote:
| This problem could also be solved by making the specs so
| rigid and implementations so constrained that none of
| these techniques could be used to differentiate one user
| agent from another.
|
| For many reasons, the lesser of two evils is probably to
| make user agent differentiation possible. The number of
| apis one has to cut out to make it impossible basically
| rolls HTML back to the 1.0 with no JavaScript era.
|
| Implementation details of the machine rendering a
| document leak through all over the place. The fact that
| they are allowed to vary while confirming to spec has
| historically been considered a feature of HTML rendering,
| not a bug.
| XCSme wrote:
| 1x1px is for sending data to a server (by passing info in the
| image request URL)
|
| Canvas fingerprinting is done by generating unique(ish)
| strings based on slight variations in how Browsers/CPUs/GPUs
| render stuff.
| croes wrote:
| Fingerprinting not tracking pixel
| square_usual wrote:
| Why /s? You're right!
| marcosdumay wrote:
| He's not completely right. Some of those sites have real
| reasons to use a canvas.
|
| He's only ~99.9% right.
| egberts1 wrote:
| of which, /s serves us well.
| donatj wrote:
| I came here precisely to say 30-40% of websites seems
| remarkably high.
|
| The number of actual canvas elements used as canvases I've
| noted in the wild is pretty small. I've been playing with the
| canvas element since it was a Safari exclusive they added to
| make building dashboard widgets more powerful, and I can
| probably say the number of times I've found them actually
| useful in building a site is on one hand.
|
| I think you're right that most of them are probably for
| fingerprinting.
| chrismorgan wrote:
| I flat-out don't believe feature usage statistics on the web
| for this kind of reason, because too many numbers are patently
| absurdly wrong as far as any kind of _legitimate_ use is
| concerned, and so any time I see an element or attribute
| occurring more often than I'd expect, I just assume some
| widely-deployed script like Google Analytics that I almost
| certainly don't want is using it, probably for fingerprinting.
| darepublic wrote:
| I appreciated the humorous tone of the article
| simonsarris wrote:
| I have been building a Canvas diagramming library since 2010
| (https://gojs.net), if anyone has any questions about 2D Canvas
| use in the real-world I'd be happy to answer them.
|
| roundRect is great. Though you don't need 4 arcTo in order to
| make a rounded rect, you can use bezier instead (we do). Their
| example is also 1% amusing because they set the `fillStyle` but
| then call `stroke` (and not `fill`). I'll have to do some
| performance comparisons, since that's the operative thing for my
| use case (and any library author).
|
| text modifiers are very welcome. It's crazy how annoying
| measuring still is, especially if you want thinks to look
| perfectly consistent across browsers. Though the chrome dominance
| is making things easier in one way, I guess.
|
| context.reset is kinda funny. Most high-performance canvas apps
| will never want to use it. For that matter you want to set all
| properties as little as possible, especially setting things like
| context.font, which are slow even if you're setting it to the
| same value. (Or it was, I haven't tested that in several years).
|
| I'm sure most users know this by now, but generally for
| performance the fewer calls you make to the canvas and the
| context, the beter. This is even true of transforms: It's faster
| to make your own Matrix class, do all your own matrix
| translation, rotation, multiplication, etc, and then make a
| single call to `context.setTransform`, than it is to call the
| other context methods.
|
| One of the greatest things to happen to 2D canvas in all these
| years was hardware acceleration. It used to be significantly
| slower. (You could switch to WebGL canvas, but at a cost of
| complexity and all kinds of annoyances rendering text, and if you
| had a lot of text it often wasn't worth it.) Thinking back, I'm
| also a little disappointed that after the death of Flash, it felt
| like Canvas never _really_ took its place. The playful web that
| came before it in some ways simply closed up.
| inDigiNeous wrote:
| Interesting to hear about that doing the matrix translations on
| the js side are faster. Have you benchmarked this recently ?
| Will have to test it out myself, was under the naive impression
| that the underlying implementation would be optimal.
| simonsarris wrote:
| Imagine something like: var transform =
| ...your own data structure transform.scale(zzz);
| transform.rotate(zzz); transform.translate(zzz);
| transform.scale(zzz); // perhaps as many as 50 as you
| go down the visual tree ctx.setTransform(use your
| data structure to set these values);
|
| This is a _little_ faster than calling all the corresponding
| methods on ctx. Of course you gotta implement a transform
| class.
|
| And of course it becomes meaningfully faster if you are
| drawing a large number of objects in a visual tree, and their
| locations do not all change, so you can save these transforms
| that you've created, and then the only thing you are doing in
| the draw loop is a single call to `ctx.setTransform` instead
| of all the calls you'd normally need. Again this really
| depends on what you're doing, but you can imagine for drawing
| the visual tree of a diagram, it can be quite an improvement.
| tuckerpo wrote:
| hey it's the twitter homestead photography guy. nice house,
| nice software too.
| Trufa wrote:
| I actually do if you have the time thanks!
|
| Whenever I'm trying to draw curved lines, I always have issues
| with how they look, they seem to look low quality/pixelated.
|
| Like here: https://developer.mozilla.org/en-
| US/docs/Web/API/CanvasRende...
|
| In the most basic examples they seem to always produce curves
| like this.
|
| Sorry I don't have more specifics since it's a project I'm not
| actively working on right now but it was a spine that I never
| removed.
|
| If the questions is too broad, please let me know!
| simonsarris wrote:
| 99% the problem is one of _pixel density._ That is, you have
| a 400x400 canvas, and a 400x400 CSS pixel space you are
| drawing it to, but your devices pixel ratio is higher than 1,
| so it looks kinda blurry. This is because devices squish more
| than one "hardware pixel" per CSS pixel. Often at a ratio of
| 1.5 or 2, or higher.
|
| The solution is to make a larger canvas, say, 800x800 and put
| it into that 400x400 space.
|
| Here is an example, using that MDN code, with a 400x400
| canvas (red) next to a 800x800 canvas (blue). CSS is forcing
| them both to appear the same 400x400 size. The blue one
| should look sharper on most devices.
|
| Note how the 800x800 canvas needs to be scaled double with
| ctx2.scale(2,2) so that it appears correct.
|
| https://codepen.io/simonsarris/pen/eYexbOb
|
| Pixel ratio is variable (window.devicePixelRatio), so this
| canvas pixel density is something you'll want to
| programmatically set for each user.
| Trufa wrote:
| Dude!! Freaking awesome!! Thanks a bunch!! That's exactly
| what I was looking for! If you have some sort of ko-fi
| account or whatever I'll buy you a coffee!
| etimberg wrote:
| One thing to keep in mind with the
| window.devicePixelRatio is that it is not a static value
| as it can change over time. Some common reasons it could
| change are if the user drags the browser window from a
| low density screen to a high density one. Additionally,
| it will change if the user zooms the page in and out.
| inDigiNeous wrote:
| Yeah I was struggling with this one a while, seems there
| is no way to know the actual devicePixelRatio of the
| display inside a browser, as the browser zoom level
| directly affects that.
|
| Or does anyone here happen to know a way ?
| leeoniya wrote:
| you can use matchMedia to detect devicePixelRatio changes
| and re-sync:
|
| https://github.com/leeoniya/uPlot/blob/190134aa844cfa2a0c
| 052...
|
| everything stays crisp even as you browser-zoom. e.g.
| https://leeoniya.github.io/uPlot/demos/area-fill.html
| moron4hire wrote:
| Zooming also fires the Window's `resize` event, which
| will also catch a user rotating their smartphone/tablet,
| or, erh, resizing the window on desktop.
| leeoniya wrote:
| resize and orientationchange don't change
| devicePixelRatio though, so they're somewhat different
| concerns.
| simonsarris wrote:
| Haha well, you could always subscribe to my newsletter
| for a month. You might get a kick out of it anyway.
|
| I'm glad to have solved your mystery!
| altairprime wrote:
| To add a small caveat here for others, assuming 2x as the
| necessary scaling multiplier is not _necessarily_ a safe
| shortcut when choosing your virtual canvas size; iPhones
| use 3x resources to look crisp, and 5K macOS users can have
| their 5120x2880 displays set to 2048x1152 or 1600x900 which
| are 2.5x and 3.2x respectively.
|
| It still helps when you do your canvas at 2x rather than
| just at 1x. But if you're looking for best-fidelity rather
| than better-fidelity, duly noted.
| mysteryDate wrote:
| This is all great feedback! I'm sure most users
| know this by now, but generally for performance the fewer calls
| you make to the canvas and the context, the beter.
|
| This is almost entirely due to the javascript engine. We're
| working on ways to improve it. roundRect is
| great. Though you don't need 4 arcTo in order to make a rounded
| rect, you can use bezier instead (we do).
|
| Yeah, the example was a little bit humorous, I kinda brute
| forced it. Their example is also 1% amusing
| because they set the `fillStyle` but then call `stroke` (and
| not `fill`).
|
| You caught what 100 rounds of edits did not.
| danielvaughn wrote:
| Sounds like you're involved in this effort, so I'm taking the
| opportunity to ask...what about the TextMetrics API? It's
| listed as supported by Chrome, but I remember trying it last
| year and it's definitely _not_ supported. Has there been
| progress on that front?
| moonchrome wrote:
| >This is almost entirely due to the javascript engine. We're
| working on ways to improve it.
|
| Is it a logo interpreter built into the rendering engine ?
| repeat 2 [fd 100 repeat 90 [rt 1 fd 0.3] fd 200 repeat 90 [rt
| 1 fd 0.3]]
|
| A rounded rect !
| c_s_guy wrote:
| > Though you don't need 4 arcTo in order to make a rounded
| rect, you can use bezier instead (we do)
|
| I'm pretty new to this - do you have an example of using
| bezier? And why is it preferred over arcTo?
| leeoniya wrote:
| i think you'd still need 4 bezierCurveTo commands, so not
| sure there's any advantage over 4 arcTo:
| function roundedRect(ctx, x, y, width, height, radius) {
| ctx.beginPath(); ctx.moveTo(x, y + radius);
| ctx.arcTo(x, y + height, x + radius, y + height, radius);
| ctx.arcTo(x + width, y + height, x + width, y + height -
| radius, radius); ctx.arcTo(x + width, y, x + width
| - radius, y, radius); ctx.arcTo(x, y, x, y +
| radius, radius); ctx.stroke(); }
|
| https://developer.mozilla.org/en-
| US/docs/Web/API/Canvas_API/...
| leeoniya wrote:
| > context.reset is kinda funny. Most high-performance canvas
| apps will never want to use it. For that matter you want to set
| all properties as little as possible, especially setting things
| like context.font, which are slow even if you're setting it to
| the same value. (Or it was, I haven't tested that in several
| years).
|
| yes, ctx.font mutation still sucks very badly. and you cannot
| avoid it during drag-resizing a canvas, which is miserable. (i
| maintain a high perf charting lib).
|
| my additional annoyances:
| https://news.ycombinator.com/item?id=30554387
| hutzlibu wrote:
| "One of the greatest things to happen to 2D canvas in all these
| years was hardware acceleration."
|
| I loved this one, too. Except for the one drawback,
| getImageData is now very, very slow. And no asynchronous method
| in sight, that could make it fast again.
| dahart wrote:
| How slow is it these days? Even readPixels() in OpenGL and hw
| buffer copies in C++ are "slow" because you're transferring
| the image data over your PCI bus.
|
| Also curious how & whether an async method could help? Is the
| problem that getImageData() has to wait to flush all pending
| draw calls before reading back? Are you thinking of some kind
| of callback that returns the previous frame's data, rather
| than demanding it 'now'? There probably is room for perf
| improvement, totally, just curious how you're imagining it
| would look and if you have data on where the current
| bottlenecks are.
| kllrnohj wrote:
| PBOs allow for asynchronous readbacks from opengl. It's not
| slow because of the pcie bus (heck for most devices this is
| unified memory in the first place, it doesn't hit any bus
| other than dram). Rather it's slow for the same reason
| glFinish() is. You're blocking waiting for the results of
| the asynchronous rendering which you probably also just
| kicked off right at that point.
|
| Also it's not like the opengl is happening on the same
| thread as the canvas2d (or even the same process), so
| that's yet more synchronization that a blocking
| getImageData needs to wait on.
| dahart wrote:
| Yeah, exactly, that's what I'm curious about - if the
| browser's renderer is adding significant amounts of delay
| due to additional synchronization, or if the problem with
| canvas.getImageData() is the same problem we've always
| had and if the delays are similar. This does make it seem
| like a callback to receive last frame's image could be
| much faster than a synchronous read call, and I'd
| certainly use that if it existed...
| hutzlibu wrote:
| "How slow is it these days?"
|
| So slow, that chrome falls back to software rendering, if
| you call getImageData 3 frames in a row.
|
| (and does not even switch back to hardwarerendering if you
| stop calling it - last time I checked, was some months ago,
| so maybe that has improved)
| adam_arthur wrote:
| This post implies you can mark a canvas as "read frequently"
| to improve getImageData.
|
| I'm excited to try it out, as I do a kind of hacky hit
| detection using a hidden canvas, And reading the pixel color
| is certainly the bottleneck there
| mpmpmpmp wrote:
| What would your strategy for working with raw image data and
| implementing a digital "zoom" that doesn't do any anti aliasing
| or smoothing? My current thought is to just have an original
| copy of the data and then the current canvas is just a smaller
| subset of the original data when zoomed. So a 100x100 pixel
| image when zoomed 1x would take a 50x50 subset based on the
| center of the viewport and copy each pixel into a 2x2 to get
| back to a 100x100 image.
| simonsarris wrote:
| Unless I misunderstand you, you should be able to
| `ctx.drawImage` from one canvas to another, with
| `imageSmoothingEnabled` set to false, and it will do what you
| want.
|
| https://developer.mozilla.org/en-
| US/docs/Web/API/CanvasRende...
| DonHopkins wrote:
| Excellent advice! Your setmatrix advice is unintuitive, but I
| believe you. The JavaScript/C barrier is expensive, while
| JavaScript calling JavaScript is optimized up the yin-yang.
|
| I love canvas because I cut my teeth on PostScript, and it's
| basically the PostScript imaging model grown up.
|
| What you said about minimizing graphics state changes is an
| important point, that also applies to PostScript. And a lot of
| PostScript optimization advice also applies to
| canvas/JavaScript too, because they're similar in many ways.
|
| Glenn Reid (who worked for Adobe, and was the author of the
| "Green Book" on PostScript language program design) wrote "The
| Distillery", which I've written about before on HN (link and
| excerpt below), that was a PostScript program that loaded in
| and partially evaluated another PostScript drawing program, and
| output another program that drew the exact same thing, only
| (usually) much faster and usually smaller. Unless you had any
| loops, which it would unroll.
|
| https://www.donhopkins.com/home/archive/news-tape/utilities/...
|
| One of the most important optimizations it did was to transform
| all the graphics into the same default coordinate system, and
| optimize out not only graphics state changes but also
| importantly calls to gsave/grestore, which could be quite
| common.
|
| https://news.ycombinator.com/item?id=21988195
|
| Glenn Reid described his classic "Grandfather Clock" metaphor
| to comp.lang.postscript that really opened my eyes about
| writing code in interpreted languages like PostScript (and
| JavaScript, while JIT'ed at runtime, still makes calling native
| code expensive), and balancing optimization with readability.
| With modern JavaScript/canvas, JavaScript code that calls other
| JavaScript code runs really fast, but calling between
| JavaScript and built-in code is still slow, so it's good to
| have the built-in code do as much as possible when you do (like
| rendering a long string of text at once, instead of rendering
| it word by word like many PostScript drivers would):
|
| Glenn's post in a comp.lang.postscript discussion about
| PostScript programming style and optimization:
|
| https://groups.google.com/forum/#!search/%22glenn$20reid%22$...
| From: Glenn Reid (Abode Systems) Newsgroup:
| comp.lang.postscript Subject: Re: An Idea to Help Make
| Postscript Easier to Read (and Write) Date: 10 Sep 88
| 17:26:24 GMT You people tend to forget that the
| PostScript language is interpreted. It is well and good
| to use tools to convert to and from PostScript, but it
| is not quite as "transparent" as we all might think. I
| like to think of a big grandfather clock, with the pendulum
| swinging. Each time pendulum swings, the PostScript
| interpreter gets to do one operation. The
| "granularity" of the clock is nowhere near the speed of
| a microprocessor instruction set, and any comparison with
| assembly languages doesn't make sense. The
| difference between: 0 0 moveto
| and 0 0 /arg2 exch def /arg1 exch def arg1
| arg2 moveto can sort of be measured in "ticks" of
| the interpreter's clock. It's not quite this simple,
| since simply pushing a literal is faster than executing
| a real PostScript operator, but it is a rough rule of thumb.
| It will take about three times as long to execute the second of
| these in a tight loop, and about five times as long if
| it is transmitted and scanned each time. My rule of
| thumb is that if you have roughly the same number of
| tokens in your stack approach as you do with your 'exch
| def' approach, the 'exch def' is likely to be much more
| readable and better. Otherwise, I usually go with the
| stack approach. One other thing of note is that if
| you have too much stack manipulation going on, it may
| well be symptomatic of a problem in the original program
| design. Also, most procedures don't do any stack
| manipulation at all, they simply use their arguments
| directly from the stack. In this situation, it is
| especially wasteful (and confusing, I think) to declare
| intermediate variables. Compare: %
| sample procedure call: (Text) 100 100 12
| /Times-Roman SETTEXT % approach 1:
| /SETTEXT { %def findfont exch scalefont
| setfont moveto show } def %
| approach 2: /SETTEXT { %def
| /arg5 exch def /arg4 exch def
| /arg3 exch def /arg2 exch def
| /arg1 exch def arg5 findfont arg4 scalefont
| setfont arg2 arg3 moveto arg1 show
| } def Which of these is easier for you to
| understand? Anyway, I think the discussion is a
| good one, but let's not forget that PostScript it is an
| interpreted language. And I don't think it is terribly
| hard to use and understand, if it is written well.
| Glenn Reid Adobe Systems
|
| Here's Glenn's "Green Book", which was like a bible to me, and
| still is quite relevant to canvas 2d context programming -- see
| especially page 9, section 1.5, Program Design Guidelines, page
| 72, section 4.6, Optimizing Translator Output, and page 99,
| chapter 7, The Mechanics of Setting Text:
|
| https://www-cdf.fnal.gov/offline/PostScript/GREENBK.PDF
|
| >page 9: 1.5 Program Design Guidelines
|
| >There are a few items that may be kept in mind while
| implementing a driver for a PostScript device. As with most
| software development, the most difficult part of writing
| programs in the PostScript language is the design of the
| program. If the design is good, implementing it is easy. If the
| design is poor, it may not even be possible to correctly
| implement it. Below are some helpful items to keep in mind when
| writing your software. All of them are explained more fully
| within the text of this book; this is only an attempt to prime
| the pump before you start reading:
|
| >* Use the operand stack efficiently. Pay particular attention
| to the order of the elements on the stack and how they are
| used.
|
| (Using the stack efficiently by designing fluent words that
| chain and dovetail together elegantly in pipelines (and
| systematically writing line-by-line stack comments) instead of
| using named variables in dictionaries is good idiomatic
| PostScript and Forth, aka tacit programming or point-free
| style, the stack-based equivalent of fluent interfaces.)
|
| https://en.wikipedia.org/wiki/Tacit_programming
|
| https://en.wikipedia.org/wiki/Fluent_interface
|
| >* Avoid unnecessary redundancy. When a program is produced,
| check for many repetitive steps that perhaps could be
| condensed. Keep identifiers short if they are to be transmitted
| many times.
|
| (Only create paths once!)
|
| >* Use the PostScript imaging model effectively. When printing,
| a document must be translated into the language of the printer.
| This includes a philosophical adjustment to the nature of the
| PostScript imaging model.
|
| (Use the graphics state stack!)
|
| >* It is better to translate into the PostScript imaging model
| than to maintain another set of graphics primitives using the
| PostScript language for emulation.
|
| The hardest problem I ever tried (and failed) to solve properly
| with PostScript was making a printer driver for rendering user
| interfaces drawn with X11 using a combination of bitmaps and
| lines, that looked perfect on the screen at 1:1 scale, but
| didn't look terrible when you zoomed into them or printed them
| at high resolution on paper. Because of X11 "half open" pixel
| rounding rules versus PostScript's "stencil paint" model, they
| just don't line up right when you zoom into them, and there's
| no fudge or compromise that works in all cases. Here is my
| commented-out failed attempt:)
|
| https://github.com/mmontone/garnet/blob/1652af38f76b1c4efb19...
| line-color line-cap line-join dash-pattern thickness
| % dup -1 ne { .5 add } if % fudge outline width thicker
| StrokeShape
|
| >page 100: Note: There is one principle to keep in mind when
| deciding upon an algorithm for setting text. The longer the
| string presented to one of the show operators, the more
| efficient the system is likely to be. This is because the
| PostScript language built-in operators, such as show,
| widthshow, and ashow, operate essentially at compiled speed
| once they have been invoked. Each moveto or div operation
| performed must first be interpreted, which is significantly
| slower.
|
| Here's a description of Glenn's PostScript Distillery, which
| foreshadowed Acrobat Distiller.
|
| https://news.ycombinator.com/item?id=28115946
|
| >Glenn Reid wrote a PostScript partial evaluator in PostScript
| that optimized other PostScript drawing programs, called "The
| Distillery". You would send still.ps to your PostScript
| printer, and then send another PostScript file that drew
| something to the printer. The first PostScript Distillery
| program would then partially evaluate the second PostScript
| drawing program, and send back a third PostScript program, an
| optimized drawing program, with all the loops and conditionals
| unrolled, calculations and transformations pre-computed, all in
| the same coordinate system.
|
| >It was originally John Warnock's idea, that Glenn implemented.
| And it led to Adobe Acrobat's "Distiller". Acrobat is basically
| PostScript without the programming language.
|
| >No, you could not make it optimize itself by sending it to a
| PostScript printer two times in a row. It was not magic: all it
| did was intercept and capture the side-effects of the
| PostScript drawing commands (fill, stroke, show), read out the
| path, and optimize it in a uniform coordinate system. Since it
| didn't do any drawing, so it would just output an empty program
| if run on itself. (Take that, halting problem!)
|
| https://donhopkins.com/home/archive/postscript/newerstill.ps...
|
| >From: greid@adobe.com (Glenn Reid) Newsgroups:
| comp.lang.postscript Subject: release 10 of the Distillery
| Date: 10 Mar 89 10:21:52 GMT
|
| >Here is another release of the PostScript Language Distillery.
| I know it's not terribly long after the last release, but there
| are some significant enhancements, and I thought it would be
| worthwhile.
|
| >I finally took a closer look at user-defined fonts, which now
| seem to be working fairly well. In particular, it seems to
| handle the Macintosh screen bitmap fonts that get used if the
| native font is unavailable when the print file is genreated.
| The entire user-defined font is reverse-engineered to the
| output file as it stands, and is used exactly like the original
| file used it. I also fixed some rotate text bugs, rotated
| charpath, and a few other things.
|
| >I want to emphasize that probably the two best uses of this
| program, currently, are to do speed comparisons of various
| PostScript language drivers and to convert "non-conforming"
| files into "conforming" files. It is not particularly well
| suited to carefully hand-written programs, especially not those
| which use looping constructs. It works (usually), but it
| unrolls the loops and makes the files much bigger.
| dmitriid wrote:
| The problem is: browser implementors are never/rarely website
| implementors. So you always end up with half-baked tangentially
| useful standards and APIs like this. They just don't know what
| is actually needed.
| mysteryDate wrote:
| Well, there's this and the fact that browser implementers
| _all_ need to come to consensus over what features to add and
| that 's an extremely difficult process to move forward. There
| also is one big browser implementer who doesn't really _want_
| the "playful web" to exist and would prefer that everyone
| live inside of apps.
|
| Edit: To be clear, we all work together and mostly get along.
| It's a long and arduous process to reach consensus and not
| everyone's incentives are aligned and this can be
| frustrating.
| dmitriid wrote:
| > There also is one big browser implementer who doesn't
| really _want_ the "playful web" to exist and would prefer
| that everyone live inside of apps.
|
| No. There's one humongous browser implementer who couldn't
| care less about consensus or what other browser vendors
| think. This vendors ships literally hundreds of new APIs
| every year and pretends they are now standards that
| everyone else must implement.
|
| Too bad developers believe them.
|
| BTW, it only took only 8 minutes for my countdown to reach
| zero: https://news.ycombinator.com/item?id=30555034
| robertoandred wrote:
| Don't you know? The "playful web" means websites getting
| access to your USB devices or being able to keep your
| screen from sleeping/locking!
| dmitriid wrote:
| Someone linked "Request for position" on these APIs:
| https://github.com/mozilla/standards-
| positions/issues/519#is...
|
| Here's Mozilla's response:
|
| --- start quote ---
|
| 4x4 transforms:
|
| There are a bunch of implementation concerns here (and
| mentioned on that issue) with regards to availability on
| various native 2d backends... Needs more investigation
|
| SVG filter interface:
|
| We would really rather people use WebGL if you want
| fast/efficient filters. (I made a number of comments on
| that issue) As is, we're generally against this one for
| the time being
|
| --- end quote ---
|
| There's literally zero response on that from @mysteryDate
| who is now gaslighting Safari in the comment above, and
| presenting these API additions as fait accompli.
|
| Honestly, at this point any time I see any public Chrome
| person write anything I immediately assume it's a
| distortion of reality _at best_ and a blatant lie at
| worst. And this is always the case.
|
| But sure. "Safari is the bad guy".
| rikroots wrote:
| > We would really rather people use WebGL if you want
| fast/efficient filters.
|
| This one made me laugh. Yes, WebGL excels at pixel
| manipulations but it is possible to write fast and
| efficient filters to work in the 2D canvas environment.
|
| For a case-in-point, I struggled for a long time to find
| a decent, fast implementation of a gaussian blur filter
| for my canvas library. Then I stumbled upon a JS
| implementation[1] based on some very clever work done by
| Intel devs which blew all my previous attempts out of the
| water - so of course I stole it (even though I still
| don't understand the approach they take)[2].
|
| > "Safari is the bad guy"
|
| As much as Safari often brings me to despair, I do like
| the work they've recently done to add color space support
| in CSS. They haven't yet pushed the functionality over to
| the canvas element, but I live in hope. For now, I have
| to emulate the calculations to get them working for my
| library[3].
|
| [1] - https://github.com/nodeca/glur/blob/master/index.js
|
| [2] - https://scrawl-v8.rikweb.org.uk/docs/source/factory
| /filterEn...
|
| [3] -
| https://scrawl-v8.rikweb.org.uk/demo/canvas-059.html
| DonHopkins wrote:
| Cool, interesting links to code -- thank you! I chased
| down Intel's paper the code linked to describing how it
| works on archive.org.
|
| https://web.archive.org/web/20110317025924/https://softwa
| re....
|
| It's not just about using SIMD instructions (they help),
| and laying out memory to optimize cache performance
| (which also helps), but most importantly that Gaussian
| blur is a "separable filter" that you can break up into a
| horizontal and vertical pass, each of which require a lot
| fewer memory references (on the order of just two times
| the number of pixels times the kernel size, instead of
| the number of pixels times the kernel size squared):
|
| IIR Gaussian Blur Filter Implementation using Intel(r)
| Advanced Vector Extensions
|
| >This white paper proposes an implementation for the
| Infinite Impulse Response (IIR) Gaussian blur filter [1]
| [2] [3] using Intel(r) Advanced Vector Extensions
| (Intel(r) AVX) instructions. [...]
|
| >The IIR Gaussian blur filter applies equation (1) on
| each pixel through two sequential passes: The horizontal
| pass: This pass processes the input image left-to-right
| (row-wise), then right-to-left. The output of the left-
| to-right pass is added to the right-to-left pass.
|
| >The vertical pass: Usually, the vertical pass processes
| the output from the horizontal pass top-to-bottom
| (column-wise), and then bottom-to-top. Accessing the
| input column-wise leads to a lot of cache blocks and
| impacts the performance of the filter. To avoid this, the
| horizontal pass transposes the output before writing to
| the output buffer. It makes the vertical pass similar to
| the horizontal pass and processes the intermediate output
| left-to-right, then right-to-left. The vertical pass
| again transposes the final output before writing the
| blurred image.
|
| https://bartwronski.com/2020/02/03/separate-your-filters-
| svd...
|
| >Separate your filters! Separability, SVD and low-rank
| approximation of 2D image processing filters Posted on
| February 3, 2020 by bartwronski
|
| >In this blog post, I explore concepts around separable
| convolutional image filters: how can we check if a 2D
| filter (like convolution, blur, sharpening, feature
| detector) is separable, and how to compute separable
| approximations to any arbitrary 2D filter represented in
| a numerical / matrix form. I'm not covering any genuinely
| new research, but think it's a really cool, fun, visual,
| interesting, and very practical topic, while being mostly
| unknown in the computer graphics community.
|
| https://en.wikipedia.org/wiki/Gaussian_blur#Mathematics
|
| >In addition to being circularly symmetric, the Gaussian
| blur can be applied to a two-dimensional image as two
| independent one-dimensional calculations, and so is
| termed a separable filter. That is, the effect of
| applying the two-dimensional matrix can also be achieved
| by applying a series of single-dimensional Gaussian
| matrices in the horizontal direction, then repeating the
| process in the vertical direction. In computational
| terms, this is a useful property, since the calculation
| can be performed in O(w_kernel w_image h_image) +
| O(h_kernel w_image h_image) time (where h is height and w
| is width; see Big O notation), as opposed to O(w_kernel
| h_kernel w_image h_image) for a non-separable kernel.
| mysteryDate wrote:
| Oh yeah! Safari is definitely doing great for colorspaces
| and we have some work to do to catch up. Very good point.
| mysteryDate wrote:
| There was a ton of work across browser vendors to make
| this a part of spec:
|
| https://html.spec.whatwg.org/multipage/canvas.html#the-
| canva...
|
| It's all there. It's all official. That github page was
| just one part of reaching consensus. There's also TAG
| review:
|
| https://github.com/w3ctag/design-reviews/issues/627
|
| FWIW Mozilla and Safari signed off on all of these
| changes at some point in time somewhere, hence why it's
| allowed to be part of spec. There were some changes that
| were not allowed to be part of the new API because one of
| those two said no (like perspective transforms, conic
| curves).
|
| For jdashg's concerns on that thread, 4x4 matrices were
| cancelled, and you can follow up with _much_ more debate
| from all parties on roundRect and filters:
|
| http://github.com/whatwg/html/pull/6763
| https://github.com/whatwg/html/pull/6765
|
| This is certainly not decided by fiat. Working to find
| consensus across browser implementers is just a ton of
| work.
| dmitriid wrote:
| > It's all there. It's all official.
|
| > FWIW Mozilla and Safari signed off on all of these
| changes at some point in time
|
| That's a relief then. Too often these days "it's official
| it's in the spec" as presented by Chrome is anything but.
|
| > This is certainly not decided by fiat.
|
| There are too many cases when it's decided unilaterally
| by Chrome.
| robertoandred wrote:
| Your post implies that Google cares about browser
| consensus. For example, "This feature has been in Firefox
| for a while and we're finally making it part of the canvas
| spec." Google DOES NOT decide what the spec is. "You" don't
| make something part of the spec.
|
| The Chrome team's hubris is insulting to the web.
| IceDane wrote:
| Your library seems absolutely great. I can't believe I've never
| stumbled upon it before since I've literally gone looking for
| stuff exactly like this several times and never found anything
| very good.
| david927 wrote:
| HN hates "me too" comments but I couldn't agree more.
| Absolutely stunning job. Great work. I don't know how I
| didn't know it existed before.
| andai wrote:
| >Thinking back, I'm also a little disappointed that after the
| death of Flash, it felt like Canvas never really took its
| place. The playful web that came before it in some ways simply
| closed up.
|
| I've been wondering if this is cultural or technical. The
| things that are easy to do get done more, and thus the tech
| (and how well it's designed) shapes mass behavior and culture.
| On the other hand, where there's a will to do something, a way
| will be found, or created...
|
| A great example is sending Flash holiday greeting cards in the
| email. Watching them with my mom is one of my favorite
| computer-related childhood memories. Yet they seemed to go out
| of style long before Flash did.
| StillBored wrote:
| Some of this has got to be the fact that macromedia flash
| originally was more targeted to artists and it was dead
| simple to create nice 2d animations. AKA it wasn't a
| programming environment so much as an artistic tool. The
| current version (adobe animate) doesn't seem nearly as
| popular despite the fact that it can apparently target
| html/canvas. Part of that just might be fragmentation, with
| wick editor, opentoonz, there isn't a single tool everyone
| talks about. Although I'm not sure if those tools can
| legitimately "grow" into programming tools the way flash and
| now animate can. (aka the artist draws up a bunch of stuff
| and then needs to learn some programming or have a programmer
| to come along and fix the donate button so it actually takes
| money like was possible with flash).
|
| OTOH, I used to know a bunch of artistic types that had
| pirated copies and would sit around and create flash
| animations for their bands/etc. Now those people just do
| video editing and post things to youtube/etc, or spend time
| editing photos for facebook/etc. There isn't a
| hypercard/programming aspect anymore buried under their
| tooling.
|
| edit: actually it looks like wick can do the hypercard/flash
| programming too, which is sorta cool.
| thrashh wrote:
| Distributing a Flash file was dead easy
|
| Distributing a HTML file and its assets? God damn complex
| tentacleuno wrote:
| > Distributing a HTML file and its assets? God damn
| complex
|
| There's always Web Bundles[0], but I have no idea what
| the UX is like. I haven't heard about Web Bundles for a
| while, but they seem like such a good idea.
|
| [0]: https://web.dev/web-bundles/
| danielvaughn wrote:
| I can understand where that sentiment comes from, but I think
| what really killed the playful flash web was accessibility.
| It's difficult enough to be fully accessible for a normal
| website; anything out of the ordinary is going to be
| significantly more difficult.
| munificent wrote:
| I think, fundamentally, delight and whimsy don't scale.
|
| They are based on some element of surprise. Once the surprise
| is gone because you've seen it a few times, the joy
| evaporates and then it's just annoying.
| multiplegeorges wrote:
| Flash was huge for playful things because it was extremely
| accessible.
|
| Say what you want about the underlying tech, the authoring
| tools were easy for a kind (like me, at the time) to pick up
| and make animations with.
|
| Is there an equivalent for Canvas?
| titzer wrote:
| I think Flash died 2 years too early, or WebAssembly came 2
| years too late. Because it always seemed to me that Flash was
| a good idea for the web, if it existed as a layer that was
| not "native" could be linked as a library (on top of Wasm and
| canvas). Alas, there were plans to emulate Flash using Wasm,
| but it was on its deathbed by the time we were starting the
| open design process. Adobe's VM seems to have had some design
| decisions that made it difficult to just "hit the button" and
| make it run decent on Wasm.
| claytongulick wrote:
| I think this can be laid at the feet of Apple.
|
| I loved Jobs' vision of HTML5 being the app platform, and
| getting rid of flash.
|
| Instead he got voted down, and we got the early death of
| flash with the replacement being a walled-garden app store,
| setting the web back for years.
|
| They're starting to get their act together (I'm looking at
| you Web Push Notifications) but it's been a long, painful
| road.
| conductr wrote:
| My recollection of Flash was it was just an annoyance. I
| remember avoiding flash websites with the exception being
| games. And I'm not a huge gamer but I recall a handful of
| flash games that stole a few days of attention from me. I
| always find it a bit odd when I hear people have positive
| nostalgic memories of flash because I had thought everyone
| equally agreed it was annoying: similar to Java applets, the
| Real Player, and actually many JavaScript things at the time.
| benrbray wrote:
| However much Flash was abused on the web, it was an
| absolute joy to create games and animations with. There
| aren't any tools I know of today that allow for the same
| rapid art+animation+code workflows. I've tried using
| Canvas2D+JS as well as SVG+JS to do some of the same
| things, and they don't even come close to Flash!
| robertoandred wrote:
| The Flash tool still exists, Adobe calls it Animate now.
| It exports to canvas/js.
| CountHackulus wrote:
| The functionality isn't really the same. Yes, you can
| export animations, but it's much more difficult to
| provide the same level of interactive game that Flash
| did.
| conductr wrote:
| Interesting account. I was diving into tech around turn
| off the millennia and I remember spending all of a day or
| so in action script and went back to the server side
| stuff. There's so much game content around I have to
| believe the void is being met somewhere? Was this just an
| easy on ramp for low/no experienced folks? I believe
| that's how the dreamweaver and other connected adobe
| products were positioned.
| thrower123 wrote:
| Yeah, it's really not. That entire segment that Flash
| games owned doesn't exist any more in the same way that
| it did.
|
| The closest thing would be the mobile games like Candy
| Crush and Garden Saga, but even there the tide has
| passed, and it's too difficult to make anything - King
| was bought by Activision for 6 billion dollars.
| moron4hire wrote:
| There were several major indie games that started out in
| Flash and ended up on consoles. Alien Homind, N++, and
| Castle Crashers come to mind, in particular. They were
| pretty great games. Castle Crashers on Xbox 360 was a
| favorite of my roommates.
| claytongulick wrote:
| Either way, the death of AS3 was a sad thing.
|
| One of the best languages ever made, imho.
|
| Optional typing, e4x, normal inheritance (non-prototypal),
| etc...
|
| The web would be a better place if AS3 took over instead of
| js (and I love js).
|
| I imagine wasm would have shown up and been a ton easier to
| implement as well. AOT bits that are full static, JIT bits
| that aren't. No need for TypeScript, Flow, etc...
|
| Especially sad since iirc Adobe donated the entire thing and
| was pushing for it to become standard in HTML4.
| leeoniya wrote:
| you can do rounded rect in about 50% fewer commands vs the
| example.
|
| https://stackoverflow.com/questions/1255512/how-to-draw-a-ro...
| Jyaif wrote:
| This is as pointless as adding MathML to a browser. Don't further
| bloat browsers. If developers need those features (which 99.9% do
| not), let them create and use libraries based on WebGL/WebGPU.
|
| Or rather: go ahead! The more stuff you add, the quicker a lite
| web (no JS/HTML, just webASM/webGPU) will emerge.
| extheat wrote:
| Just because you don't use the feature doesn't mean others
| don't. I use Canvas2D regularly and enjoy the simplicity of it,
| it is definitely one of the best features of the Web APIs.
| wly_cdgr wrote:
| Useless additions that miss the point. The only thing Canvas2D
| needs is frequent and ongoing improvements to line rendering
| performance.
| veganhouseDJ wrote:
| This brings Canvas up to speed with SVG as far as features no
| one uses.
| oliwarner wrote:
| > 30-40% of web pages have a <canvas> element
|
| What? That seems like an outrageously high number, like an order
| of magnitude out.
|
| Or are we counting anything with an advert on it? Any page on a
| domain? Even then... A third of the internet? I'm doubtful.
| maccard wrote:
| It's for fingerprinting
| [deleted]
| mysteryDate wrote:
| This number is a little bit of a guess. It is the number of
| calls to `<canvas>` divided by the total number of page loads.
| Obviously some pages are using more than one canvas, hence the
| large range.
|
| As for fingerprinting, most canvases are 1. not their default
| size, 2. not 1x1 (like fingerprintjs uses) 3. never call
| `getImageData`. All these things together point to the idea
| that these are legitimate uses. Yes, fingerprinting on the web
| platform is a problem. It's also a problem with canvas. I think
| it's disingenuous to say "canvas is mostly used for
| fingerprinting" without ways to support that statement.
| slmjkdbtl wrote:
| Admittedly, the API is a bit behind the times when it comes to
| state-of-the-art 2D drawing
|
| What does state-of-the-art 2D API look like?
| londons_explore wrote:
| > Let's make sad tabs happy again! In the event that a client
| runs out of GPU memory or some other disaster befalls your
| canvas, you can now receive a callback and redraw as needed:
|
| No... this isn't how it should be. The browser should hide such
| details from the javascript. The canvas contents either shouldn't
| be lost by the GPU at all, or if they are, the browser should
| keep enough information to be able to recreate it (for example, a
| backup of all the canvas pixels plus recent draw commands
| executed).
|
| Lets be honest - most GPU context losses are GPU driver bugs and
| should just be fixed, not require every web page to try to redraw
| to work around them.
| mdswanson wrote:
| Nice to see these updates! I maintain a free/open-source Adobe
| Illustrator plug-in for generating Canvas drawings:
| https://blog.mikeswanson.com/ai2canvas
| dathinab wrote:
| One of the most common uses of Canvas2D on chrome is still
| fingerprinting.
___________________________________________________________________
(page generated 2022-03-04 23:00 UTC)