2
$\begingroup$

I would like a way to create an image of text that is a specific height in pixels. In the following code, the text is sized to fit in the specified raster. Since there are five letters, we expect each letter, with padding, to consume about 1/5 the raster width. When cropped, the height is a bit larger than that, but that makes sense because letter height will generally be greater than letter width. The problem with this approach is that letter height depends in a complicated way on the widths of the letters used. Is there a simple way to ensure that text is rendered at a specific height (e.g. for the letter "x") in pixels?

rastersize = 256;
tmp0 = Rasterize["jello", RasterSize -> rastersize {1, 1}]
tmp1 = ImageCrop[tmp0]
ImageDimensions /@ {tmp0, tmp1}
rastersize /5.
$\endgroup$
8
  • $\begingroup$ It depends on what you mean by "pixel". If by "pixel" you mean the individual "cells" in the image data, then ImageResize will do the job. If by "pixel" you mean something that's related to your screen resolution, then that's going to be much more complicated. If by "pixel" you mean font size, then just use the FontSize option on your text. $\endgroup$
    – lericr
    Commented Mar 24, 2023 at 17:15
  • 1
    $\begingroup$ I could put some examples together, but the whole pixel thing is kind of fraught. There are several different models that get applied simultaneously at different parts of the "stack" between typing some text in some font at some size to outputing an image to some specific display or print. So, in the meantime, it would be very helpful if you described your end goal. And maybe some of your success criteria or how you prioritize the different aspects of the job. Or how much trial and error you're willing to do. $\endgroup$
    – lericr
    Commented Mar 24, 2023 at 20:22
  • 2
    $\begingroup$ And please don't take offense at me asking you to clarify the objective. Sometimes it seems obvious to the poster what the objective is, but having seen several different people try to control what amounts to font sizes within images in different ways, I sincerely don't know what you're trying to achieve. $\endgroup$
    – lericr
    Commented Mar 24, 2023 at 20:27
  • 1
    $\begingroup$ I don't know why you mention width when the end of your question seems focused on height. I don't know what you mean by "letter height depends in a complicated way on the widths of the letters used". The start of your question asks about controlling image height, but the end seems focused on character height. Etc. Etc. $\endgroup$
    – lericr
    Commented Mar 24, 2023 at 20:27
  • 1
    $\begingroup$ although by no means do i consider myself 'practiced' in font manipulation, it is my understanding that fonts have a specific aspect ratio. you cannot unilaterally increase the height of the letter 'a' without expecting to deform it. So if you want to control the height, it is my (potentially naive) understanding that you need to understand how it will affect the width. I hope this helps. $\endgroup$
    – alex
    Commented Mar 27, 2023 at 18:43

2 Answers 2

2
$\begingroup$

The PDF trick

Exporting reimporting a PDF of text yields curve primitives which can be rasterized with some control:

Remove[rasterizeWithHeight]
rasterizeWithHeight[t_,h_,"pdf"] := Cases[
  ImportString[ExportString[t,"PDF"],{"PDF","Pages"}],
  Graphics[x_,___]:> 
  Rasterize[Graphics[x,PlotRangePadding->0,ImagePadding->0], 
  RasterSize->{_,h}],\[Infinity]
][[1]]

"pdf"

This is system dependent and often chops off parts of glyphs. Here's a side by side with PlotRangePadding->0 on the left, and default padding on the right:

jj

Perhaps we could do better by manually computing the extrema of the Bezier curves.


In general, your approach could be to look for accurate data sources of font metrics, or to compute the measurements yourself. There's JLink which exposes the FontMetrics class, but it's unclear whether that would yield better results.

$\endgroup$
3
+25
$\begingroup$

Okay, I'll give it a go, but it just seems unlikely that this is what you want. All I really have to go on is what you said:

I would like a way to create an image of text that is a specific height in pixels

Some sample text:

text = "jello"

When we rasterize, the system will make choices about the image data based on how the image will display. So, we first need to get a feel for that part of the process.

experiment = Rasterize[text];
Options[experiment, ImageResolution]

{ImageResolution->144.}

ImageDimensions[experiment]

{78, 34}

So, to get a height of 5 pixels, we need to choose a value for the ImageResolution option that will give us a height of 5 instead of 34.

textAt5PixelHeight = Rasterize[text, ImageResolution -> (5*144/34)]

enter image description here

ImageDimensions@textAt5PixelHeight

{12, 5}

Now, it sounds like you're wanting to crop any white border. It also sounds like you don't necessarily want to specify a total height, but the height for a particular character. These requirements add complications, but some reasonable approach can be devised. But the bigger problems will be dealing with different fonts, font sizes, and possibly other contextual things that affect the display. So, rather than press forward, I'd like to get your feedback on whether this is actually even in the right ballpark.

$\endgroup$
4
  • $\begingroup$ This is a brilliant answer. What is interesting is that the default image resolution for the rasterization is not unique. On my computer it is set at 96 (v.13.2). Not sure why. $\endgroup$
    – alex
    Commented Mar 27, 2023 at 19:37
  • $\begingroup$ @alex, yeah, and it's not even clear to me that it's consistent on the same system. The documentation seems to leave it open to the specific implementation details at the time of rasterization (but maybe I'm reading too much into it). Thanks for the "brilliant" comment, but I think that this approach can break in many ways. I really wish I had a better idea of the end goal. $\endgroup$
    – lericr
    Commented Mar 27, 2023 at 20:34
  • $\begingroup$ It might come across as too generous of a statement but I meant it. I thought that you smartly exploited the inner mechanics of how ImageResolution is allocated and used it to yield a text at the specified height. it might not be the answer that OP wants, but it is definitely good start. $\endgroup$
    – alex
    Commented Mar 27, 2023 at 21:00
  • 2
    $\begingroup$ @lericr, the default value for ImageResolution with Rasterize will be the equivalent to Max@CurrentValue[{"ConnectedDisplays", "Resolution"}] $\endgroup$
    – ihojnicki
    Commented Mar 28, 2023 at 13:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.