PDF Reader night mode - ios

I am working on a pdf reader but I am facing problem in creating night mode for a PDF Document. I have successfully created the new PDF Document with Black background and white foreground. but can not do for an already created document I am doing for new PDF Document is
func show(text:NSAttributedString) {
// let attributedString = NSAttributedString(string: text, attributes: [NSAttributedString.Key.foregroundColor: UIColor.white])
// text.attribute(NSAttributedString.Key.foregroundColor, at: 0, effectiveRange: NSRange(location: 0, length: text.length))
let printFormatter = UISimpleTextPrintFormatter(attributedText: text)
let renderer = UIPrintPageRenderer()
renderer.addPrintFormatter(printFormatter, startingAtPageAt: 0)
// A4 size
let pageSize = CGSize(width: 595.2, height: 841.8)
// Use this to get US Letter size instead
// let pageSize = CGSize(width: 612, height: 792)
// create some sensible margins
let pageMargins = UIEdgeInsets(top: 72, left: 72, bottom: 72, right: 72)
// calculate the printable rect from the above two
let printableRect = CGRect(x: pageMargins.left, y: pageMargins.top, width: pageSize.width - pageMargins.left - pageMargins.right, height: pageSize.height - pageMargins.top - pageMargins.bottom)
// and here's the overall paper rectangle
let paperRect = CGRect(x: 0, y: 0, width: pageSize.width, height: pageSize.height)
renderer.setValue(NSValue(cgRect: paperRect), forKey: "paperRect")
renderer.setValue(NSValue(cgRect: printableRect), forKey: "printableRect")
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, paperRect, nil)
renderer.prepare(forDrawingPages: NSMakeRange(0, renderer.numberOfPages))
let bounds = UIGraphicsGetPDFContextBounds()
for i in 0 ..< renderer.numberOfPages {
UIGraphicsBeginPDFPage()
let currentContext = UIGraphicsGetCurrentContext()
currentContext?.setFillColor(UIColor.yellow.cgColor)
currentContext?.fill(bounds)
renderer.drawPage(at: i, in: bounds)
}
UIGraphicsEndPDFContext()
var pdfUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
pdfUrl?.appendPathComponent("text")
pdfUrl?.appendPathExtension("pdf")
do {
try pdfData.write(to: pdfUrl!)
} catch {
print(error.localizedDescription)
}
let pdfdocemrnt = PDFDocument(url: pdfUrl!)
self.baseView.document = pdfdocemrnt!
}
Please help if someone knows the issue.

Related

PDFPage size/bounds won't change with setBounds unless setting a smaller size

Code below perfectly changes bounds if setting a smaller size. But when setting a larger size it won't work. Isn't it possible to upscale a PDFPage size?
what works:
let page = PDFPage()
let rectBefore = page.bounds(for: .cropBox)
print("rectBefore \(rectBefore)")
page.setBounds(CGRect(x: 0, y: 0, width: 500, height: 500), for: .cropBox)
let rectAfter = page.bounds(for: .cropBox)
print("rectAfter \(rectAfter)")
// prints:
// rectBefore (0.0, 0.0, 612.0, 792.0)
// rectAfter (0.0, 0.0, 500.0, 500.0) -> Works as expected
what won't work:
let page = PDFPage()
let rectBefore = page.bounds(for: .cropBox)
print("rectBefore \(rectBefore)")
page.setBounds(CGRect(x: 0, y: 0, width: 1000, height: 1000), for: .cropBox)
let rectAfter = page.bounds(for: .cropBox)
print("rectAfter \(rectAfter)")
// prints:
// rectBefore (0.0, 0.0, 612.0, 792.0)
// rectAfter (0.0, 0.0, 612.0, 792.0) -> Didn't change
PDFPage() gives you a default 8.5" x 11.0" page.
You cannot make the .cropBox (or any PDFDisplayBox) larger than the page itself.
If you want to create a different size page, you'll probably want to use UIGraphicsPDFRenderer to create the data, and then PDFDocument(data: theData) to generate the PDF document with the desired page size.
For example:
let pdfMetaData = [
kCGPDFContextCreator: "Test Creator",
kCGPDFContextAuthor: "Test Author"
]
let format = UIGraphicsPDFRendererFormat()
format.documentInfo = pdfMetaData as [String: Any]
// 1000 x 1000 point-size page
let pageWidth = 1000
let pageHeight = 1000
let pageRect = CGRect(x: 0, y: 0, width: pageWidth, height: pageHeight)
let renderer = UIGraphicsPDFRenderer(bounds: pageRect, format: format)
let pData = renderer.pdfData { (context) in
context.beginPage()
let attributes = [
NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 40)
]
let text = "1,000 x 1,000 (approx 13.8\" x 13.8\") pdf page"
text.draw(at: CGPoint(x: 0, y: 0), withAttributes: attributes)
}
if let pdd = PDFDocument(data: pData),
let pdfPage = pdd.page(at: 0)
{
print(pdfPage.bounds(for: .cropBox))
}

iOS print NSAttributedString with images as NSTextAttachement to PDF

I'm trying to convert the content of an UITextView to PDF. The UITextView uses an NSAttributedString that contains text and images.
The images are instances of NSTextAttachment.
I went through the UIPrintPageRenderer way passing the UIPrintFormatter that I get from the UITextView through its viewPrintFormatter() function and it works perfectly for the text but I can't see any of the images. It looks like the images are actually taking up space as I can see the empty space between text lines, but no image is being rendered.
I suspect it might be the formatter, but I don't know how to work around it.
Any help is greatly appreciated.
The code I'm using to create the PDF from the NSAttributedString is the following:
public func createPDF(text: NSAttributedString, documentPath: URL, customPrintFormatter: UIPrintFormatter? = nil) {
let printFormatter = customPrintFormatter == nil ? UISimpleTextPrintFormatter(attributedText: text) : customPrintFormatter!
let renderer = UIPrintPageRenderer()
renderer.addPrintFormatter(printFormatter, startingAtPageAt: 0)
// A4 size
let pageSize = CGSize(width: 595.2, height: 841.8)
// create some sensible margins
let pageMargins = UIEdgeInsets(top: 72, left: 72, bottom: 72, right: 72)
// calculate the printable rect from the above two
let printableRect = CGRect(x: pageMargins.left, y: pageMargins.top, width: pageSize.width - pageMargins.left - pageMargins.right, height: pageSize.height - pageMargins.top - pageMargins.bottom)
// and here's the overall paper rectangle
let paperRect = CGRect(x: 0, y: 0, width: pageSize.width, height: pageSize.height)
renderer.setValue(NSValue(cgRect: paperRect), forKey: "paperRect")
renderer.setValue(NSValue(cgRect: printableRect), forKey: "printableRect")
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, paperRect, nil)
renderer.prepare(forDrawingPages: NSMakeRange(0, renderer.numberOfPages))
let bounds = UIGraphicsGetPDFContextBounds()
for i in 0 ..< renderer.numberOfPages {
UIGraphicsBeginPDFPage()
renderer.drawPage(at: i, in: bounds)
}
UIGraphicsEndPDFContext()
do {
try pdfData.write(to: documentPath)
} catch {
print(error.localizedDescription)
}
}
The following is the code that creates the NSTextAttachment
let attachment = NSTextAttachment()
attachment.image = UIImage.init(named: "1.png")
attachment.bounds = CGRect.init(x: 0, y: 0, width: 200, height: 100)
let img = NSMutableAttributedString.init(attachment: attachment)
let imgRange = NSRange.init(location: match.range(at: 0).location + match.range(at: 0).length, length: img.length)
self.beginEditing()
backingStore.insert(img, at: match.range(at: 0).location + match.range(at: 0).length)
let r = NSMakeRange(match.range(at: 0).location + match.range(at: 0).length, img.length)
self.edited([.editedCharacters, .editedAttributes], range: range, changeInLength: img.length)
self.endEditing()

SpriteKit draw upside down text

In a playground, I am trying to make a SpriteKit scene with a top left origin going down (ie like a drawing program). Everything works except for text which is flipped. I need to make the text right side up. I am missing something. If I add the translate and scale, the text vanishes.
//: A SpriteKit based Playground
import PlaygroundSupport
import SpriteKit
class GameScene: SKScene
{
static let width = 1000
static let height = 1800
override func didMove(to view: SKView)
{
self.backgroundColor = SKColor.white
let cam = SKCameraNode()
self.camera = cam
cam.yScale = -1
let node = SKSpriteNode(color: SKColor.yellow, size: CGSize(width: 500, height: 300))
node.anchorPoint = CGPoint(x: 0, y: 0)
node.position = CGPoint(x: 10, y: 10)
let renderer = UIGraphicsImageRenderer(size: CGSize(width: 200, height: 200))
let img = renderer.image { ctx in
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
let attrs = [NSAttributedStringKey.font: UIFont(name: "Futura", size: 72)!, NSAttributedStringKey.paragraphStyle: paragraphStyle]
//ctx.cgContext.translateBy(x: 0, y:200)
//ctx.cgContext.scaleBy(x: 0, y: -1)
let string = "Test"
string.draw(with: CGRect(x: 32, y: 32, width: 200, height: 200), options: .usesLineFragmentOrigin, attributes: attrs, context: nil)
}
let tex = SKTexture(image: img)
let zzz = SKSpriteNode(texture: tex)
zzz.anchorPoint = CGPoint(x: 0, y: 0)
zzz.position = CGPoint(x: 10, y: 10)
node.addChild(zzz)
// let z = SKSpriteNode(color: SKColor.red, size: CGSize(width: 200, height: 150))
// z.anchorPoint = CGPoint(x: 0, y: 0)
// z.position = CGPoint(x: 10, y: 10)
// node.addChild(z)
//
// let q = SKSpriteNode(color: SKColor.green, size: CGSize(width: 80, height: 70))
// q.anchorPoint = CGPoint(x: 0, y: 0)
// q.position = CGPoint(x: 10, y: 10)
// z.addChild(q)
self.addChild(node)
self.addChild(cam)
cam.position = CGPoint(x: GameScene.width/2, y: GameScene.height/2)
}
}
let sceneView = SKView(frame: CGRect(x:0 , y:0, width: 480, height: 640))
let scene = GameScene(size: CGSize(width: GameScene.width, height: GameScene.height))
scene.scaleMode = .aspectFit
sceneView.presentScene(scene)
PlaygroundSupport.PlaygroundPage.current.liveView = sceneView
Update:
ctx.cgContext.textMatrix = .identity
ctx.cgContext.translateBy(x: 0, y: 200)
ctx.cgContext.scaleBy(x: 1.0, y: -1.0)
now draws the text rightside up, but it is wrapped at 50% of the width
Final Update:
This worked, its rightsize up. The font size is proportional to the scene size (which is a dimension that fits on all iOS devices.
self.camera = cam
cam.yScale = -1
let boxSize = CGSize(width: 500, height: 500)
let node = SKSpriteNode(color: SKColor.yellow, size: boxSize)
node.anchorPoint = CGPoint(x: 0, y: 0)
node.position = CGPoint(x: 10, y: 10)
let renderer = UIGraphicsImageRenderer(size: boxSize)
let img = renderer.image { ctx in
let bounds = CGRect(x: 16, y: 0, width: boxSize.width-32, height: boxSize.height)
let string = "This is a long test with many lines."
let range = NSRange( location: 0, length: string.count)
guard let context = UIGraphicsGetCurrentContext() else { return }
let path = CGMutablePath()
path.addRect(bounds)
let attrString = NSMutableAttributedString(string: string)
attrString.addAttribute(NSAttributedStringKey.font, value: UIFont(name: "Futura", size: 84)!, range: range )
let framesetter = CTFramesetterCreateWithAttributedString(attrString as CFAttributedString)
let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, attrString.length), path, nil)
CTFrameDraw(frame, context)
}
You should read https://www.raywenderlich.com/153591/core-text-tutorial-ios-making-magazine-app
CoreText inverts (technically, rotates) text in iOS. This is possibly because it is shared with MacOS which uses a different coordinate system. (Though why they couldn't fix this for iOS I have no idea).
Whatever the cause, you aren't doing anything wrong, iOS is doing the wrong thing. The simple solution (as per the linked article) is to simply rotate the text before drawing it.

how to create A4 size pdf by using webview ios swift

i tried following codes but it shows still small size of pdf....
let render = UIPrintPageRenderer()
let fmt = webView.viewPrintFormatter() UIMarkupTextPrintFormatter(markupText: htmlString!)
fmt.perPageContentInsets = UIEdgeInsets(top: 72, left: 72, bottom: 72, right: 72)
render.addPrintFormatter(webView.viewPrintFormatter(), startingAtPageAt: 0);
render.addPrintFormatter(fmt, startingAtPageAt: 0)
let page = CGRect(x: 0, y: 0, width: 595, height: 842)// take the size of the webView
let printable = page.insetBy(dx: 0, dy: 0)
render.setValue(NSValue(cgRect: page), forKey: "paperRect")
render.setValue(NSValue(cgRect: printable), forKey: "printableRect")
// 4. Create PDF context and draw
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, CGRect.zero, nil)
for i in 1 ... render.numberOfPages {
UIGraphicsBeginPDFPage();
let bounds = UIGraphicsGetPDFContextBounds()
render.drawPage(at: i - 1, in: bounds)
}
UIGraphicsEndPDFContext();
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
print(documentsPath)
pdfData.write(toFile: "\(documentsPath)/pdffName.pdf", atomically: true)

Swift PDF create Rectangle?

I would like to create an rectangle on an PDF File, but i dont how to do that. Its simple to create some text or images, but i would like to add some shapes like rectangles and circles.
Is the UIGraphicsBeginPDFPageWithInfo the same as the CGContext?
At the moment i am using this:
UIGraphicsBeginPDFContextToFile(pdfFileName, CGRectZero, nil);
UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, 612, 792), nil);
// add some text
let mainTitle = "..."
mainTitle.drawInRect(CGRectMake(30, 110, 552, 40), withAttributes: textAttributesBoldLargeHeader)
But how to add a custom rectangle?
Just get the PDF drawing context with UIGraphicsGetCurrentContext()
and draw anything to it. Simple example:
UIGraphicsBeginPDFContextToFile(pdfFileName, CGRectZero, nil);
UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, 612, 792), nil);
let context = UIGraphicsGetCurrentContext()
CGContextSetFillColorWithColor(context, UIColor.blueColor().CGColor)
let rect = CGRect(x: 10, y: 10, width: 100, height: 200)
CGContextFillRect(context, rect)
UIGraphicsEndPDFContext()
You can also extend UIView to render the current context and save the data as pdf file:
Swift 3 or later
extension UIView {
var pdfData: Data {
let result = NSMutableData()
UIGraphicsBeginPDFContextToData(result, frame, nil)
guard let context = UIGraphicsGetCurrentContext() else { return result as Data }
UIGraphicsBeginPDFPage()
layer.render(in: context)
UIGraphicsEndPDFContext()
return result as Data
}
}
Testing:
class ViewController: UIViewController {
let rectangle = UIBezierPath(rect: CGRect(x: 30, y: 110, width: 350, height: 40))
let shapeLayer = CAShapeLayer()
override func viewDidLoad() {
super.viewDidLoad()
shapeLayer.path = rectangle.cgPath
shapeLayer.strokeColor = UIColor.blue.cgColor
shapeLayer.fillColor = UIColor.red.cgColor
view.layer.addSublayer(shapeLayer)
do {
try view.pdfData.write(to: FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("view.pdf"), options: .atomic)
} catch {
print(error)
}
}
}

Resources