Blurry text

The following code works well except when I display the picture in a canvas, all the letters are blurry

PageImage(ImageNbr) = SELF.BitmapForCaching(525, 725)
g = PageImage(ImageNbr).Graphics
g.DrawString(“Cruise Table 1 - Field Data”,55,65)

And in the canvas paint event:

g.DrawPicture(PageImage(ImageNbr), 0, 0, PageImage(ImageNbr).Width * PicScale, PageImage(ImageNbr).Height * PicScale, XScroll, YScroll, PageImage(ImageNbr).Width, PageImage(ImageNbr).Height)

I use the PicScale for “Zoom In” and “Zoom out” and the x-yscroll to scroll the picture via arrow keys. All that works fine, but the letters are blurry, especially when sent to a printer.

PageImage is declared as PageImage(10) AS Picture

I have been going over post after post, dating 14 years back; and only get try this or try that, and nothing works.

Surely this has an easy known solution for producing crisp clear letters. Any help will be greatly appreciated.

What is 525, 725 ? Is it the size of the canvas ?

You will probably get a crisper effect by using the picture as backdrop, instead of redrawing it in Paint. Maybe you refactor your code to use backdrop at 1:1, and draw it in paint with resizing when zooming in or out.

You could also create a picture just for backdrop, into which you draw (me.backdrop.graphics) instead of doing it to g.

To send to the printer, you must create a much larger picture to accommodate horizontal and verticalResolution.

If your printer is for instance 300 dpi, the necessary picture must be (525/72)*300, (725/72)*300 to provide a good, non blurry result.

this would be expected… zooming out on a picture reduces the level of clarity… the same effect (in the old days) when you took a film negative and attempted to blow it up… it becomes blurry (or in the case of a graphics image becomes “pixelated”)

The only real way to get clear text, it to draw the text at the size it is intended to be displayed at (or larger). If you make a BIG picture and reduce it then blurriness is less apparent (to a point)

The letters are blurry whether I use the zoom or not. Appears that the drawstring writes the letters blurry. So the picture is set and I can not un-blurry it. I need to have DrawString draw crisp clear letters, rather than blurry ones.

No… you are doing something that is less than optimal…
I say this because I have apps that do exactly what you are indicating, and the text comes out just fine

and why not just draw to “g” instead of using a interim step?

I think I may know …
according to the LR

this infers that on a HDpi screen, the returned “picture” has a gscaleX of 2
but then when you do DrawPicture… you are applying the scale AGAIN

PageImage() contains all the output pages, so the user can page through the output, and print one page or all pages. A nice feature.

You cannot get a decent printing from pictures that have a much lower resolution than the printer.

The text is blurry in the canvas too, so I can’t blame my printer.

Have you tried to leave PicScale out of the DrawPicture as I suggested… it looks like you are creating it @2x, and displaying it at @4x, this would introduce “blurrying”

I tried it with and without the Picscale, then compared output. They were literally identical.

As others have suggested, and from personal experience in creating page layout software in Xojo. Don’t use a picture.

Instead design your code to use a graphics class and dimensions ( top, left, width, height ), this way you can maintain consistency and still provide scrolling. Scaling the content is not needed when printing, however if you want to provide a zoom mechanism, look into either handling the scale yourself when drawing each element, or simply cheat and use graphics.ScaleX & graphics.ScaleY, if you use the graphics class, be sure to concatenate the new scale values with the existing values of the class.

When you draw to a picture or graphics class, you are rasterizing at whatever resolution that graphics class / picture is set to.

The screen in HiDPI is at 144 dpi, and in non HiDPI is at 72 dpi. Do you understand that actually the blurry effect will be worse, even terrible, on a common inkjet printer at 600 dpi ?

It is not a matter of pointlessly blaming a peripheral, it is a matter of addressing the printer correctly.

Solved:
The solution for this commercial app was essentially what I do when building 3D graphs and objects. I build an oversized object then multiply it by 0.1; The graph/object and various axes all become sharp and clear, no blurry characters.

For this current problem, I do not have access to the user printers or monitors. And since there are literally hundreds, I don’t want access. It’s also unacceptable to tell users that they need a printer with X DPI to get good clear output. The same goes for monitors.

So when defining a picture I expanded it by a factor of 5

  Expander = 5     // expand pic by a factor of 5 
  Crisper = 0.2    // before displaying or printing a page, I reduce it by multiplying it by Crisper, so letters are crisp and sharp for both the monitor and printer.
  PixHt = 12       // height of a line in pixels

“In other words, all text becomes non-blurry before being sent to a printer or monitor.”

Consider it like a photograph that you are going to scan. If the photo is blurry then the scan will be blurry. If the photo is clear and crisp then the scan will be clear and crisp. The scanner will not change the picture itself.

By using a picture, everything remains in a nice neat package that can be stored and delivered with a user friendly interface. I initialize a picture (a single page) with:

  PageImage = BitmapForCaching(525*Expander, 725*Expander)     // make image 5 times larger than needed
  g = PageImage.Graphics

After initializing, building the picture took a little more effort since the x and y positions had to consider this size change. Statements look like:

  YPos = YPos + PixHt * Expander
  g.DrawString("   Proj leader: " + ProjLeader,XPos,YPos)

This new YPos advances the output one line from the last YPos. XPos was also multiplied by the Expander, but remained the same for each line. An underscore took this form:

  YPos = YPos + PixHt/2 * Expander
  g.DrawLine(50 * Expander,YPos,525 * Expander,YPos)

Once the page was complete I refreshed the canvas to get the Paint event to fire with this command:

  g.DrawPicture(PageImage, 0, 0, PageImage.Width * Crisper * PicScale, PageImage.Height * Crisper * PicScale, XScroll, YScroll, PageImage.Width, PageImage.Height)

The Crisper eliminates the oversized pic (5x) and brings it back to a normal size. Now all the letters are sharp and ‘crisp’. The PicScale is for my zoom buttons and the scrolls allow for scrolling.

Next to the canvas I have controls for Prior page, Next page, Go to page, zoom in, zoom out, print visible page, print multiple pages, reset to original size after zooming and re-center after scrolling.

With multi-paged documents, at some point you’re going to run out of memory since each page is treated as a separate picture that cannot be discarded. For this app, it would not be unusual to have a 500 page report, outlining collected field data. The solution is to create a new database record where you can save each page in a document. With that feature I can retrieve, say, page 234 of Table 5 and display it. I don’t have to re-create the first 233 pages to produce page 234. The speed is such that the user will never know it is coming from the database.

Like everything else, this will get refined and improved over time. TJ