[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)