ImageProgressive.swift 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. //
  2. // ImageProgressive.swift
  3. // Kingfisher
  4. //
  5. // Created by lixiang on 2019/5/10.
  6. //
  7. // Copyright (c) 2019 Wei Wang <onevcat@gmail.com>
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining a copy
  10. // of this software and associated documentation files (the "Software"), to deal
  11. // in the Software without restriction, including without limitation the rights
  12. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. // copies of the Software, and to permit persons to whom the Software is
  14. // furnished to do so, subject to the following conditions:
  15. //
  16. // The above copyright notice and this permission notice shall be included in
  17. // all copies or substantial portions of the Software.
  18. //
  19. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. // THE SOFTWARE.
  26. import UIKit
  27. final class ImageProgressive {
  28. private let options: KingfisherParsedOptionsInfo
  29. private(set) var scannedCount: Int = 0
  30. private var scannedIndex = -1
  31. private var lastSOSIndex = 0
  32. init(_ options: KingfisherParsedOptionsInfo) {
  33. self.options = options
  34. }
  35. func scanning(_ data: Data) -> Data? {
  36. guard options.progressiveJPEG, data.kf.contains(jpeg: .SOF2) else {
  37. return nil
  38. }
  39. guard (scannedIndex + 1) < data.count else {
  40. return nil
  41. }
  42. var index = scannedIndex + 1
  43. var count = scannedCount
  44. while index < (data.count - 1) {
  45. scannedIndex = index
  46. // 0xFF, 0xDA - Start Of Scan
  47. let SOS = ImageFormat.JPEGMarker.SOS.bytes
  48. if data[index] == SOS[0], data[index + 1] == SOS[1] {
  49. lastSOSIndex = index
  50. count += 1
  51. }
  52. index += 1
  53. }
  54. // Found more scans this the previous time
  55. guard count > scannedCount else { return nil }
  56. scannedCount = count
  57. // `> 1` checks that we've received a first scan (SOS) and then received
  58. // and also received a second scan (SOS). This way we know that we have
  59. // at least one full scan available.
  60. guard count > 1 && lastSOSIndex > 0 else { return nil }
  61. return data[0 ..< lastSOSIndex]
  62. }
  63. func decode(_ data: Data, with callbacks: [SessionDataTask.TaskCallback], completion: @escaping (Image) -> Void) {
  64. let processor = ImageDataProcessor(
  65. data: data[0 ..< lastSOSIndex],
  66. callbacks: callbacks,
  67. processingQueue: options.processingQueue
  68. )
  69. processor.onImageProcessed.delegate(on: self) { (self, result) in
  70. guard let image = try? result.0.get() else { return }
  71. // Blur partial images.
  72. // if self.scannedCount < 5 {
  73. // // Progressively reduce blur as we load more scans.
  74. // let radius = max(2, 14 - self.scannedCount * 4)
  75. // image = image.kf.blurred(withRadius: CGFloat(radius))
  76. // }
  77. CallbackQueue.mainCurrentOrAsync.execute { completion(image) }
  78. }
  79. processor.process()
  80. }
  81. }