More languages
Some test text!
More languages
Sample Swift code to use PDFTron SDK's page writing API to generate new pages, embed fonts & images, and copy graphical elements from one page to another. Learn more about our Swift PDF Library and PDF Editing & Manipulation Library.
Get Started Samples DownloadTo run this sample, get started with a free trial of Apryse SDK.
//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2019 by PDFTron Systems Inc. All Rights Reserved.
// Consult legal.txt regarding legal and license information.
//---------------------------------------------------------------------------------------
import PDFNet
import Foundation
func runElementBuilderTest() -> Int {
return autoreleasepool {
var ret: Int = 0
do {
try PTPDFNet.catchException {
let doc: PTPDFDoc = PTPDFDoc()
let eb: PTElementBuilder = PTElementBuilder() // ElementBuilder is used to build new Element objects
let writer: PTElementWriter = PTElementWriter() // ElementWriter is used to write Elements to the page
var element: PTElement
var gstate: PTGState
// Start a new page ------------------------------------
var page: PTPage? = doc.pageCreate(PTPDFRect(x1: 0, y1: 0, x2: 612, y2: 794))
writer.writerBegin(with: page, placement: e_ptoverlay, page_coord_sys: true, compress: true, resources: nil) // begin writing to the page
// Create an Image that can be reused in the document or on the same page.
let img: PTImage = PTImage.create(doc.getSDFDoc(), filename: Bundle.main.path(forResource: "peppers", ofType: "jpg"))
element = eb.createImage(withMatrix: img, mtx: PTMatrix2D(a: Double(img.getWidth() / 2), b: -145, c: 20, d: Double(img.getHeight() / 2), h: 200, v: 150))
writer.writePlacedElement(element)
gstate = element.getGState() // use the same image (just change its matrix)
gstate.setTransform(200, b: 0, c: 0, d: 300, h: 50, v: 450)
writer.writePlacedElement(element)
// use the same image again (just change its matrix).
writer.writePlacedElement(eb.createImage(withCornerAndScale: img, x: 300, y: 600, hscale: 200, vscale: -150))
writer.end() // save changes to the current page
doc.pagePushBack(page)
// Start a new page ------------------------------------
// Construct and draw a path object using different styles
page = doc.pageCreate(PTPDFRect(x1: 0, y1: 0, x2: 612, y2: 794))
writer.writerBegin(with: page, placement: e_ptoverlay, page_coord_sys: true, compress: true, resources: nil) // begin writing to the page
eb.reset(PTGState()) // Reset the GState to default
eb.pathBegin() // start constructing the path
eb.move(to: 306, y: 396)
eb.curve(to: 681, cy1: 771, cx2: 399.75, cy2: 864.75, x2: 306, y2: 771)
eb.curve(to: 212.25, cy1: 864.75, cx2: -69, cy2: 771, x2: 306, y2: 396)
eb.closePath()
element = eb.pathEnd() // the path is now finished
element.setPathFill(true) // the path should be filled
// Set the path color space and color
gstate = element.getGState()
gstate.setFill(PTColorSpace.createDeviceCMYK())
gstate.setFillColor(with: PTColorPt(x: 1, y: 0, z: 0, w: 0)) // cyan
gstate.setTransform(0.5, b: 0, c: 0, d: 0.5, h: -20, v: 300)
writer.writePlacedElement(element)
// Draw the same path using a different stroke color
element.setPathStroke(true) // this path is should be filled and stroked
gstate.setFillColor(with: PTColorPt(x: 0, y: 0, z: 1, w: 0)) // yellow
gstate.setStroke(PTColorSpace.createDeviceRGB())
gstate.setStrokeColor(with: PTColorPt(x: 1, y: 0, z: 0, w: 0)) // red
gstate.setTransform(0.5, b: 0, c: 0, d: 0.5, h: 280, v: 300)
gstate.setLineWidth(20)
writer.writePlacedElement(element)
// Draw the same path with with a given dash pattern
element.setPathFill(false) // this path is should be only stroked
gstate.setStrokeColor(with: PTColorPt(x: 0, y: 0, z: 1, w: 0)) // blue
gstate.setTransform(0.5, b: 0, c: 0, d: 0.5, h: 280, v: 0)
let dash_pattern = NSMutableArray(capacity: 1)
dash_pattern.add(30.0)
gstate.setDashPattern(dash_pattern, phase: 0)
writer.writePlacedElement(element)
// Use the path as a clipping path
writer.write(eb.createGroupBegin())
// Save the graphics state
// Start constructing the new path (the old path was lost when we created
// a new Element using CreateGroupBegin()).
eb.pathBegin()
eb.move(to: 306, y: 396)
eb.curve(to: 681, cy1: 771, cx2: 399.75, cy2: 864.75, x2: 306, y2: 771)
eb.curve(to: 212.25, cy1: 864.75, cx2: -69, cy2: 771, x2: 306, y2: 396)
eb.closePath()
element = eb.pathEnd() // path is now constructed
element.setPathClip(true) // this path is a clipping path
element.setPathStroke(true) // this path should be filled and stroked
gstate = element.getGState()
gstate.setTransform(0.5, b: 0, c: 0, d: 0.5, h: -20, v: 0)
writer.write(element)
writer.write(eb.createImage(withCornerAndScale: img, x: 100, y: 300, hscale: 400, vscale: 600))
writer.write(eb.createGroupEnd()) // Restore the graphics state
writer.end() // save changes to the current page
doc.pagePushBack(page)
// Start a new page ------------------------------------
page = doc.pageCreate(PTPDFRect(x1: 0, y1: 0, x2: 612, y2: 794))
writer.writerBegin(with: page, placement: e_ptoverlay, page_coord_sys: true, compress: true, resources: nil) // begin writing to this page
eb.reset(PTGState()) // Reset the GState to default
// Begin writing a block of text
element = eb.createTextBegin(with: PTFont.create(doc.getSDFDoc(), type: e_pttimes_roman, embed: false), font_sz: 12)
writer.write(element)
element = eb.createTextRun("Hello World!")
element.setTextMatrix(10, b: 0, c: 0, d: 10, h: 0, v: 600)
element.getGState().setLeading(15) // Set the spacing between lines
writer.write(element)
writer.write(eb.createTextNewLine()) // New line
element = eb.createTextRun("Hello World!")
gstate = element.getGState()
gstate.setTextRenderMode(e_ptstroke_text)
gstate.setCharSpacing(-1.25)
gstate.setWordSpacing(-1.25)
writer.write(element)
writer.write(eb.createTextNewLine()) // New line
element = eb.createTextRun("Hello World!")
gstate = element.getGState()
gstate.setCharSpacing(0)
gstate.setWordSpacing(0)
gstate.setLineWidth(3)
gstate.setTextRenderMode(e_ptfill_stroke_text)
gstate.setStroke(PTColorSpace.createDeviceRGB())
gstate.setStrokeColor(with: PTColorPt(x: 1, y: 0, z: 0, w: 0)) // red
gstate.setFill(PTColorSpace.createDeviceCMYK())
gstate.setFillColor(with: PTColorPt(x: 1, y: 0, z: 0, w: 0)) // cyan
writer.write(element)
writer.write(eb.createTextNewLine()) // New line
// Set text as a clipping path to the image.
element = eb.createTextRun("Hello World!")
gstate = element.getGState()
gstate.setTextRenderMode(e_ptclip_text)
writer.write(element)
// Finish the block of text
writer.write(eb.createTextEnd())
// Draw an image that will be clipped by the above text
writer.write(eb.createImage(withCornerAndScale: img, x: 10, y: 100, hscale: 1300, vscale: 720))
writer.end() // save changes to the current page
doc.pagePushBack(page)
// Start a new page ------------------------------------
//
// The example illustrates how to embed the external font in a PDF document.
// The example also shows how ElementReader can be used to copy and modify
// Elements between pages.
let reader: PTElementReader = PTElementReader()
// Start reading Elements from the last page. We will copy all Elements to
// a new page but will modify the font associated with text.
reader.begin(doc.getPage(UInt32(doc.getPageCount())))
page = doc.pageCreate(PTPDFRect(x1: 0, y1: 0, x2: 1300, y2: 794))
writer.writerBegin(with: page, placement: e_ptoverlay, page_coord_sys: true, compress: true, resources: nil) // begin writing to this page
eb.reset(PTGState()) // Reset the GState to default
// Embed an external font in the document.
let font = PTFont.createTrueTypeFont(doc.getSDFDoc(), font_path: Bundle.main.path(forResource: "font", ofType: "ttf"), embed: true, subset: true)
while let element = reader.next() {
if element.getType().rawValue == e_pttext.rawValue {
element.getGState().setFont(font, font_sz: 12)
}
writer.write(element)
}
reader.end()
writer.end() // save changes to the current page
doc.pagePushBack(page)
// Start a new page ------------------------------------
//
// The example illustrates how to embed the external font in a PDF document.
// The example also shows how ElementReader can be used to copy and modify
// Elements between pages.
// Start reading Elements from the last page. We will copy all Elements to
// a new page but will modify the font associated with text.
reader.begin(doc.getPage(UInt32(doc.getPageCount())))
page = doc.pageCreate(PTPDFRect(x1: 0, y1: 0, x2: 1300, y2: 794))
writer.writerBegin(with: page, placement: e_ptoverlay, page_coord_sys: true, compress: true, resources: nil) // begin writing to this page
eb.reset(PTGState()) // Reset the GState to default
// Embed an external font in the document.
let font2 = PTFont.createType1Font(doc.getSDFDoc(), font_path: Bundle.main.path(forResource: "Misc-Fixed", ofType: "pfa"), embed: true)
while let element = reader.next() {
if element.getType().rawValue == e_pttext.rawValue {
element.getGState().setFont(font2, font_sz: 12)
}
writer.write(element)
}
reader.end()
writer.end() // save changes to the current page
doc.pagePushBack(page)
// Start a new page ------------------------------------
page = doc.pageCreate(PTPDFRect(x1: 0, y1: 0, x2: 612, y2: 792))
writer.writerBegin(with: page, placement: e_ptoverlay, page_coord_sys: true, compress: true, resources: nil) // begin writing to this page
eb.reset(PTGState()) // Reset the GState to default
// Begin writing a block of text
element = eb.createTextBegin(with: PTFont.create(doc.getSDFDoc(), type: e_pttimes_roman, embed: false), font_sz: 12)
element.setTextMatrix(1.5, b: 0, c: 0, d: 1.5, h: 50, v: 600)
element.getGState().setLeading(15) // Set the spacing between lines
writer.write(element)
let para = """
A PDF text object consists of operators that can show \
text strings, move the text position, and set text state and certain \
other parameters. In addition, there are three parameters that are \
defined only within a text object and do not persist from one text \
object to the next: Tm, the text matrix, Tlm, the text line matrix, \
Trm, the text rendering matrix, actually just an intermediate result \
that combines the effects of text state parameters, the text matrix \
(Tm), and the current transformation matrix
"""
let para_end = para.count
var text_run = 0
let para_width: Double = 300 // paragraph width is 300 units
var cur_width: Double = 0
while text_run < para_end {
var text_run_end: Int = (para as NSString).range(of: " ", options: .literal, range: NSRange(location: text_run, length: para.count - text_run)).location
if text_run_end == NSNotFound {
text_run_end = para_end - 1
}
let str: String = (para as NSString).substring(with: NSRange(location: text_run, length: text_run_end - text_run + 1))
element = eb.createTextRun(str)
if cur_width + element.getTextLength() < para_width {
writer.write(element)
cur_width = cur_width + element.getTextLength()
}
else {
writer.write(eb.createTextNewLine()) // New line
element = eb.createTextRun(str)
cur_width = element.getTextLength()
writer.write(element)
}
text_run = text_run_end + 1
}
// -----------------------------------------------------------------------
// The following code snippet illustrates how to adjust spacing between
// characters (text runs).
element = eb.createTextNewLine()
writer.write(element) // Skip 2 lines
writer.write(element)
writer.write(eb.createTextRun("An example of space adjustments between inter-characters:"))
writer.write(eb.createTextNewLine())
// Write string "AWAY" without space adjustments between characters.
element = eb.createTextRun("AWAY")
writer.write(element)
writer.write(eb.createTextNewLine())
// Write string "AWAY" with space adjustments between characters.
element = eb.createTextRun("A")
writer.write(element)
element = eb.createTextRun("W")
element.setPosAdjustment(140)
writer.write(element)
element = eb.createTextRun("A")
element.setPosAdjustment(140)
writer.write(element)
element = eb.createTextRun("Y again")
element.setPosAdjustment(115)
writer.write(element)
// Draw the same strings using direct content output...
writer.flush() // flush pending Element writing operations.
// You can also write page content directly to the content stream using
// ElementWriter.WriteString(...) and ElementWriter.WriteBuffer(...) methods.
// Note that if you are planning to use these functions you need to be familiar
// with PDF page content operators (see Appendix A in PDF Reference Manual).
// Because it is easy to make mistakes during direct output we recommend that
// you use ElementBuilder and Element interface instead.
writer.write("T* T* ") // Skip 2 lines
writer.write("(Direct output to PDF page content stream:) Tj T* ")
writer.write("(AWAY) Tj T* ")
writer.write("[(A)140(W)140(A)115(Y again)] TJ ")
// Finish the block of text
writer.write(eb.createTextEnd())
writer.end() // save changes to the current page
doc.pagePushBack(page)
// Start a new page ------------------------------------
// Image Masks
//
// In the opaque imaging model, images mark all areas they occupy on the page as
// if with opaque paint. All portions of the image, whether black, white, gray,
// or color, completely obscure any marks that may previously have existed in the
// same place on the page.
// In the graphic arts industry and page layout applications, however, it is common
// to crop or 'mask out' the background of an image and then place the masked image
// on a different background, allowing the existing background to show through the
// masked areas. This sample illustrates how to use image masks.
page = doc.pageCreate(PTPDFRect(x1: 0, y1: 0, x2: 612, y2: 792))
writer.writerBegin(with: page, placement: e_ptoverlay, page_coord_sys: true, compress: true, resources: nil) // begin writing to this page
// Create the Image Mask
let imgf = PTMappedFile(filename: Bundle.main.path(forResource: "imagemask", ofType: "dat"))
let mask_read = PTFilterReader(filter: imgf)
let device_gray = PTColorSpace.createDeviceGray()
let mask: PTImage = PTImage.create(withStreamAndFormat: doc.getSDFDoc(), image_data: mask_read, width: 64, height: 64, bpc: 1, color_space: device_gray, input_format: e_ptascii_hex)
mask.getSDFObj().putBool("ImageMask", value: true)
element = eb.createRect(0, y: 0, width: 612, height: 794)
element.setPathStroke(false)
element.setPathFill(true)
element.getGState().setFill(device_gray)
element.getGState().setFillColor(with: PTColorPt(x: 0.8, y: 0, z: 0, w: 0))
writer.writePlacedElement(element)
element = eb.createImage(withMatrix: mask, mtx: PTMatrix2D(a: 200, b: 0, c: 0, d: -200, h: 40, v: 680))
element.getGState().setFillColor(with: PTColorPt(x: 0.1, y: 0, z: 0, w: 0))
writer.writePlacedElement(element)
element.getGState().setFill(PTColorSpace.createDeviceRGB())
element.getGState().setFillColor(with: PTColorPt(x: 1, y: 0, z: 0, w: 0))
element = eb.createImage(withMatrix: mask, mtx: PTMatrix2D(a: 200, b: 0, c: 0, d: -200, h: 320, v: 680))
writer.writePlacedElement(element)
element.getGState().setFillColor(with: PTColorPt(x: 0, y: 1, z: 0, w: 0))
element = eb.createImage(withMatrix: mask, mtx: PTMatrix2D(a: 200, b: 0, c: 0, d: -200, h: 40, v: 380))
writer.writePlacedElement(element)
do {
// This sample illustrates Explicit Masking.
let img: PTImage = PTImage.create(withFile: doc.getSDFDoc(), filename: Bundle.main.path(forResource: "peppers", ofType: "jpg"), encoder_hints: PTObj())
// mask is the explicit mask for the primary (base) image
img.setMaskWith(mask)
element = eb.createImage(withMatrix: img, mtx: PTMatrix2D(a: 200, b: 0, c: 0, d: -200, h: 320, v: 380))
writer.writePlacedElement(element)
}
writer.end() // save changes to the current page
doc.pagePushBack(page)
// Transparency sample ----------------------------------
// Start a new page -------------------------------------
page = doc.pageCreate(PTPDFRect(x1: 0, y1: 0, x2: 612, y2: 792))
writer.writerBegin(with: page, placement: e_ptoverlay, page_coord_sys: true, compress: true, resources: nil) // begin writing to this page
eb.reset(PTGState()) // Reset the GState to default
// Write some transparent text at the bottom of the page.
element = eb.createTextBegin(with: PTFont.create(doc.getSDFDoc(), type: e_pttimes_roman, embed: false), font_sz: 100)
// Set the text knockout attribute. Text knockout must be set outside of
// the text group.
gstate = element.getGState()
gstate.setTextKnockout(false)
gstate.setBlendMode(e_ptbl_difference)
writer.write(element)
element = eb.createTextRun("Transparency")
element.setTextMatrix(1, b: 0, c: 0, d: 1, h: 30, v: 30)
gstate = element.getGState()
gstate.setFill(PTColorSpace.createDeviceCMYK())
gstate.setFillColor(with: PTColorPt(x: 1, y: 0, z: 0, w: 0))
gstate.setFillOpacity(0.5)
writer.write(element)
// Write the same text on top the old; shifted by 3 points
element.setTextMatrix(1, b: 0, c: 0, d: 1, h: 33, v: 33)
gstate.setFillColor(with: PTColorPt(x: 0, y: 1, z: 0, w: 0))
gstate.setFillOpacity(0.5)
writer.write(element)
writer.write(eb.createTextEnd())
// Draw three overlapping transparent circles.
eb.pathBegin() // start constructing the path
eb.move(to: 459.223, y: 505.646)
eb.curve(to: 459.223, cy1: 415.841, cx2: 389.85, cy2: 343.04, x2: 304.273, y2: 343.04)
eb.curve(to: 218.697, cy1: 343.04, cx2: 149.324, cy2: 415.841, x2: 149.324, y2: 505.646)
eb.curve(to: 149.324, cy1: 595.45, cx2: 218.697, cy2: 668.25, x2: 304.273, y2: 668.25)
eb.curve(to: 389.85, cy1: 668.25, cx2: 459.223, cy2: 595.45, x2: 459.223, y2: 505.646)
element = eb.pathEnd()
element.setPathFill(true)
gstate = element.getGState()
gstate.setFill(PTColorSpace.createDeviceRGB())
gstate.setFillColor(with: PTColorPt(x: 0, y: 0, z: 1, w: 0)) // Blue Circle
gstate.setBlendMode(e_ptbl_normal)
gstate.setFillOpacity(0.5)
writer.write(element)
// Translate relative to the Blue Circle
gstate.setTransform(1, b: 0, c: 0, d: 1, h: 113, v: -185)
gstate.setFillColor(with: PTColorPt(x: 0, y: 1, z: 0, w: 0)) // Green Circle
gstate.setFillOpacity(0.5)
writer.write(element)
// Translate relative to the Green Circle
gstate.setTransform(1, b: 0, c: 0, d: 1, h: -220, v: 0)
gstate.setFillColor(with: PTColorPt(x: 1, y: 0, z: 0, w: 0)) // Red Circle
gstate.setFillOpacity(0.5)
writer.write(element)
writer.end() // save changes to the current page
doc.pagePushBack(page)
// End page ------------------------------------
doc.save(toFile: URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]).appendingPathComponent("element_builder.pdf").path, flags: e_ptremove_unused.rawValue)
// doc.Save((output_path + "element_builder.pdf").c_str(), Doc::e_ptlinearized, NULL);
print("Done. Result saved in element_builder.pdf...")
}
} catch let e as NSError {
print("Uncaught exception: \(e)")
ret = 1
}
return ret
}
}