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.Heights
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
And this is why I renew your plugins every single year.
Thanks, Christian. When Covid is over you are getting a hug! (not really).
When Covid is done, weāll do some traveling for sure!
I may visit a few friends and do a few local Xojo meetings.
What resolution ?
You do not use:
Picture.HorizontalResolution
Picture.VerticalResolution
http://documentation.xojo.com/api/graphics/picture.html#picture-horizontalresolution
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
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.
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.
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.
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= MyLogoVar 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.PageGraphicsVar pic As picture= MyLogo
Var newWidth As Double = 150
Var theScale As Double = newWidth/pic.Width
Var newHeight As Double = pic.Height*theScaleg.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! (ć)
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) ?
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.
I know that this is an old thread, but I wanted to reply because this is an issue that I have come across and I seem to have figured out a workaround that just uses the native xojo PDFGraphics class.
Instead of scaling the picture like this (which results in poor resolution):
g.DrawPicture (Image, x, y,destWidth, destHeight, sourceX, sourceY, sourceWidth, sourceHeight)
I have discovered that if you use Graphics.Scale instead, then the resolution is good
I have tested this with the following code adapted from one of the Xojo blog posts on PDF rotation and scaling:
Var d As New PDFDocument
Var g As Graphics = d.Graphics
Var p As Picture = Picture.Open(SpecialFolder.Desktop.Child("r2d2.png"))
If p <> Nil Then
g.DrawPicture(p, 0, 0, p.Width/2, p.Height/2, 0, 0, p.Width, p.Height)
Var sf As Double = 0.5
g.Scale(sf, sf)
g.DrawPicture(p,0,p.Height)
Var f As FolderItem = SpecialFolder.Desktop.Child("RotateScaleTranslate.pdf")
d.Save(f)
f.Open
End If
You will see that it will draw the same picture twice, both the same size, but the first one has poor resolution while the second one looks crisp
I hope this helps someone else as it was a frustrating problem to troubleshoot!
Cheers,
Frank
That is great.
Thanks for sharing.