5
$\begingroup$

I want to Rasterize large numbers of single characters quickly, not as a single image but many separate ones. Ideally each one has unique/shrinkwrapped dimensions, but "monospacing" them by taking the largest possible image size is OK.

Consider the strategies

chars=CharacterRange[32,200]
Timing[Rasterize/@chars]                                 (*Option 1= 31 seconds*)
Timing[ParallelMap[Rasterize,chars]]                     (*Option 2= 0.3 seconds*)
Timing[Rasterize@Style[Row@chars,LineBreakWithin->False]](*Option 3= 0.08 seconds*)

Obviously option 2 is a massive improvement, but option 3 is the best if only it gave separate images.

Can I have my cake and eat it too; a fast/optimized version of Rasterize that threads over lists?


This answer to "Faster alternative to Rasterize" indicates that Rasterize does its work in the front end, so is hard to profile/time.

I may dig around with JLink or write some C to figure out more internals. Blindly digging, I found System`ConvertersDump`ConvertGraphicToRasterDataPacket and System`ConvertersDump`GetRasterData which uses "BitmapPacket"s.

I'm not experienced enough to play with these internals -- can I manually construct and send a System`ConvertersDump`Utilities`GetFromFE packet?

$\endgroup$
1
  • 1
    $\begingroup$ All of those internal functions are used to implement Rasterize. The simple fact is, creating a graphics context and a destination image to render to is going the limiting factor. Generating/rendering an atlas and then cutting it up is the fastest approach. That is what WordCloud happens to do at the moment. $\endgroup$ Commented yesterday

1 Answer 1

5
$\begingroup$

This uses Rasterize only once and then ImagePartition is used.

p = 50; (* p*p pixels per character *)
n = 13; (* n*n characters *)
chars2 = 
  PadRight[Join[CharacterRange[33, 126], CharacterRange[192, 266]], 
   n^2, "*"];
ts = 20; (* text size *)

Graphics[{Table[
    Text[Style[chars2[[i + n j]], ts], {i, -j}], {i, n}, {j, 0, n - 1}]},
   PlotRange -> {{0.5, n + 0.5}, {0.5, -n + 0.5}}, 
  PlotRangePadding -> 0];
Rasterize[%, RasterSize -> n {p, p}];
imgs = ImagePartition[%, p];
imgs // Grid

enter image description here

It the form of a function that rasterizes chunks of 169 characters:

chraster[ch_, p_, ts_] := 
 With[{n = 13, 
   pch = Partition[PadRight[ch, Ceiling[Length[ch]/169]*169, "*"], 
     169]}, Flatten[
    ImagePartition[
       Rasterize[
        Graphics[{Table[
           Text[Style[#[[i + n j]], ts], {i, -j}], {i, n}, {j, 0, 
            n - 1}]}, PlotRange -> {{0.5, n + 0.5}, {0.5, -n + 0.5}}, 
         PlotRangePadding -> 0], RasterSize -> n {p, p}], p] & /@ 
     pch][[;; Length[ch]]]]

ch = RandomChoice[Alphabet[], 169]
chraster[ch, 50, 20] // Timing

enter image description here

ch = RandomChoice[Alphabet[], 327];
chraster[ch, 50, 20]; // Timing

{0.125, Null}
$\endgroup$
2
  • $\begingroup$ If you make this a general function which accepts an arbitrary list of characters, I'll accept. I think doing it in one row would be easier for this purpose. +1 though, I forgot that specifying the position of Graphics objects allowed for control over subsequent splitting. $\endgroup$ Commented yesterday
  • $\begingroup$ @Adam What is maximum length of your "arbitrary list of characters"? It will not work for any length, for 1000 characters the image could be so large, that it would not fit into available memory. $\endgroup$ Commented 18 hours ago

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.