Images in quadwriter #8

Open
opened 5 years ago by otherjoel · 17 comments
otherjoel commented 5 years ago (Migrated from github.com)

In #lang quadwriter/markdown saving the below to the same folder as test.jpg

#lang quadwriter/markdown

![image](test.jpg)

—then doing Run in DrRacket results in div: unbound identifier in: div

Also: pict->quad would be useful

In `#lang quadwriter/markdown` saving the below to the same folder as `test.jpg` ``` #lang quadwriter/markdown ![image](test.jpg) ``` —then doing _Run_ in DrRacket results in `div: unbound identifier in: div` Also: `pict->quad` would be useful
mbutterick commented 5 years ago (Migrated from github.com)

How should a quadwriter/markdown image be scaled and positioned, by default?

How should a `quadwriter/markdown` image be scaled and positioned, by default?
mbutterick commented 5 years ago (Migrated from github.com)

By the principle of least user labor, it doesn’t seem like quadwriter should rely on the native size of the image file, because that would impose a lot of new preparation of the image files to get them right.

OTOH assuming that an image wants to be a block-level element, scaling the image to the full width of the line seems like it would often be too big.

PS What would a pict->quad function do?

By the principle of least user labor, it doesn’t seem like `quadwriter` should rely on the native size of the image file, because that would impose a lot of new preparation of the image files to get them right. OTOH assuming that an image wants to be a block-level element, scaling the image to the full width of the line seems like it would often be too big. PS What would a `pict->quad` function do?
otherjoel commented 5 years ago (Migrated from github.com)

How should a quadwriter/markdown image be scaled and positioned, by default?

Specifically for the markdown variant, for raster images as block-level elements, I would scale the image using the DPI metadata in the original file, or if that is wider than the text block I would scale it down to fit. Not sure about vector images. Center it in the text block and use the alt text, if any, as a caption underneath.

> How should a `quadwriter/markdown` image be scaled and positioned, by default? Specifically for the markdown variant, for raster images as block-level elements, I would scale the image using the DPI metadata in the original file, or if that is wider than the text block I would scale it down to fit. Not sure about vector images. Center it in the text block and use the alt text, if any, as a caption underneath.
otherjoel commented 5 years ago (Migrated from github.com)

PS What would a pict->quad function do?

It would be good to be able to include picts built with the racket/draw functions in the PDF output. even to be able to place them at precise coordinates on the page. Two use cases I have in mind are Racket REPL example output and book cover design.

> PS What would a `pict->quad` function do? It would be good to be able to include `pict`s built with the `racket/draw` functions in the PDF output. even to be able to place them at precise coordinates on the page. Two use cases I have in mind are Racket REPL example output and book cover design.
mbutterick commented 5 years ago (Migrated from github.com)

A Racket pict is just a precursor object to a rendered file. So unless I misunderstand, the pict->quad could be as simple as this, where you render your pict object to png as a temp file, and then pass the path of this file as an image-data attribute:

#lang racket
(require quadwriter pict)

(define mypict (cloud 100 75 "lavenderblush"))

(define (pict->quad p [type 'png])
  (define fn (format "~a~a.~a" (object-name p) (eq-hash-code p) type))
  (send (pict->bitmap mypict) save-file fn type)
  `(q ((image-data ,fn))))

(render-pdf (pict->quad mypict) "test.pdf")

(Of course, there is nothing magical about the temp filename)

A Racket `pict` is just a precursor object to a rendered file. So unless I misunderstand, the `pict->quad` could be as simple as this, where you render your `pict` object to `png` as a temp file, and then pass the path of this file as an `image-data` attribute: ```racket #lang racket (require quadwriter pict) (define mypict (cloud 100 75 "lavenderblush")) (define (pict->quad p [type 'png]) (define fn (format "~a~a.~a" (object-name p) (eq-hash-code p) type)) (send (pict->bitmap mypict) save-file fn type) `(q ((image-data ,fn)))) (render-pdf (pict->quad mypict) "test.pdf") ``` (Of course, there is nothing magical about the temp filename)
mbutterick commented 5 years ago (Migrated from github.com)

That doesn’t help with the scaling / positioning, which I have to think about more.

That doesn’t help with the scaling / positioning, which I have to think about more.
mbutterick commented 5 years ago (Migrated from github.com)

I would scale the image using the DPI metadata in the original file

BTW are you certain that PNG files carry DPI metadata? I have not found evidence of this yet, though I never want to rule out my own ignorance as a contributing factor.

> I would scale the image using the DPI metadata in the original file BTW are you certain that PNG files carry DPI metadata? I have not found evidence of this yet, though I never want to rule out my own ignorance as a contributing factor.
otherjoel commented 5 years ago (Migrated from github.com)

the pict->quad could be as simple as this, where you render your pict object to png as a temp file, and then pass the path of this file as an image-data attribute

That could work for sure, though wouldn't it be cleaner to do this in-memory, and avoid leaving artifacts on the filesystem to clean up?

BTW are you certain that PNG files carry DPI metadata?

Yeah, I’m actually certain they may not…looks like the PNG standard specifies an optional header for dots per meter. Bummer, although maybe it does make things simpler if you just say scaling info must be specified in (or derivable from) the q-expression regardless of the image file format.

> the `pict->quad` could be as simple as this, where you render your `pict` object to `png` as a temp file, and then pass the path of this file as an `image-data` attribute That could work for sure, though wouldn't it be cleaner to do this in-memory, and avoid leaving artifacts on the filesystem to clean up? > BTW are you certain that PNG files carry DPI metadata? Yeah, I’m actually certain they _may not_…looks like the PNG standard specifies an [optional header](https://www.w3.org/TR/2003/REC-PNG-20031110/#11pHYs) for dots per meter. Bummer, although maybe it does make things simpler if you just say scaling info must be specified in (or derivable from) the q-expression regardless of the image file format.
otherjoel commented 5 years ago (Migrated from github.com)

Image scaling could have a document-wide DPI value with a useful default, or specifiable by keyword argument

Outside of quadwriter/markdown, perhaps there could be three ways to handle scaling besides (i.e. overriding) the above:

  1. Individual q-expressions with image data could specify a DPI value, and the print size and width of the image would be derived from this.
  2. Or an expression could specify one of width or height (in what, points?) and the image would be scaled accordingly, retaining its aspect ratio.
  3. Or both width and height could be specified and the image would be forced into those dimensions.
Image scaling could have a document-wide DPI value with a useful default, or specifiable by keyword argument Outside of `quadwriter/markdown`, perhaps there could be three ways to handle scaling besides (i.e. overriding) the above: 1. Individual q-expressions with image data could specify a DPI value, and the print size and width of the image would be derived from this. 2. Or an expression could specify _one of_ width or height (in what, points?) and the image would be scaled accordingly, retaining its aspect ratio. 3. Or both width and height could be specified and the image would be forced into those dimensions.
mbutterick commented 5 years ago (Migrated from github.com)

That could work for sure, though wouldn't it be cleaner to do this in-memory, and avoid leaving artifacts on the filesystem to clean up?

I’ll have to think about it more. Yes, cleaner in one sense. But a temp file is going to have to be made somewhere along the way. It’s arguably dirtier for quadwriter to handle that housekeeping because it requires it to know about Racket pict objects (whereas so far, I’ve been trying to keep everything restricted to the Q-expression interface).

Image scaling could have a document-wide DPI value with a useful default, or specifiable by keyword argument

I’ve implemented it more or less as you suggest. quadwriter/markdown arbitrarily imposes an image height of 150 pixels. It seems like the scaling needs a little more finesse so that it cooperates with the line width, so that if you set an image scale, and then make the line width smaller (say, by adding columns) that the images aren’t left at their former size.

> That could work for sure, though wouldn't it be cleaner to do this in-memory, and avoid leaving artifacts on the filesystem to clean up? I’ll have to think about it more. Yes, cleaner in one sense. But a temp file is going to have to be made somewhere along the way. It’s arguably dirtier for `quadwriter` to handle that housekeeping because it requires it to know about Racket pict objects (whereas so far, I’ve been trying to keep everything restricted to the Q-expression interface). > Image scaling could have a document-wide DPI value with a useful default, or specifiable by keyword argument I’ve implemented it more or less as you suggest. `quadwriter/markdown` arbitrarily imposes an image height of 150 pixels. It seems like the scaling needs a little more finesse so that it cooperates with the line width, so that if you set an image scale, and then make the line width smaller (say, by adding columns) that the images aren’t left at their former size.
mbutterick commented 5 years ago (Migrated from github.com)

(but for now, your original example should work)

(but for now, your original example should work)
otherjoel commented 5 years ago (Migrated from github.com)

Maybe allow us (Quadwriter users) to supply the raw PNG or PDF bytes to the Q-expression and we can convert the picts ourselves using convert?

Maybe allow us (Quadwriter users) to supply the raw PNG or PDF bytes to the Q-expression and we can convert the picts ourselves using [`convert`](https://docs.racket-lang.org/file/convertible.html)?
mbutterick commented 5 years ago (Migrated from github.com)

“raw PNG or PDF bytes” = for instance, encoded as base64?

“raw PNG or PDF bytes” = for instance, encoded as base64?
otherjoel commented 5 years ago (Migrated from github.com)

OK I see what you are getting at. Q-expressions elements can only be strings or other q-expressions. I think I have been confusing q-expressions with quads.

So I get why you wouldn't want to allow byte-strings in q-expressions (you could no longer treat them as x-expressions). Maybe base64 is a good option to have when you're not dealing with a 24MP photo, you just want a blue rectangle or some REPL output or something else dynamically generated.

It's also dawning on me no variant of quadwriter is intended for use as a generic PDF canvas service. Maybe at the quad level though?

OK I see what you are getting at. Q-expressions elements can only be strings or other q-expressions. I think I have been confusing q-expressions with `quad`s. So I get why you wouldn't want to allow byte-strings in q-expressions (you could no longer treat them as x-expressions). Maybe base64 is a good option to have when you're not dealing with a 24MP photo, you just want a blue rectangle or some REPL output or something else dynamically generated. It's also dawning on me no variant of `quadwriter` is intended for use as a generic PDF canvas service. Maybe at the `quad` level though?
mbutterick commented 5 years ago (Migrated from github.com)

Right, I think of quadwriter as following the flow-based model of word processors — where, for the most part, you’re not specifying the exact position of anything — vs. the more controlled model of a page-layout program like InDesign, where everything is positioned exactly, aka a “generic PDF canvas service” (if I understand you correctly)

But I think that canvas service is a subset of quadwriter. How would it work? You just want to put boxes at certain positions, with (possibly) line-wrapped type inside, or images? And everything happens on one logical “page”, so there’s no column or page breaks to compute?

Right, I think of `quadwriter` as following the flow-based model of word processors — where, for the most part, you’re not specifying the exact position of anything — vs. the more controlled model of a page-layout program like InDesign, where everything is positioned exactly, aka a “generic PDF canvas service” (if I understand you correctly) But I think that canvas service is a subset of `quadwriter`. How would it work? You just want to put boxes at certain positions, with (possibly) line-wrapped type inside, or images? And everything happens on one logical “page”, so there’s no column or page breaks to compute?
otherjoel commented 5 years ago (Migrated from github.com)

You just want to put boxes at certain positions, with (possibly) line-wrapped type inside, or images?

I'm envisioning how I would use quad/quadwriter in place of racket/draw under the hood of #lang bookcover, so I'd be using it to, for example, implement the kinds of things talked about in the bookcover overview. So: arbitrary page sizes; graphical elements or line-wrapped type placed at precise coordinates, possibly overlapping; barcodes; generative art; etc. With the current approach I create a bunch of picts and then draw them on a pdf-dc%.

The benefits over racket/draw would be things like better typesetting (bookcover cannot currently wrap text at all), much better portability across OSs, less fighting with the system font stack over things like font naming, etc.

And everything happens on one logical “page”, so there’s no column or page breaks to compute?

Yes, although maybe ideally it should be possible to combine multiple such page/canvases into a single output PDF file.

> You just want to put boxes at certain positions, with (possibly) line-wrapped type inside, or images? I'm envisioning how I would use quad/quadwriter in place of racket/draw under the hood of `#lang bookcover`, so I'd be using it to, for example, implement the kinds of things talked about in the [bookcover overview](https://docs.racket-lang.org/bookcover/Overview.html). So: arbitrary page sizes; graphical elements or line-wrapped type placed at precise coordinates, possibly overlapping; barcodes; [generative art](https://web.archive.org/web/20081015005111/http://postspectacular.com/process/20080711_faberfindslaunch); etc. With the current approach I create a bunch of `pict`s and then draw them on a `pdf-dc%`. The benefits over racket/draw would be things like better typesetting (bookcover cannot currently wrap text at all), much better portability across OSs, less fighting with the system font stack over things like font naming, etc. > And everything happens on one logical “page”, so there’s no column or page breaks to compute? Yes, although maybe ideally it should be possible to combine multiple such page/canvases into a single output PDF file.
mbutterick commented 5 years ago (Migrated from github.com)

This sounds reasonable, and suggests the utility of a quaddraw app as a complement to quadwriter. Mostly I think it’s a matter of factoring out the reusable parts from quadwriter and then adding a couple controls (e.g., exact positioning). I suspect, however, that I won’t be able to make a start on this until after Racket School.

This sounds reasonable, and suggests the utility of a `quaddraw` app as a complement to `quadwriter`. Mostly I think it’s a matter of factoring out the reusable parts from `quadwriter` and then adding a couple controls (e.g., exact positioning). I suspect, however, that I won’t be able to make a start on this until after Racket School.
Sign in to join this conversation.
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: mbutterick/typesetting#8
Loading…
There is no content yet.