Try to solve the SwiftUI bug of rendering EXIF UIImage in WebImage. Now we use the Image(decorative:) API to grab the CGImage and orientation instead. For vector image, draw vector image into bitmap for rescue
This commit is contained in:
parent
14a3cce8e5
commit
0a41337ed0
|
@ -39,13 +39,9 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
// Dynamic check to support vector format for both WebImage/AnimatedImage
|
||||
SDWebImageManager.shared.optionsProcessor = SDWebImageOptionsProcessor { url, options, context in
|
||||
var options = options
|
||||
var context = context
|
||||
if let _ = context?[.animatedImageClass] as? SDAnimatedImage.Type {
|
||||
// AnimatedImage supports vector rendering, should not force decode
|
||||
options.insert(.avoidDecodeImage)
|
||||
} else {
|
||||
// WebImage supports bitmap rendering only
|
||||
context?[.imageThumbnailPixelSize] = CGSize.zero
|
||||
}
|
||||
return SDWebImageOptionsResult(options: options, context: context)
|
||||
}
|
||||
|
|
|
@ -47,13 +47,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||
// Dynamic check to support vector format for both WebImage/AnimatedImage
|
||||
SDWebImageManager.shared.optionsProcessor = SDWebImageOptionsProcessor { url, options, context in
|
||||
var options = options
|
||||
var context = context
|
||||
if let _ = context?[.animatedImageClass] as? SDAnimatedImage.Type {
|
||||
// AnimatedImage supports vector rendering, should not force decode
|
||||
options.insert(.avoidDecodeImage)
|
||||
} else {
|
||||
// WebImage supports bitmap rendering only
|
||||
context?[.imageThumbnailPixelSize] = CGSize.zero
|
||||
}
|
||||
return SDWebImageOptionsResult(options: options, context: context)
|
||||
}
|
||||
|
|
|
@ -20,13 +20,6 @@ class ExtensionDelegate: NSObject, WKExtensionDelegate {
|
|||
SDImageCodersManager.shared.addCoder(SDImageWebPCoder.shared)
|
||||
SDImageCodersManager.shared.addCoder(SDImageSVGCoder.shared)
|
||||
SDImageCodersManager.shared.addCoder(SDImagePDFCoder.shared)
|
||||
// Dynamic check to support vector format for WebImage
|
||||
SDWebImageManager.shared.optionsProcessor = SDWebImageOptionsProcessor { url, options, context in
|
||||
var context = context
|
||||
// WebImage supports bitmap rendering only
|
||||
context?[.imageThumbnailPixelSize] = CGSize.zero
|
||||
return SDWebImageOptionsResult(options: options, context: context)
|
||||
}
|
||||
}
|
||||
|
||||
func applicationDidBecomeActive() {
|
||||
|
|
|
@ -26,13 +26,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||
// Dynamic check to support vector format for both WebImage/AnimatedImage
|
||||
SDWebImageManager.shared.optionsProcessor = SDWebImageOptionsProcessor { url, options, context in
|
||||
var options = options
|
||||
var context = context
|
||||
if let _ = context?[.animatedImageClass] as? SDAnimatedImage.Type {
|
||||
// AnimatedImage supports vector rendering, should not force decode
|
||||
options.insert(.avoidDecodeImage)
|
||||
} else {
|
||||
// WebImage supports bitmap rendering only
|
||||
context?[.imageThumbnailPixelSize] = CGSize.zero
|
||||
}
|
||||
return SDWebImageOptionsResult(options: options, context: context)
|
||||
}
|
||||
|
|
|
@ -81,6 +81,7 @@ struct ContentView: View {
|
|||
"https://nr-platform.s3.amazonaws.com/uploads/platform/published_extension/branding_icon/275/AmazonS3.png",
|
||||
"https://raw.githubusercontent.com/ibireme/YYImage/master/Demo/YYImageDemo/mew_baseline.jpg",
|
||||
"https://via.placeholder.com/200x200.jpg",
|
||||
"https://dv6mh24acw2xi.cloudfront.net/public/moments/gabbr/tmpImg9143171451882065582.jpeg",
|
||||
"https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/w3c.svg",
|
||||
"https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/wikimedia.svg",
|
||||
"https://raw.githubusercontent.com/icons8/flat-color-icons/master/pdf/stack_of_photos.pdf",
|
||||
|
|
|
@ -75,6 +75,10 @@
|
|||
32C43E3322FD5DF400BE87F5 /* SDWebImageSwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32C43E3122FD5DE100BE87F5 /* SDWebImageSwiftUI.swift */; };
|
||||
32C43E3422FD5DF400BE87F5 /* SDWebImageSwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32C43E3122FD5DE100BE87F5 /* SDWebImageSwiftUI.swift */; };
|
||||
32C43E3522FD5DF400BE87F5 /* SDWebImageSwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32C43E3122FD5DE100BE87F5 /* SDWebImageSwiftUI.swift */; };
|
||||
32D26A022446B546005905DA /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32D26A012446B546005905DA /* Image.swift */; };
|
||||
32D26A032446B546005905DA /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32D26A012446B546005905DA /* Image.swift */; };
|
||||
32D26A042446B546005905DA /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32D26A012446B546005905DA /* Image.swift */; };
|
||||
32D26A052446B546005905DA /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32D26A012446B546005905DA /* Image.swift */; };
|
||||
32ED4826242A13030053338E /* ImageManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32ED4825242A13030053338E /* ImageManagerTests.swift */; };
|
||||
32ED4827242A13030053338E /* ImageManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32ED4825242A13030053338E /* ImageManagerTests.swift */; };
|
||||
32ED4828242A13030053338E /* ImageManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32ED4825242A13030053338E /* ImageManagerTests.swift */; };
|
||||
|
@ -133,6 +137,7 @@
|
|||
32C43E2922FD586200BE87F5 /* SDWebImage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDWebImage.framework; path = Carthage/Build/tvOS/SDWebImage.framework; sourceTree = "<group>"; };
|
||||
32C43E2D22FD586E00BE87F5 /* SDWebImage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDWebImage.framework; path = Carthage/Build/watchOS/SDWebImage.framework; sourceTree = "<group>"; };
|
||||
32C43E3122FD5DE100BE87F5 /* SDWebImageSwiftUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SDWebImageSwiftUI.swift; sourceTree = "<group>"; };
|
||||
32D26A012446B546005905DA /* Image.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Image.swift; sourceTree = "<group>"; };
|
||||
32ED4825242A13030053338E /* ImageManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageManagerTests.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
|
@ -278,6 +283,7 @@
|
|||
32C43DDF22FD54C600BE87F5 /* AnimatedImage.swift */,
|
||||
32C43E3122FD5DE100BE87F5 /* SDWebImageSwiftUI.swift */,
|
||||
326E480923431C0F00C633E9 /* ImageViewWrapper.swift */,
|
||||
32D26A012446B546005905DA /* Image.swift */,
|
||||
);
|
||||
path = Classes;
|
||||
sourceTree = "<group>";
|
||||
|
@ -698,6 +704,7 @@
|
|||
326B8487236335110011BDFB /* ActivityIndicator.swift in Sources */,
|
||||
32C43E1622FD583700BE87F5 /* ImageManager.swift in Sources */,
|
||||
32C43E1822FD583700BE87F5 /* AnimatedImage.swift in Sources */,
|
||||
32D26A022446B546005905DA /* Image.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -714,6 +721,7 @@
|
|||
326B8488236335110011BDFB /* ActivityIndicator.swift in Sources */,
|
||||
32C43E1922FD583700BE87F5 /* ImageManager.swift in Sources */,
|
||||
32C43E1B22FD583700BE87F5 /* AnimatedImage.swift in Sources */,
|
||||
32D26A032446B546005905DA /* Image.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -730,6 +738,7 @@
|
|||
326B8489236335110011BDFB /* ActivityIndicator.swift in Sources */,
|
||||
32C43E1C22FD583800BE87F5 /* ImageManager.swift in Sources */,
|
||||
32C43E1E22FD583800BE87F5 /* AnimatedImage.swift in Sources */,
|
||||
32D26A042446B546005905DA /* Image.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -746,6 +755,7 @@
|
|||
326B848A236335110011BDFB /* ActivityIndicator.swift in Sources */,
|
||||
32C43E1F22FD583800BE87F5 /* ImageManager.swift in Sources */,
|
||||
32C43E2122FD583800BE87F5 /* AnimatedImage.swift in Sources */,
|
||||
32D26A052446B546005905DA /* Image.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) DreamPiggy <lizhuoli1126@126.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
|
||||
extension Image {
|
||||
@inlinable init(platformImage: PlatformImage) {
|
||||
#if os(macOS)
|
||||
self.init(nsImage: platformImage)
|
||||
#else
|
||||
self.init(uiImage: platformImage)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
|
||||
extension PlatformImage {
|
||||
static var empty = PlatformImage()
|
||||
}
|
||||
|
||||
#if os(iOS) || os(tvOS) || os(watchOS)
|
||||
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
|
||||
extension PlatformImage.Orientation {
|
||||
@inlinable var toSwiftUI: Image.Orientation {
|
||||
switch self {
|
||||
case .up:
|
||||
return .up
|
||||
case .upMirrored:
|
||||
return .upMirrored
|
||||
case .down:
|
||||
return .down
|
||||
case .downMirrored:
|
||||
return .downMirrored
|
||||
case .left:
|
||||
return .left
|
||||
case .leftMirrored:
|
||||
return .leftMirrored
|
||||
case .right:
|
||||
return .right
|
||||
case .rightMirrored:
|
||||
return .rightMirrored
|
||||
@unknown default:
|
||||
return .up
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Image.Orientation {
|
||||
@inlinable var toPlatform: PlatformImage.Orientation {
|
||||
switch self {
|
||||
case .up:
|
||||
return .up
|
||||
case .upMirrored:
|
||||
return .upMirrored
|
||||
case .down:
|
||||
return .down
|
||||
case .downMirrored:
|
||||
return .downMirrored
|
||||
case .left:
|
||||
return .left
|
||||
case .leftMirrored:
|
||||
return .leftMirrored
|
||||
case .right:
|
||||
return .right
|
||||
case .rightMirrored:
|
||||
return .rightMirrored
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -18,19 +18,6 @@ public typealias PlatformImage = NSImage
|
|||
public typealias PlatformImage = UIImage
|
||||
#endif
|
||||
|
||||
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
|
||||
extension Image {
|
||||
init(platformImage: PlatformImage) {
|
||||
#if os(macOS)
|
||||
self.init(nsImage: platformImage)
|
||||
#else
|
||||
self.init(uiImage: platformImage)
|
||||
#endif
|
||||
}
|
||||
|
||||
static var empty = Image(platformImage: PlatformImage())
|
||||
}
|
||||
|
||||
#if os(macOS)
|
||||
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
|
||||
public typealias PlatformView = NSView
|
||||
|
|
|
@ -63,13 +63,13 @@ public struct WebImage : View {
|
|||
// this prefetch the memory cache of image, to immediately render it on screen
|
||||
// this solve the case when `onAppear` not been called, for example, some transaction indeterminate state, SwiftUI :)
|
||||
if imageManager.isFirstPrefetch {
|
||||
self.imageManager.prefetch()
|
||||
imageManager.prefetch()
|
||||
}
|
||||
return Group {
|
||||
if imageManager.image != nil {
|
||||
if isAnimating && !self.imageManager.isIncremental {
|
||||
if isAnimating && !imageManager.isIncremental {
|
||||
if currentFrame != nil {
|
||||
configure(image: Image(platformImage: currentFrame!))
|
||||
configure(image: currentFrame!)
|
||||
.onAppear {
|
||||
self.imagePlayer?.startPlaying()
|
||||
}
|
||||
|
@ -84,16 +84,16 @@ public struct WebImage : View {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
configure(image: Image(platformImage: imageManager.image!))
|
||||
configure(image: imageManager.image!)
|
||||
.onReceive(imageManager.$image) { image in
|
||||
self.setupPlayer(image: image)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if currentFrame != nil {
|
||||
configure(image: Image(platformImage: currentFrame!))
|
||||
configure(image: currentFrame!)
|
||||
} else {
|
||||
configure(image: Image(platformImage: imageManager.image!))
|
||||
configure(image: imageManager.image!)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -122,10 +122,47 @@ public struct WebImage : View {
|
|||
}
|
||||
}
|
||||
|
||||
func configure(image: Image) -> some View {
|
||||
/// Configure the platform image into the SwiftUI rendering image
|
||||
func configure(image: PlatformImage) -> some View {
|
||||
var image = image
|
||||
// Actual rendering SwiftUI image
|
||||
let result: Image
|
||||
// NSImage works well with SwiftUI, include Animated and Vector Image
|
||||
#if os(macOS)
|
||||
result = Image(nsImage: image)
|
||||
#else
|
||||
// Fix the SwiftUI.Image rendering issue when use UIImage based, the `.aspectRatio` does not works. SwiftUI's Bug :)
|
||||
// See issue #101
|
||||
// Case 1: UIAnimatedImage, grab poster image
|
||||
if image.sd_isAnimated {
|
||||
// check images property
|
||||
if let images = image.images, images.count > 0 {
|
||||
image = images[0]
|
||||
}
|
||||
}
|
||||
// Case 2: Vector Image, draw bitmap image
|
||||
else if image.sd_isVector {
|
||||
// ensure CGImage is nil
|
||||
if image.cgImage == nil {
|
||||
// draw vector into bitmap with the screen scale (behavior like AppKit)
|
||||
UIGraphicsBeginImageContextWithOptions(image.size, false, UIScreen.main.scale)
|
||||
image.draw(at: .zero)
|
||||
image = UIGraphicsGetImageFromCurrentImageContext() ?? .empty
|
||||
UIGraphicsEndImageContext()
|
||||
}
|
||||
}
|
||||
// If we have CGImage, use CGImage based API, else use UIImage based API
|
||||
if let cgImage = image.cgImage {
|
||||
let orientation = image.imageOrientation.toSwiftUI
|
||||
result = Image(decorative: cgImage, scale: image.scale, orientation: orientation)
|
||||
} else {
|
||||
result = Image(uiImage: image)
|
||||
}
|
||||
#endif
|
||||
|
||||
// Should not use `EmptyView`, which does not respect to the container's frame modifier
|
||||
// Using a empty image instead for better compatible
|
||||
configurations.reduce(image) { (previous, configuration) in
|
||||
return configurations.reduce(result) { (previous, configuration) in
|
||||
configuration(previous)
|
||||
}
|
||||
}
|
||||
|
@ -136,12 +173,12 @@ public struct WebImage : View {
|
|||
if let placeholder = placeholder {
|
||||
// If use `.delayPlaceholder`, the placeholder is applied after loading failed, hide during loading :)
|
||||
if imageManager.options.contains(.delayPlaceholder) && imageManager.isLoading {
|
||||
return AnyView(configure(image: Image.empty))
|
||||
return AnyView(configure(image: .empty))
|
||||
} else {
|
||||
return placeholder
|
||||
}
|
||||
} else {
|
||||
return AnyView(configure(image: Image.empty))
|
||||
return AnyView(configure(image: .empty))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -260,7 +297,9 @@ extension WebImage {
|
|||
/// - Parameter image: A Image view that describes the placeholder.
|
||||
public func placeholder(_ image: Image) -> WebImage {
|
||||
return placeholder {
|
||||
configure(image: image)
|
||||
configurations.reduce(image) { (previous, configuration) in
|
||||
configuration(previous)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue