From 3ade1586c1070c27fbb534bc7e24efa5388c467d Mon Sep 17 00:00:00 2001 From: kean Date: Tue, 24 Dec 2024 12:00:04 -0500 Subject: [PATCH 1/2] Remove ImageLoader --- .../Classes/Utility/Media/ImageLoader.swift | 302 ------------------ 1 file changed, 302 deletions(-) delete mode 100644 WordPress/Classes/Utility/Media/ImageLoader.swift diff --git a/WordPress/Classes/Utility/Media/ImageLoader.swift b/WordPress/Classes/Utility/Media/ImageLoader.swift deleted file mode 100644 index edfbfe771365..000000000000 --- a/WordPress/Classes/Utility/Media/ImageLoader.swift +++ /dev/null @@ -1,302 +0,0 @@ -import MobileCoreServices -import AlamofireImage -import AutomatticTracks -import WordPressShared -import WordPressMedia - -/// Class used together with `CachedAnimatedImageView` to facilitate the loading of both -/// still images and animated gifs. -/// -/// - warning: Deprecated, please use `AsyncImageView` or `.wp` extensions for `UIImageView`. -@objc class ImageLoader: NSObject { - typealias ImageLoaderSuccessBlock = () -> Void - typealias ImageLoaderFailureBlock = (Error?) -> Void - - // MARK: Public Fields - - public var photonQuality: UInt { - get { - return selectedPhotonQuality - } - set(newPhotonQuality) { - selectedPhotonQuality = min(max(newPhotonQuality, Constants.minPhotonQuality), Constants.maxPhotonQuality) - } - } - - // MARK: - Image Dimensions Support - typealias ImageLoaderDimensionsBlock = (ImageDimensionFormat, CGSize) -> Void - - /// Called if the imageLoader is able to determine the image format, and dimensions - /// for the image prior to it being downloaded. - /// Note: Set the property prior to calling any load method - public var imageDimensionsHandler: ImageLoaderDimensionsBlock? - private var imageDimensionsFetcher: ImageDimensionsFetcher? = nil - - // MARK: Private Fields - - private unowned let imageView: CachedAnimatedImageView - private let loadingIndicator: ActivityIndicatorType - - private var successHandler: ImageLoaderSuccessBlock? - private var errorHandler: ImageLoaderFailureBlock? - private var placeholder: UIImage? - private var selectedPhotonQuality: UInt = Constants.defaultPhotonQuality - - @objc init(imageView: CachedAnimatedImageView, gifStrategy: GIFStrategy = .mediumGIFs) { - self.imageView = imageView - imageView.gifStrategy = gifStrategy - - let loadingIndicator = CircularProgressView(style: .primary) - loadingIndicator.backgroundColor = .clear - self.loadingIndicator = loadingIndicator - - super.init() - - imageView.addLoadingIndicator(self.loadingIndicator, style: .fullView) - } - - /// Removes the gif animation and prevents it from animate again. - /// Call this in a table/collection cell's `prepareForReuse()`. - /// - @objc func prepareForReuse() { - imageView.prepForReuse() - } - - /// Load an image from a specific post, using the given URL. Supports animated images (gifs) as well. - /// - /// - Parameters: - /// - url: The URL to load the image from. - /// - host: The `MediaHost` of the image. - /// - size: The preferred size of the image to load. - /// - func loadImage(with url: URL, from host: MediaHost, preferredSize size: CGSize = .zero) { - if url.isFileURL { - downloadImage(from: url) - } else if url.isGif { - loadGif(with: url, from: host, preferredSize: size) - } else { - imageView.clean() - loadStaticImage(with: url, from: host, preferredSize: size) - } - } - - @objc(loadImageWithURL:fromPost:preferredSize:placeholder:success:error:) - func loadImage(with url: URL, from post: AbstractPost, preferredSize size: CGSize = .zero, placeholder: UIImage?, success: ImageLoaderSuccessBlock?, error: ImageLoaderFailureBlock?) { - - let host = MediaHost(post) - loadImage(with: url, from: host, preferredSize: size, placeholder: placeholder, success: success, error: error) - } - - @objc(loadImageWithURL:fromReaderPost:preferredSize:placeholder:success:error:) - func loadImage(with url: URL, from readerPost: ReaderPost, preferredSize size: CGSize = .zero, placeholder: UIImage?, success: ImageLoaderSuccessBlock?, error: ImageLoaderFailureBlock?) { - loadImage(with: url, from: MediaHost(readerPost), preferredSize: size, placeholder: placeholder, success: success, error: error) - } - - /// Load an image from a specific post, using the given URL. Supports animated images (gifs) as well. - /// - /// - Parameters: - /// - url: The URL to load the image from. - /// - host: The host of the image. - /// - size: The preferred size of the image to load. You can pass height 0 to set width and preserve aspect ratio. - /// - placeholder: A placeholder to show while the image is loading. - /// - success: A closure to be called if the image was loaded successfully. - /// - error: A closure to be called if there was an error loading the image. - func loadImage(with url: URL, from host: MediaHost, preferredSize size: CGSize = .zero, placeholder: UIImage?, success: ImageLoaderSuccessBlock?, error: ImageLoaderFailureBlock?) { - - self.placeholder = placeholder - successHandler = success - errorHandler = error - - loadImage(with: url, from: host, preferredSize: size) - } - - // MARK: - Private helpers - - /// Load an animated image from the given URL. - /// - private func loadGif(with url: URL, from host: MediaHost, preferredSize size: CGSize = .zero) { - let mediaAuthenticator = MediaRequestAuthenticator() - mediaAuthenticator.authenticatedRequest( - for: url, - from: host, - onComplete: { request in - self.downloadGif(from: request) - }, - onFailure: { error in - WordPressAppDelegate.crashLogging?.logError(error) - self.callErrorHandler(with: error) - }) - } - - /// Load a static image from the given URL. - /// - private func loadStaticImage(with url: URL, from host: MediaHost, preferredSize size: CGSize = .zero) { - let finalURL: URL - - switch host { - case .publicSite: fallthrough - case .privateSelfHostedSite: - finalURL = url - case .publicWPComSite: fallthrough - case .privateAtomicWPComSite: - finalURL = photonUrl(with: url, preferredSize: size) - case .privateWPComSite: - finalURL = privateImageURL(with: url, from: host, preferredSize: size) - } - - let mediaRequestAuthenticator = MediaRequestAuthenticator() - - mediaRequestAuthenticator.authenticatedRequest(for: finalURL, from: host, onComplete: { request in - self.downloadImage(from: request) - }) { error in - WordPressAppDelegate.crashLogging?.logError(error) - self.callErrorHandler(with: error) - } - } - - /// Constructs the URL for an image from a private post hosted in WPCom. - /// - private func privateImageURL(with url: URL, from host: MediaHost, preferredSize size: CGSize) -> URL { - let scale = UIScreen.main.scale - let scaledSize = CGSize(width: size.width * scale, height: size.height * scale) - let scaledURL = WPImageURLHelper.imageURLWithSize(scaledSize, forImageURL: url) - - return scaledURL - } - - /// Gets the photon URL with the specified size, or returns the passed `URL` - /// - private func photonUrl(with url: URL, preferredSize size: CGSize) -> URL { - guard let photonURL = getPhotonUrl(for: url, size: size) else { - return url - } - - return photonURL - } - - /// Triggers the image dimensions fetcher if the `imageDimensionsHandler` property is set - private func calculateImageDimensionsIfNeeded(from request: URLRequest) { - guard let imageDimensionsHandler else { - return - } - - let fetcher = ImageDimensionsFetcher(request: request, success: { (format, size) in - guard let size, size != .zero else { - return - } - - DispatchQueue.main.async { - imageDimensionsHandler(format, size) - } - }) - - fetcher.start() - - imageDimensionsFetcher = fetcher - } - - /// Stop the image dimension calculation - private func cancelImageDimensionCalculation() { - imageDimensionsFetcher?.cancel() - imageDimensionsFetcher = nil - } - - /// Download the animated image from the given URL Request. - /// - private func downloadGif(from request: URLRequest) { - calculateImageDimensionsIfNeeded(from: request) - - imageView.startLoadingAnimation() - imageView.setAnimatedImage(request, placeholderImage: placeholder, success: { [weak self] in - self?.callSuccessHandler() - }) { [weak self] (error) in - self?.callErrorHandler(with: error) - } - } - - /// Downloads the image from the given URL Request. - /// - private func downloadImage(from request: URLRequest) { - calculateImageDimensionsIfNeeded(from: request) - - imageView.startLoadingAnimation() - imageView.af.setImage(withURLRequest: request, completion: { [weak self] dataResponse in - guard let self else { - return - } - - switch dataResponse.result { - case .success: - self.callSuccessHandler() - case .failure(let error): - self.callErrorHandler(with: error) - } - }) - } - - /// Downloads the image from the given URL. - /// - private func downloadImage(from url: URL) { - let request = URLRequest(url: url) - downloadImage(from: request) - } - - private func callSuccessHandler() { - cancelImageDimensionCalculation() - - imageView.stopLoadingAnimation() - guard successHandler != nil else { - return - } - DispatchQueue.main.async { - self.successHandler?() - } - } - - private func callErrorHandler(with error: Error?) { - if let error, (error as NSError).code == NSURLErrorCancelled { - return - } - - cancelImageDimensionCalculation() - - DispatchQueue.main.async { [weak self] in - guard let self else { - return - } - - if self.imageView.shouldShowLoadingIndicator { - (self.loadingIndicator as? CircularProgressView)?.state = .error - } - - self.errorHandler?(error) - } - } -} - -// MARK: - Loading Media object - -extension ImageLoader { - private func getPhotonUrl(for url: URL, size: CGSize) -> URL? { - var finalSize = size - if url.isGif { - // Photon helper sets the size to load the retina version. We don't want that for gifs - let scale = UIScreen.main.scale - finalSize = CGSize(width: size.width / scale, height: size.height / scale) - } - return PhotonImageURLHelper.photonURL(with: finalSize, - forImageURL: url, - forceResize: true, - imageQuality: selectedPhotonQuality) - } -} - -// MARK: - Constants - -private extension ImageLoader { - enum Constants { - static let minPhotonQuality: UInt = 1 - static let maxPhotonQuality: UInt = 100 - static let defaultPhotonQuality: UInt = 80 - } -} From ffd7cf6d43803142103a953df663d8e489a6de9a Mon Sep 17 00:00:00 2001 From: kean Date: Tue, 24 Dec 2024 12:03:00 -0500 Subject: [PATCH 2/2] Remove ImageDimensionParser --- .../ImageDimensionFetcher.swift | 87 ------ .../ImageDimensionParser.swift | 268 ------------------ WordPress/WordPress.xcodeproj/project.pbxproj | 54 +--- .../ImageDimensionParserTests.swift | 65 ----- .../WordPressTest/Test Images/100x100-png | Bin 4036 -> 0 bytes .../WordPressTest/Test Images/100x100.gif | Bin 156 -> 0 bytes .../WordPressTest/Test Images/100x100.jpg | Bin 4620 -> 0 bytes .../WordPressTest/Test Images/invalid-gif.gif | Bin 155 -> 0 bytes .../Test Images/invalid-jpeg-header.jpg | Bin 12 -> 0 bytes .../Test Images/valid-gif-header.gif | 1 - .../Test Images/valid-jpeg-header.jpg | Bin 12 -> 0 bytes .../Test Images/valid-png-header | Bin 24 -> 0 bytes .../{Test Images => }/iphone-photo.heic | Bin 13 files changed, 1 insertion(+), 474 deletions(-) delete mode 100644 WordPress/Classes/Utility/Image Dimension Parser/ImageDimensionFetcher.swift delete mode 100644 WordPress/Classes/Utility/Image Dimension Parser/ImageDimensionParser.swift delete mode 100644 WordPress/WordPressTest/ImageDimensionParserTests.swift delete mode 100644 WordPress/WordPressTest/Test Images/100x100-png delete mode 100644 WordPress/WordPressTest/Test Images/100x100.gif delete mode 100644 WordPress/WordPressTest/Test Images/100x100.jpg delete mode 100755 WordPress/WordPressTest/Test Images/invalid-gif.gif delete mode 100755 WordPress/WordPressTest/Test Images/invalid-jpeg-header.jpg delete mode 100755 WordPress/WordPressTest/Test Images/valid-gif-header.gif delete mode 100755 WordPress/WordPressTest/Test Images/valid-jpeg-header.jpg delete mode 100755 WordPress/WordPressTest/Test Images/valid-png-header rename WordPress/WordPressTest/{Test Images => }/iphone-photo.heic (100%) 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 3fc17a04dfc58ac82b6d7555d5c1919e8c6dfe75..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4036 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 diff --git a/WordPress/WordPressTest/Test Images/100x100.gif b/WordPress/WordPressTest/Test Images/100x100.gif deleted file mode 100644 index f70ac685ee572a228ea4aaa2341646ac3bb48ac5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 156 zcmZ?wbhEHbOkqf2XkY+=|Ns9h{$ye00y1?#e2@$SQ*lrK%F}Q87th&pt9$dkJ-_+e z9(hcA*17D}scrALkAL#H{;l`%MdIbsvAS>1U7M>g#W|{pRgI{rtAg-1k2MaPU4J5Jnq@q;5X If`P#r0NM6XUH||9 diff --git a/WordPress/WordPressTest/Test Images/100x100.jpg b/WordPress/WordPressTest/Test Images/100x100.jpg deleted file mode 100644 index db3980bd4aa96122e1a3f5b89a91cae4658bd1ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4620 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 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 ae4a6ef503de6dec1ff6974f42fa6bc55c5ee8c2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12 Tcmex=