diff --git a/WordPress/Classes/Utility/Image Dimension Parser/ImageDimensionFetcher.swift b/WordPress/Classes/Utility/Image Dimension Parser/ImageDimensionFetcher.swift deleted file mode 100644 index 28d4a693619d..000000000000 --- a/WordPress/Classes/Utility/Image Dimension Parser/ImageDimensionFetcher.swift +++ /dev/null @@ -1,87 +0,0 @@ -import UIKit - -class ImageDimensionsFetcher: NSObject, URLSessionDataDelegate { - // Helpful typealiases for the closures - public typealias CompletionHandler = (ImageDimensionFormat, CGSize?) -> Void - public typealias ErrorHandler = (Error?) -> Void - - let completionHandler: CompletionHandler - let errorHandler: ErrorHandler? - - // Internal use properties - private let request: URLRequest - private var task: URLSessionDataTask? = nil - private let parser: ImageDimensionParser - private var session: URLSession? = nil - - deinit { - cancel() - } - - init(request: URLRequest, - success: @escaping CompletionHandler, - error: ErrorHandler? = nil, - imageParser: ImageDimensionParser = ImageDimensionParser()) { - self.request = request - self.completionHandler = success - self.errorHandler = error - self.parser = imageParser - - super.init() - } - - /// Starts the calculation process - func start() { - let config = URLSessionConfiguration.default - let session = URLSession(configuration: config, delegate: self, delegateQueue: nil) - let task = session.dataTask(with: request) - task.resume() - - self.task = task - self.session = session - } - - func cancel() { - session?.invalidateAndCancel() - task?.cancel() - } - - // MARK: - URLSessionDelegate - public func urlSession(_ session: URLSession, task dataTask: URLSessionTask, didCompleteWithError error: Error?) { - // Don't trigger an error if we cancelled the task - if let error, (error as NSError).code == NSURLErrorCancelled { - return - } - - self.errorHandler?(error) - } - - func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { - // Add the downloaded data to the parser - parser.append(bytes: data) - - // Wait for the format to be detected - guard let format = parser.format else { - return - } - - // Check if the format is unsupported - guard format != .unsupported else { - completionHandler(format, nil) - - // We can't parse unsupported images, cancel the download - cancel() - return - } - - // Wait for the image size - guard let size = parser.imageSize else { - return - } - - completionHandler(format, size) - - // The image size has been calculated, stop downloading - cancel() - } -} diff --git a/WordPress/Classes/Utility/Image Dimension Parser/ImageDimensionParser.swift b/WordPress/Classes/Utility/Image Dimension Parser/ImageDimensionParser.swift deleted file mode 100644 index de2726fe5a58..000000000000 --- a/WordPress/Classes/Utility/Image Dimension Parser/ImageDimensionParser.swift +++ /dev/null @@ -1,268 +0,0 @@ -import UIKit - -class ImageDimensionParser { - private(set) var format: ImageDimensionFormat? - private(set) var imageSize: CGSize? = nil - - private var data: Data - - init(with data: Data = Data()) { - self.data = data - - parse() - } - - public func append(bytes: Data) { - data.append(contentsOf: bytes) - - parse() - } - - private func parse() { - guard - let format = ImageDimensionFormat(with: data) - else { - return - } - - self.format = format - imageSize = dimensions(with: data) - - guard imageSize != nil else { - return - } - } - - // MARK: - Dimension Calculating - private func dimensions(with data: Data) -> CGSize? { - switch format { - case .png: return pngSize(with: data) - case .gif: return gifSize(with: data) - case .jpeg: return jpegSize(with: data) - - default: return nil - } - } - - // MARK: - PNG Parsing - private func pngSize(with data: Data) -> CGSize? { - // Bail out if the data size is too small to read the header - let chunkSize = PNGConstants.chunkSize - let ihdrStart = PNGConstants.headerSize + chunkSize - - // The min length needed to read the width / height - let minLength = ihdrStart + chunkSize * 3 - - guard data.count >= minLength else { - return nil - } - - // Validate the header to make sure the width/height is in the correct spot - guard data.subdata(start: ihdrStart, length: chunkSize) == PNGConstants.IHDR else { - return nil - } - - // Width is immediately after the IHDR header - let widthOffset = ihdrStart + chunkSize - - // Height is after the width - let heightOffset = widthOffset + chunkSize - - // Height and width are stored as 32 bit ints - // http://www.libpng.org/pub/png/spec/1.0/PNG-Chunks.html - // ^ The maximum for each is (2^31)-1 in order to accommodate languages that have difficulty with unsigned 4-byte values. - let width = CFSwapInt32(data[widthOffset, chunkSize] as UInt32) - let height = CFSwapInt32(data[heightOffset, chunkSize] as UInt32) - - return CGSize(width: Int(width), height: Int(height)) - } - - private struct PNGConstants { - // PNG header size is 8 bytes - static let headerSize = 8 - - // PNG is broken up into 4 byte chunks, except for the header - static let chunkSize = 4 - - // IHDR header: // https://www.w3.org/TR/PNG/#11IHDR - static let IHDR = Data([0x49, 0x48, 0x44, 0x52]) - } - - // MARK: - GIF Parsing - private func gifSize(with data: Data) -> CGSize? { - // Bail out if the data size is too small to read the header - let valueSize = GIFConstants.valueSize - let headerSize = GIFConstants.headerSize - - // Min length we need to read is the header size + 4 bytes - let minLength = headerSize + valueSize * 3 - - guard data.count >= minLength else { - return nil - } - - // The width appears directly after the header, and the height after that. - let widthOffset = headerSize - let heightOffset = widthOffset - - // Reads the "logical screen descriptor" which appears after the GIF header block - let width: UInt16 = data[widthOffset, valueSize] - let height: UInt16 = data[heightOffset, valueSize] - - return CGSize(width: Int(width), height: Int(height)) - } - - private struct GIFConstants { - // http://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp - - // The GIF header size is 6 bytes - static let headerSize = 6 - - // The height and width are stored as 2 byte values - static let valueSize = 2 - } - - // MARK: - JPEG Parsing - private struct JPEGConstants { - static let blockSize: UInt16 = 256 - - // 16 bytes skips the header and the first block - static let minDataCount = 16 - - static let valueSize = 2 - static let heightOffset = 5 - - // JFIF{NULL} - static let jfifHeader = Data([0x4A, 0x46, 0x49, 0x46, 0x00]) - } - - private func jpegSize(with data: Data) -> CGSize? { - // Bail out if the data size is too small to read the header - guard data.count > JPEGConstants.minDataCount else { - return nil - } - - // Adapted from: - // - https://web.archive.org/web/20131016210645/http://www.64lines.com/jpeg-width-height - - var i = JPEGConstants.jfifHeader.count - 1 - - let blockSize: UInt16 = JPEGConstants.blockSize - - // Retrieve the block length of the first block since the first block will not contain the size of file - var block_length = UInt16(data[i]) * blockSize + UInt16(data[i+1]) - - while i < data.count { - i += Int(block_length) - - // Protect again out of bounds issues - // 10 = the max size we need to read all the values from below - if i + 10 >= data.count { - return nil - } - - // Check that we are truly at the start of another block - if data[i] != 0xFF { - return nil - } - - // SOFn marker - let marker = data[i+1] - - let isValidMarker = (marker >= 0xC0 && marker <= 0xC3) || - (marker >= 0xC5 && marker <= 0xC7) || - (marker >= 0xC9 && marker <= 0xCB) || - (marker >= 0xCD && marker <= 0xCF) - - if isValidMarker { - // "Start of frame" marker which contains the file size - let valueSize = JPEGConstants.valueSize - let heightOffset = i + JPEGConstants.heightOffset - let widthOffset = heightOffset + valueSize - - let height = CFSwapInt16(data[heightOffset, valueSize] as UInt16) - let width = CFSwapInt16(data[widthOffset, valueSize] as UInt16) - - return CGSize(width: Int(width), height: Int(height)) - } - - // Go to the next block - i += 2 // Skip the block marker - block_length = UInt16(data[i]) * blockSize + UInt16(data[i+1]) - } - - return nil - } -} - -// MARK: - ImageFormat -enum ImageDimensionFormat { - // WordPress supported image formats: - // https://wordpress.com/support/images/ - // https://codex.wordpress.org/Uploading_Files - case jpeg - case png - case gif - case unsupported - - init?(with data: Data) { - if data.headerIsEqual(to: FileMarker.jpeg) { - self = .jpeg - } - else if data.headerIsEqual(to: FileMarker.gif) { - self = .gif - } - else if data.headerIsEqual(to: FileMarker.png) { - self = .png - } - else if data.count < FileMarker.png.count { - return nil - } - else { - self = .unsupported - } - } - - // File type markers denote the type of image in the first few bytes of the file - private struct FileMarker { - // https://en.wikipedia.org/wiki/JPEG_Network_Graphics - static let png = Data([0x89, 0x50, 0x4E, 0x47]) - - // https://en.wikipedia.org/wiki/JPEG_File_Interchange_Format - // FFD8 = SOI, APP0 marker - static let jpeg = Data([0xFF, 0xD8, 0xFF]) - - // https://en.wikipedia.org/wiki/GIF - static let gif = Data([0x47, 0x49, 0x46, 0x38]) //GIF8 - } -} - -// MARK: - Private: Extensions -private extension Data { - func headerData(with length: Int) -> Data { - return subdata(start: 0, length: length) - } - - func headerIsEqual(to value: Data) -> Bool { - // Prevent any out of bounds issues - if count < value.count { - return false - } - - let header = headerData(with: value.count) - - return header == value - } - - func subdata(start: Int, length: Int) -> Data { - return subdata(in: start ..< start + length) - } - - subscript(range: Range) -> UInt16 { - return subdata(in: range).withUnsafeBytes { $0.load(as: UInt16.self) } - } - - subscript(start: Int, length: Int) -> T { - return self[start.. Data { - let url = Bundle(for: ImageDimensionParserTests.self).url(forResource: name, withExtension: nil)! - return try! Data(contentsOf: url) - } -} diff --git a/WordPress/WordPressTest/Test Images/100x100-png b/WordPress/WordPressTest/Test Images/100x100-png deleted file mode 100644 index 3fc17a04dfc5..000000000000 Binary files a/WordPress/WordPressTest/Test Images/100x100-png and /dev/null differ diff --git a/WordPress/WordPressTest/Test Images/100x100.gif b/WordPress/WordPressTest/Test Images/100x100.gif deleted file mode 100644 index f70ac685ee57..000000000000 Binary files a/WordPress/WordPressTest/Test Images/100x100.gif and /dev/null differ diff --git a/WordPress/WordPressTest/Test Images/100x100.jpg b/WordPress/WordPressTest/Test Images/100x100.jpg deleted file mode 100644 index db3980bd4aa9..000000000000 Binary files a/WordPress/WordPressTest/Test Images/100x100.jpg and /dev/null differ diff --git a/WordPress/WordPressTest/Test Images/invalid-gif.gif b/WordPress/WordPressTest/Test Images/invalid-gif.gif deleted file mode 100755 index 5fb2c25c410d..000000000000 Binary files a/WordPress/WordPressTest/Test Images/invalid-gif.gif and /dev/null differ diff --git a/WordPress/WordPressTest/Test Images/invalid-jpeg-header.jpg b/WordPress/WordPressTest/Test Images/invalid-jpeg-header.jpg deleted file mode 100755 index 19b8194f7d8c..000000000000 Binary files a/WordPress/WordPressTest/Test Images/invalid-jpeg-header.jpg and /dev/null differ diff --git a/WordPress/WordPressTest/Test Images/valid-gif-header.gif b/WordPress/WordPressTest/Test Images/valid-gif-header.gif deleted file mode 100755 index c9f3ee173650..000000000000 --- a/WordPress/WordPressTest/Test Images/valid-gif-header.gif +++ /dev/null @@ -1 +0,0 @@ -GIF89a \ No newline at end of file diff --git a/WordPress/WordPressTest/Test Images/valid-jpeg-header.jpg b/WordPress/WordPressTest/Test Images/valid-jpeg-header.jpg deleted file mode 100755 index ae4a6ef503de..000000000000 Binary files a/WordPress/WordPressTest/Test Images/valid-jpeg-header.jpg and /dev/null differ diff --git a/WordPress/WordPressTest/Test Images/valid-png-header b/WordPress/WordPressTest/Test Images/valid-png-header deleted file mode 100755 index 8c6519eefd84..000000000000 Binary files a/WordPress/WordPressTest/Test Images/valid-png-header and /dev/null differ diff --git a/WordPress/WordPressTest/Test Images/iphone-photo.heic b/WordPress/WordPressTest/iphone-photo.heic similarity index 100% rename from WordPress/WordPressTest/Test Images/iphone-photo.heic rename to WordPress/WordPressTest/iphone-photo.heic