Reputation: 1218
I have a pdf that has an Image Field
and in swift I have a UIImage
, how do I draw the UIImage
on the pdf where the Image Field
annotation is?
Attempt 1
I have tried setting some fields on the annotation to the image by converting it to a base64 string with no luck.
let image: UIImage = UIImage.shapeImageWithBezierPath(bezierPath: path, fillColor: .white, strokeColor: .black)
let data = image.jpegData(compressionQuality: 0.5)
annotation.widgetStringValue = String(data?.base64EncodedString() ?? "")
annotation.contents = String(data?.base64EncodedString() ?? "")
Attempt 2
I also found this similar question Cannot add image and save to pdf file using PDFKit, but it creates a new annotation and places it on top of the page, while I need to place my image in or on top of an annotation on my PDF.
Using the above question I tried the following without any luck.
let image: UIImage = UIImage.shapeImageWithBezierPath(bezierPath: path, fillColor: .white, strokeColor: .black)
let pageBounds = page.bounds(for: .cropBox)
let imageBounds = CGRect(x: pageBounds.midX, y: pageBounds.midY, width: image.size.width, height: image.size.height)
let imageStamp = PDFImageAnnotation(image, bounds: imageBounds, properties: nil)
imageStamp.shouldDisplay = true
imageStamp.shouldPrint = true
annotation.page?.addAnnotation(imageStamp)
Attempt 3
I have also tried drawing the image onto the annotation like the following, but it doesn't appear on the pdf.
let image: UIImage = UIImage.shapeImageWithBezierPath(bezierPath: path, fillColor: .white, strokeColor: .black)
image.draw(in: annotation.accessibilityFrame)
Attempt 4
I discovered I can draw a UIBezierPath
on my annotation with the following code, but my image has to be saved as base64 in my database which cannot be converted back to an UIBezierPath
, so I still need to determine how to draw an image on an annotation.
annotation.type = "Ink"
annotation.color = UIColor(.black)
annotation.add(path) //path being my `UIBezierPath`
Thanks for any help!!!!
Upvotes: 1
Views: 784
Reputation: 1218
I was able to draw my image inside the annotation image bounds and then replace the annotation by writing this class
final private class PDFImageAnnotation: PDFAnnotation {
var image: UIImage?
convenience init(image: UIImage?, properties: [AnyHashable: Any]?, rect: CGRect) {
//set bounds & image
self.init(bounds: rect, forType: .stamp, withProperties: properties)
self.image = image
}
override func draw(with box: PDFDisplayBox, in context: CGContext) {
//flip image context if upside down
//context.translateBy(x: 0.0, y: 235) //y depends on image height, image will disappear (out of bounds) if not set correctly
//context.scaleBy(x: 1.0, y: -1.0)
//draw image
guard let cgImage = image?.cgImage else { return }
context.draw(cgImage, in: self.bounds)
}
}
And calling this during my pdf generation
//make UIImage from base64
let uiImage = UIImage(data: Data(base64Encoded: String(data?.base64EncodedString() ?? ""))!)
//get image bounds from current pdf annotation
let imageBounds = CGRect(x: (annotation.startPoint.x * -1), y: (annotation.startPoint.y * -1), width: 100, height: 20)
//create image annotation with class
let imageStamp = PDFImageAnnotation(image: uiImage, properties: nil, rect: imageBounds)
//remove old annotation
page.removeAnnotation(annotation)
//add new annotation
imageStamp.fieldName = "CustomerSignature"
page.addAnnotation(imageStamp)
A better solution may be to write an extension class for PDFAnnotation
extension PDFAnnotation {
func draw(with box: PDFDisplayBox, in context: CGContext, cgImage: CGImage) {
//flip image context if upside down
//context.translateBy(x: 0.0, y: 235) //y depends on image height, image will disappear (out of bounds) if not set correctly
//context.scaleBy(x: 1.0, y: -1.0)
context.scaleBy(x: 1.0, y: -1.0)
context.draw(cgImage, in: self.bounds)
}
}
But I am unsure how to pass in the CGContext
. . .
annotation.draw(with: pdfView.displayBox, in ????, cgImage: cgImage)
Upvotes: 1