PDFGraphics DrawPicture

Does anyone know a way to get the PDF Graphics to NOT draw pictures scaled down in resolution?
I had hoped drawing a larger image to a reduced size would address the resolution, but the output is not printable and therefore not usable.

Can you share your code and the image width, height and resolution values ?

Var w,h As Double
Var s As Double

w = inchToPixel(2)
h = inchToPixel(0.5)

Var pic As picture = ReportHeaderGraphic
s = Min(w/pic.Width, h/pic.Height)

Var pw, ph As Double
pw = pic.Widths
ph = pic.Height
s

g.DrawPicture pic, margins, margins, pw, ph, 0,0, pic.Width, pic.Height

The image is 900pixels wide by 200 tall.

Using DynaPDF this looks great, but there are some features of DynaPDF (using it’s Xojo graphics methods) that don’t seem to be implemented yet, so I’m really hoping to use the native Xojo classes.

If you miss something, I may be able to add more methods.
But if you use DynaPDF’s native API, you may already have more capabilities. And you can mix both ways.

Christian, it seems the GraphicsPath isn’t implemented (unless I’m making a mistake).
I had thought about using DynaPDF native, but at this point I have a ton of graphics that are drawn to canvases and such that I can simply redirect to the PDFDocument. The GraphicsPath stuff is pretty significant I this solution, so it would be hard to rework. ** should I be seeing GraphicsPath working?

GraphicsPath is implemented, but a bit different than you expect.

Since you can’t inspect a GraphicsPath object, we had to subclass it, overwrite all methods and record what you draw. That is why we have a DynapdfGraphicsPathMBS class. You can use with normal graphics class, too.
Here some sample code:

Sub draw(g as graphics, pdf as DynaPDFMBS = nil)
			Const Pi = 3.14159
			Dim pi2 As Double = pi * 2.0
			
			Var gp As DynapdfGraphicsPathMBS
			g.DrawingColor = &cFF0000
			g.PenSize = 5
			g.PenHeight = 5
			g.PenWidth = 5
			
			Title = Str(g.PenWidth)+"x"+Str(g.PenHeight)
			'g.DrawLine 0, 0, 100, 100
			g.PenSize = 1
			
			// arc
			g.AntiAlias = True
			g.PenSize = 3
			
			Dim r As Integer = 40
			Dim n As Integer = 0
			For w As Integer = 0 To 350 Step 10
				
				Select Case n Mod 4
				Case 0
					g.DrawingColor = &cFF0000
				Case 1
					g.DrawingColor = &c00FF00
				Case 2
					g.DrawingColor = &c0000FF
				Case 3
					g.DrawingColor = &cFF00FF
				End Select
				n = n + 1
				
				Dim w0 As Double = w
				
				Dim w1 As Double =  w0       / 180.0 * pi
				Dim w2 As Double = (w0+10.0) / 180.0 * pi
				Dim clockwise As Boolean = False
				
				If pdf <> Nil Then
					'w1 = Convrt(w1)
					'w2 = Convrt(w2)
					
					'w1 = pi2 - w1
					'w2 = pi2 - w2
					'clockwise = True
				End If
				
				gp = New DynapdfGraphicsPathMBS
				gp.AddArc(200, 200, r, w1, w2, clockwise)
				g.DrawPath gp
				
				r = r + 1
				
			Next
			
			
			g.DrawingColor = &c00FFFF
			
			
			Dim w1 As Double = 0
			Dim w2 As Double = pi/2
			Dim clockwise As Boolean = False
			
			gp = New DynapdfGraphicsPathMBS
			gp.AddArc(200, 200, 80, w1, w2, clockwise)
			g.DrawPath gp
			
			
			Var curve As New DynapdfGraphicsPathMBS
			curve.MoveToPoint(320, 200+20)
			curve.AddCurveToPoint(320, 200+100, 500, 200+100, 500, 200+20)
			g.DrawingColor = &c00FF00
			g.DrawPath(curve)
			
			// Draw a fluffy white cloud
			Var cloud As New DynapdfGraphicsPathMBS
			cloud.MoveToPoint(270, 80)
			cloud.AddCurveToPoint(230, 100, 230, 150, 330, 150)
			cloud.AddCurveToPoint(350, 180, 420, 180, 440, 150)
			cloud.AddCurveToPoint(520, 150, 520, 120, 490, 100)
			cloud.AddCurveToPoint(530,  40, 470,  30, 440,  50)
			cloud.AddCurveToPoint(420,   5, 350,  20, 350,  50)
			cloud.AddCurveToPoint(300,   5, 250,  20, 270,  80)
			
			g.DrawingColor = &c0000FF
			g.PenSize = 5
			g.DrawPath(cloud)
			
			
			Var p As New DynapdfGraphicsPathMBS
			p.MoveToPoint(10, 5) // Start location
			p.AddLineToPoint(40, 40)
			p.AddLineToPoint(5, 60)
			
			g.DrawingColor = &c0000FF
			g.DrawPath(p, True)
			
			
			Var qCurve As New DynapdfGraphicsPathMBS
			qCurve.MoveToPoint(38, 100)
			qCurve.AddQuadraticCurveToPoint(138, 0, 238, 100)
			
			g.DrawingColor = &c00FF00
			g.PenSize = 10
			g.DrawPath(qCurve)
			
			Var rect As New DynapdfGraphicsPathMBS
			rect.AddRectangle(300+10, 300+10, 100, 150)
			g.DrawingColor = &cFF0000
			g.DrawPath(rect)
			
			rect = New DynapdfGraphicsPathMBS
			rect.AddRoundRectangle(10, 300+10, 100, 150, 10, 10)
			g.DrawPath(rect)
		End Sub
1 Like

And this is why I renew your plugins every single year.

Thanks, Christian. When Covid is over you are getting a hug! (not really).

1 Like

When Covid is done, we’ll do some traveling for sure!
I may visit a few friends and do a few local Xojo meetings.

1 Like

What resolution ?

You do not use:
Picture.HorizontalResolution

Picture.VerticalResolution

So, if your image ( 900 x 200 ) is 72 dpi, you always get this result.

If the image reslution is - say - 300 dpi or more, set the above properties to that number.

HTH

1 Like

really, it should be using total pixels regardless of resolution. Resolution only dictates display width/height, and I’m overriding these in the drawing command.

Regardless, I’ve seamlessly switched to DynaPDF and it will be good.

Thanks, Emile.

3 Likes

Resolution only dictates display width/height
No. It means print quality.
Nota: it would take you less time to make te-he change and test (if th compile is fast) than writing an answer.

Tink differently: why Retina / HDPi (dmonitor display) are no more 72 / 96 dpi but far more ?

In Photoshop (but not only), you can choose to display all pixels or display the image as is: yes, in that case it means a difference in size. But at print time, you get the same size / different quality.

HTH

Thanks, Emile. I got this covered.
MBS plugins covers the issue exactly by fitting the width and height of the original into the destination without discarding pixels.

1 Like

Please remember to call SetResolution like this:

call pdf.SetResolution(300)

with the resolution you want to have as maximum.
DynaPDF will check what size the image is shown and limit resolution to the setting you pass. Default is 150 dpi. This avoids excessive image sizes.

1 Like

Good note.
150 is fine for this purpose.
Thanks, Christian.

Isn’t it what I said earlier ?

Emile,
I believe it’s exactly what you said. It just wasn’t working for me, and I think I know why. However there are so many other benefits to the MBS plugin that it makes it a moot point to chase it right now.

Here is my more detailed explanation:

If I do the following:

Var p As New PDFDocument
Var pic As picture= MyLogo

Var newWidth As Double = 150 
Var theScale As Double = newWidth/pic.Width
Var newHeight As Double = pic.Height*theScale

pic.HorizontalResolution = 600
pic.VerticalResolution= 600

p.Graphics.DrawPicture pic, 0,0, newWidth, newHeight, 0,0, pic.Width, pic.Height

Var f As FolderItem = SpecialFolder.Desktop.child("test xojo.pdf")
If f.Exists Then f.Delete

p.save(f)
f.Open(True)

I know that changing the resolution doesn’t add more pixels.
I get a low resolution output. Looks to be 72dpi. Jaggies. Yuck.
I tried this after your first suggestion.

I know you also know this too, but others may read the thread and I want to offer a clear message to anyone with less graphics understanding:

A picture has a set amount of information (pixels) those pixels can be presented at any resolution you want, but the size of the image is changed… An image that is 300 dpi and is 1 inch wide can be scaled to 1/2 inch at 600dpi… no data loss. Of course higher resolution doesn’t always increase quality - there is a point of diminishing returns (my customer just sent me a 1 page US letter sized PDF with such large images that the PDF, compressed, was 750mb… for screen presentation)

My expectation of the PDFGraphics is that setting an image in a given size in the PDF document should retain the total pixel count as PDF are resolution independent. That isn’t what’s happening. I thought it may be like a printer where you can set a higher resolution for the output drawing, but I can’t see how to do that. I believe this is just a limitation of the newly added PDFDocument capability. And I’m not knocking the PDFDocument additions… I think they are great.

On the other hand, when I use Christian’s plugin like this (below), I get exactly what I expect.

Var pdf As New DynaPDFMBS
Var f As FolderItem = SpecialFolder.Desktop.child(“test dyna.pdf”)
If f.Exists Then f.Delete
Call pdf.CreateNewPDF(f)

Call pdf.Append
Var g As graphics
g = pdf.PageGraphics

Var pic As picture= MyLogo

Var newWidth As Double = 150
Var theScale As Double = newWidth/pic.Width
Var newHeight As Double = pic.Height*theScale

g.DrawPicture pic, 0,0, newWidth, newHeight, 0,0, pic.Width, pic.Height
Call pdf.CloseFile
f.Open(True)

I recognize that there is a way to set the resolution on DynaPDF, but the default 150 is perfect for my current purpose.

Considering that I own a license for the copy of DynaPDF, that it’s no more code to write, and that I can extend what I’m doing to include XMP, and spot color elements, it’s kind of a no brainer for me at this time.

So yes, I think I’m agreeing with your line of reasoning.

Or… I have been up since 1am last night, so I could be missing your point completely! (ツ)

1 Like

Var newWidth As Double = 150
This is the image Width, not Resolution.

the default 150 is perfect for my current purpose.
My Retina screen dpi is… 144 (current setting), but it can be more (default setting).

Note to self: I am doing so many errors ! Other’s errors are so easy to find, why mine are so hard (for me) ? :wink:

Things change with time…

This was an example to test being able to add an image at a higher resolution, not my actual code.
I’m aware 159 is the width of the placement.
The resolution should have been 600dpi in the pdf document version and 159 in the DynaPDF version.

Thanks, Emile.