Skip to content

Commit

Permalink
Split image resizing and compression
Browse files Browse the repository at this point in the history
  • Loading branch information
philprime committed Jul 12, 2018
1 parent d0d08e0 commit d431d48
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 49 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
**Implemented enhancements:**

- Added options to `PDFImage`, allowing more precise control about resizing and compression.
- Improvements to internal image resizing and compression methods.

**Closed issues:**

- Issue #77
- Issue #78

## [1.1.2](https://github.com/Techprimate/TPPDF/tree/1.1.2) (2018-07-12)
[Full Changelog](https://github.com/Techprimate/TPPDF/compare/1.1.1...1.1.2)
Expand Down
95 changes: 64 additions & 31 deletions Example/Tests/Graphics/PDFGraphics_Spec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,46 +65,79 @@ class PDFGraphics_Spec : QuickSpec {
expect(dashes).to(haveCount(0))
}

it("can resize and compress an image") {
describe("resizing and compression") {

let base64String = "R0lGODlhPQBEAPeoAJosM//AwO/AwHVYZ/z595kzAP/s7P+goOXMv8+fhw/v739/f+8PD98fH/8mJl+fn/9ZWb8/PzWlwv///6wWGbImAPgTEMImIN9gUFCEm/gDALULDN8PAD6atYdCTX9gUNKlj8wZAKUsAOzZz+UMAOsJAP/Z2ccMDA8PD/95eX5NWvsJCOVNQPtfX/8zM8+QePLl38MGBr8JCP+zs9myn/8GBqwpAP/GxgwJCPny78lzYLgjAJ8vAP9fX/+MjMUcAN8zM/9wcM8ZGcATEL+QePdZWf/29uc/P9cmJu9MTDImIN+/r7+/vz8/P8VNQGNugV8AAF9fX8swMNgTAFlDOICAgPNSUnNWSMQ5MBAQEJE3QPIGAM9AQMqGcG9vb6MhJsEdGM8vLx8fH98AANIWAMuQeL8fABkTEPPQ0OM5OSYdGFl5jo+Pj/+pqcsTE78wMFNGQLYmID4dGPvd3UBAQJmTkP+8vH9QUK+vr8ZWSHpzcJMmILdwcLOGcHRQUHxwcK9PT9DQ0O/v70w5MLypoG8wKOuwsP/g4P/Q0IcwKEswKMl8aJ9fX2xjdOtGRs/Pz+Dg4GImIP8gIH0sKEAwKKmTiKZ8aB/f39Wsl+LFt8dgUE9PT5x5aHBwcP+AgP+WltdgYMyZfyywz78AAAAAAAD///8AAP9mZv///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAKgALAAAAAA9AEQAAAj/AFEJHEiwoMGDCBMqXMiwocAbBww4nEhxoYkUpzJGrMixogkfGUNqlNixJEIDB0SqHGmyJSojM1bKZOmyop0gM3Oe2liTISKMOoPy7GnwY9CjIYcSRYm0aVKSLmE6nfq05QycVLPuhDrxBlCtYJUqNAq2bNWEBj6ZXRuyxZyDRtqwnXvkhACDV+euTeJm1Ki7A73qNWtFiF+/gA95Gly2CJLDhwEHMOUAAuOpLYDEgBxZ4GRTlC1fDnpkM+fOqD6DDj1aZpITp0dtGCDhr+fVuCu3zlg49ijaokTZTo27uG7Gjn2P+hI8+PDPERoUB318bWbfAJ5sUNFcuGRTYUqV/3ogfXp1rWlMc6awJjiAAd2fm4ogXjz56aypOoIde4OE5u/F9x199dlXnnGiHZWEYbGpsAEA3QXYnHwEFliKAgswgJ8LPeiUXGwedCAKABACCN+EA1pYIIYaFlcDhytd51sGAJbo3onOpajiihlO92KHGaUXGwWjUBChjSPiWJuOO/LYIm4v1tXfE6J4gCSJEZ7YgRYUNrkji9P55sF/ogxw5ZkSqIDaZBV6aSGYq/lGZplndkckZ98xoICbTcIJGQAZcNmdmUc210hs35nCyJ58fgmIKX5RQGOZowxaZwYA+JaoKQwswGijBV4C6SiTUmpphMspJx9unX4KaimjDv9aaXOEBteBqmuuxgEHoLX6Kqx+yXqqBANsgCtit4FWQAEkrNbpq7HSOmtwag5w57GrmlJBASEU18ADjUYb3ADTinIttsgSB1oJFfA63bduimuqKB1keqwUhoCSK374wbujvOSu4QG6UvxBRydcpKsav++Ca6G8A6Pr1x2kVMyHwsVxUALDq/krnrhPSOzXG1lUTIoffqGR7Goi2MAxbv6O2kEG56I7CSlRsEFKFVyovDJoIRTg7sugNRDGqCJzJgcKE0ywc0ELm6KBCCJo8DIPFeCWNGcyqNFE06ToAfV0HBRgxsvLThHn1oddQMrXj5DyAQgjEHSAJMWZwS3HPxT/QMbabI/iBCliMLEJKX2EEkomBAUCxRi42VDADxyTYDVogV+wSChqmKxEKCDAYFDFj4OmwbY7bDGdBhtrnTQYOigeChUmc1K3QTnAUfEgGFgAWt88hKA6aCRIXhxnQ1yg3BCayK44EWdkUQcBByEQChFXfCB776aQsG0BIlQgQgE8qO26X1h8cEUep8ngRBnOy74E9QgRgEAC8SvOfQkh7FDBDmS43PmGoIiKUUEGkMEC/PJHgxw0xH74yx/3XnaYRJgMB8obxQW6kL9QYEJ0FIFgByfIL7/IQAlvQwEpnAC7DtLNJCKUoO/w45c44GwCXiAFB/OXAATQryUxdN4LfFiwgjCNYg+kYMIEFkCKDs6PKAIJouyGWMS1FSKJOMRB/BoIxYJIUXFUxNwoIkEKPAgCBZSQHQ1A2EWDfDEUVLyADj5AChSIQW6gu10bE/JG2VnCZGfo4R4d0sdQoBAHhPjhIB94v/wRoRKQWGRHgrhGSQJxCS+0pCZbEhAAOw=="

let data: Data! = Data(base64Encoded: base64String)
expect(data).toNot(beNil())

let image: UIImage! = UIImage(data: data)
expect(image).toNot(beNil())
var image: UIImage!
let resultFrame = CGRect(x: 0, y: 0, width: 40, height: 40)

beforeEach {
image = UIImage(data: data)
expect(image).toNot(beNil())

expect(image.size) == CGSize(width: 61, height: 68)
}

expect(image.size) == CGSize(width: 61, height: 68)
it("can resize image") {
let result = PDFGraphics.resizeAndCompressImage(image: image,
frame: resultFrame,
shouldResize: true,
shouldCompress: false,
quality: 0.2)
expect(result) !== image
expect(result.size) == CGSize(width: 25, height: 25)
}

it("can compress image") {
let result = PDFGraphics.resizeAndCompressImage(image: image,
frame: resultFrame,
shouldResize: false,
shouldCompress: true,
quality: 0.2)
expect(result) !== image
expect(result.size) == image.size
}

it("can resize and compress image") {
let result = PDFGraphics.resizeAndCompressImage(image: image,
frame: resultFrame,
shouldResize: true,
shouldCompress: true,
quality: 0.2)
expect(result) !== image
expect(result.size) == CGSize(width: 25.0, height: 25.0)
}

it("can return original image") {
let result = PDFGraphics.resizeAndCompressImage(image: image,
frame: resultFrame,
shouldResize: false,
shouldCompress: false,
quality: 0.2)
expect(result) === image
}

it("can compress an image") {
let result = PDFGraphics.resizeAndCompressImage(image: image,
frame: resultFrame,
shouldResize: true,
shouldCompress: true,
quality: 0.0)
expect(result) !== image
}

var compressFrame = CGRect(x: 0, y: 0, width: 40, height: 40)
var compressed = PDFGraphics.resizeAndCompressImage(image: image,
frame: compressFrame,
it("can resize and compress an image") {
let result = PDFGraphics.resizeAndCompressImage(image: image,
frame: resultFrame,
shouldResize: true,
shouldCompress: true,
quality: 1.0)
expect(compressed.size) == compressFrame.size

compressFrame = CGRect(x: 0, y: 0, width: 40.0, height: 40.0)
compressed = PDFGraphics.resizeAndCompressImage(image: image,
frame: compressFrame,
shouldResize: true,
shouldCompress: true,
quality: 0.2)
expect(compressed.size) == CGSize(width: 25.0, height: 25.0)

compressed = PDFGraphics.resizeAndCompressImage(image: image,
frame: compressFrame,
shouldResize: true,
shouldCompress: true,
quality: 0.0)
expect(compressed.size) == CGSize(width: 8, height: 8)

compressed = PDFGraphics.resizeAndCompressImage(image: image,
frame: compressFrame,
shouldResize: false,
shouldCompress: false,
quality: 0.0)
expect(compressed) == image
quality: 0.0)
expect(result.size) == CGSize(width: 8, height: 8)
}
}
}
}
Expand Down
58 changes: 43 additions & 15 deletions Source/Graphics/PDFGraphics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -159,28 +159,56 @@ class PDFGraphics {
var finalImage = image

if shouldResize {
// resize
var resizeFactor = (3 * quality > 1) ? 1 : 3 * quality
if resizeFactor == 0 {
resizeFactor = 0.2
}
let resizeImageSize = CGSize(width: frame.size.width * resizeFactor, height: frame.size.height * resizeFactor)

UIGraphicsBeginImageContext(resizeImageSize)
image.draw(in: CGRect(x: 0, y: 0, width: resizeImageSize.width, height: resizeImageSize.height))
finalImage = UIGraphicsGetImageFromCurrentImageContext() ?? finalImage
UIGraphicsEndImageContext()
finalImage = resize(image: finalImage, frame: frame, quality: quality)
}

if shouldCompress {
if let jpegData = UIImageJPEGRepresentation(finalImage, quality) {
finalImage = UIImage(data: jpegData) ?? finalImage
}
finalImage = compress(image: finalImage, quality: quality)
}

return finalImage
}

/**
Draws a scaled version of the given `image` into the given `frame`.
- parameter image: Image to resize
- parameter frame: Frame in which the new image will fit
- parameter quality: Value between 0.0 and 1.0, where 1.0 is maximum quality, used for size calculations
- returns: Resized version of `image`
*/
static func resize(image: UIImage, frame: CGRect, quality: CGFloat) -> UIImage {
let factor: CGFloat = min(3 * quality, 1)
let resizeFactor = factor.isZero ? 0.2 : factor

let size = CGSize(width: frame.width * resizeFactor,
height: frame.height * resizeFactor)

UIGraphicsBeginImageContext(size)
image.draw(in: CGRect(origin: .zero, size: size))
let finalImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

return finalImage ?? image
}

/**
Performs JPEG compression on the given image.
If the given image can not be compressed, it will silently return the original image.
- parameter image: Image to compress
- parameter quality: Value between 0.0 and 1.0, where 1.0 is maximum quality/least compression
*/
static func compress(image: UIImage, quality: CGFloat) -> UIImage {
guard let data = UIImageJPEGRepresentation(image, quality) else {
return image
}
guard let compressed = UIImage(data: data) else {
return image
}
return compressed
}

/**
Constants for filling, mostly used for debugging elements
*/
Expand Down
6 changes: 3 additions & 3 deletions TPPDF.podspec
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
Pod::Spec.new do |s|
s.name = 'TPPDF'
s.version = '1.1.2'
s.version = '1.2.0'
s.summary = 'TPPDF is a simple-to-use PDF builder for iOS'
s.description = <<-DESC
TPPDF is an object-based PDF builder.
TPPDF is an object-based PDF builder, completely built in Swift.
You create a document by defining, adding and positioning different objects.
TPPDF then calculates the document and creates a PDF.
TPPDF then calculates the layout and renders a PDF file.
DESC

s.homepage = 'https://github.com/techprimate/TPPDF'
Expand Down

0 comments on commit d431d48

Please sign in to comment.