mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 21:45:19 +00:00
Wallpaper pattern tiling in landscape
This commit is contained in:
parent
1d5837a4f8
commit
8733c482c7
@ -125,7 +125,7 @@ public enum DeviceMetrics: CaseIterable, Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
var screenSize: CGSize {
|
||||
public var screenSize: CGSize {
|
||||
switch self {
|
||||
case .iPhone4:
|
||||
return CGSize(width: 320.0, height: 480.0)
|
||||
|
@ -1070,7 +1070,7 @@ final class MediaPickerSelectedListNode: ASDisplayNode, UIScrollViewDelegate, UI
|
||||
self.wallpaperBackgroundNode.update(wallpaper: wallpaper)
|
||||
self.wallpaperBackgroundNode.updateBubbleTheme(bubbleTheme: theme, bubbleCorners: bubbleCorners)
|
||||
transition.updateFrame(node: self.wallpaperBackgroundNode, frame: CGRect(origin: CGPoint(x: inset, y: 0.0), size: CGSize(width: size.width - inset * 2.0, height: size.height)))
|
||||
self.wallpaperBackgroundNode.updateLayout(size: CGSize(width: size.width - inset * 2.0, height: size.height), transition: transition)
|
||||
self.wallpaperBackgroundNode.updateLayout(size: CGSize(width: size.width - inset * 2.0, height: size.height), tile: false, transition: transition)
|
||||
|
||||
self.updateItems(transition: itemsTransition)
|
||||
|
||||
|
@ -2469,7 +2469,7 @@ public func svgIconImageFile(account: Account, fileReference: FileMediaReference
|
||||
} else {
|
||||
renderSize = CGSize(width: 90.0, height: 90.0)
|
||||
}
|
||||
fullSizeImage = renderPreparedImage(data, renderSize, .clear, UIScreenScale)
|
||||
fullSizeImage = renderPreparedImage(data, renderSize, .clear, UIScreenScale, false)
|
||||
if let image = fullSizeImage {
|
||||
fittedSize = image.size.aspectFitted(arguments.boundingSize)
|
||||
}
|
||||
|
@ -285,7 +285,7 @@ private final class BubbleSettingsControllerNode: ASDisplayNode, UIScrollViewDel
|
||||
bottomInset = 37.0
|
||||
|
||||
self.chatBackgroundNode.frame = chatFrame
|
||||
self.chatBackgroundNode.updateLayout(size: chatFrame.size, transition: transition)
|
||||
self.chatBackgroundNode.updateLayout(size: chatFrame.size, tile: false, transition: transition)
|
||||
self.messagesContainerNode.frame = chatFrame
|
||||
|
||||
transition.updateFrame(node: self.toolbarNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - toolbarHeight), size: CGSize(width: layout.size.width, height: toolbarHeight + layout.intrinsicInsets.bottom)))
|
||||
|
@ -268,7 +268,7 @@ class ForwardPrivacyChatPreviewItemNode: ListViewItemNode {
|
||||
backgroundNode.frame = backgroundFrame.insetBy(dx: 0.0, dy: -100.0)
|
||||
backgroundNode.update(wallpaper: item.wallpaper)
|
||||
backgroundNode.updateBubbleTheme(bubbleTheme: item.theme, bubbleCorners: item.chatBubbleCorners)
|
||||
backgroundNode.updateLayout(size: backgroundNode.bounds.size, transition: .immediate)
|
||||
backgroundNode.updateLayout(size: backgroundNode.bounds.size, tile: false, transition: .immediate)
|
||||
}
|
||||
|
||||
strongSelf.maskNode.frame = backgroundFrame.insetBy(dx: params.leftInset, dy: 0.0)
|
||||
|
@ -393,7 +393,7 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
||||
backgroundNode.frame = backgroundFrame.insetBy(dx: 0.0, dy: -100.0)
|
||||
backgroundNode.update(wallpaper: item.wallpaper)
|
||||
backgroundNode.updateBubbleTheme(bubbleTheme: item.theme, bubbleCorners: item.chatBubbleCorners)
|
||||
backgroundNode.updateLayout(size: backgroundNode.bounds.size, transition: .immediate)
|
||||
backgroundNode.updateLayout(size: backgroundNode.bounds.size, tile: false, transition: .immediate)
|
||||
}
|
||||
|
||||
strongSelf.maskNode.frame = backgroundFrame.insetBy(dx: params.leftInset, dy: 0.0)
|
||||
|
@ -564,7 +564,7 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView
|
||||
}
|
||||
|
||||
self.chatBackgroundNode.frame = chatFrame
|
||||
self.chatBackgroundNode.updateLayout(size: chatFrame.size, transition: transition)
|
||||
self.chatBackgroundNode.updateLayout(size: chatFrame.size, tile: false, transition: transition)
|
||||
self.messagesContainerNode.frame = chatFrame
|
||||
|
||||
transition.updateFrame(node: self.toolbarNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - toolbarHeight), size: CGSize(width: layout.size.width, height: toolbarHeight + layout.intrinsicInsets.bottom)))
|
||||
|
@ -1198,7 +1198,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
||||
transition.updateFrame(node: self.backgroundContainerNode, frame: CGRect(origin: CGPoint(), size: backgroundSize))
|
||||
|
||||
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: layout.size))
|
||||
self.backgroundNode.updateLayout(size: self.backgroundNode.bounds.size, transition: transition)
|
||||
self.backgroundNode.updateLayout(size: self.backgroundNode.bounds.size, tile: false, transition: transition)
|
||||
|
||||
transition.updatePosition(node: self.backgroundWrapperNode, position: CGPoint(x: backgroundSize.width / 2.0, y: backgroundSize.height / 2.0))
|
||||
|
||||
|
@ -712,11 +712,11 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
|
||||
self.messagesContainerNode.frame = self.chatContainerNode.bounds
|
||||
self.instantChatBackgroundNode.frame = self.chatContainerNode.bounds
|
||||
self.instantChatBackgroundNode.updateLayout(size: self.instantChatBackgroundNode.bounds.size, transition: .immediate)
|
||||
self.instantChatBackgroundNode.updateLayout(size: self.instantChatBackgroundNode.bounds.size, tile: false, transition: .immediate)
|
||||
self.remoteChatBackgroundNode.frame = self.chatContainerNode.bounds
|
||||
self.blurredNode.frame = self.chatContainerNode.bounds
|
||||
self.wallpaperNode.frame = self.chatContainerNode.bounds
|
||||
self.wallpaperNode.updateLayout(size: self.wallpaperNode.bounds.size, transition: .immediate)
|
||||
self.wallpaperNode.updateLayout(size: self.wallpaperNode.bounds.size, tile: false, transition: .immediate)
|
||||
|
||||
transition.updateFrame(node: self.toolbarNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - toolbarHeight), size: CGSize(width: layout.size.width, height: toolbarHeight)))
|
||||
self.toolbarNode.updateLayout(size: CGSize(width: layout.size.width, height: 49.0), layout: layout, transition: transition)
|
||||
|
@ -267,7 +267,7 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode {
|
||||
let backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
|
||||
if let backgroundNode = strongSelf.backgroundNode {
|
||||
backgroundNode.frame = backgroundFrame.insetBy(dx: 0.0, dy: -100.0)
|
||||
backgroundNode.updateLayout(size: backgroundNode.bounds.size, transition: .immediate)
|
||||
backgroundNode.updateLayout(size: backgroundNode.bounds.size, tile: false, transition: .immediate)
|
||||
}
|
||||
strongSelf.maskNode.frame = backgroundFrame.insetBy(dx: params.leftInset, dy: 0.0)
|
||||
strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: layoutSize.width, height: separatorHeight))
|
||||
|
@ -1169,7 +1169,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
if self.cropNode.supernode == nil {
|
||||
self.imageNode.frame = self.wrapperNode.bounds
|
||||
self.nativeNode.frame = self.wrapperNode.bounds
|
||||
self.nativeNode.updateLayout(size: self.nativeNode.bounds.size, transition: .immediate)
|
||||
self.nativeNode.updateLayout(size: self.nativeNode.bounds.size, tile: false, transition: .immediate)
|
||||
self.blurredNode.frame = self.imageNode.frame
|
||||
} else {
|
||||
self.cropNode.frame = self.wrapperNode.bounds
|
||||
|
@ -1625,7 +1625,7 @@ final class MessageStoryRenderer {
|
||||
let size = layout.size
|
||||
self.containerNode.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||
self.instantChatBackgroundNode.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||
self.instantChatBackgroundNode.updateLayout(size: size, transition: .immediate)
|
||||
self.instantChatBackgroundNode.updateLayout(size: size, tile: false, transition: .immediate)
|
||||
self.messagesContainerNode.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||
|
||||
let addressLayout = self.addressNode.updateLayout(size)
|
||||
|
@ -5,7 +5,7 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NSData * _Nullable prepareSvgImage(NSData * _Nonnull data);
|
||||
UIImage * _Nullable renderPreparedImage(NSData * _Nonnull data, CGSize size, UIColor * _Nonnull backgroundColor, CGFloat scale);
|
||||
UIImage * _Nullable renderPreparedImage(NSData * _Nonnull data, CGSize size, UIColor * _Nonnull backgroundColor, CGFloat scale, bool fit);
|
||||
|
||||
UIImage * _Nullable drawSvgImage(NSData * _Nonnull data, CGSize size, UIColor * _Nullable backgroundColor, UIColor * _Nullable foregroundColor, bool opaque);
|
||||
|
||||
|
@ -9,6 +9,11 @@ CGSize aspectFillSize(CGSize size, CGSize bounds) {
|
||||
return CGSizeMake(floor(size.width * scale), floor(size.height * scale));
|
||||
}
|
||||
|
||||
CGSize aspectFitSize(CGSize size, CGSize bounds) {
|
||||
CGFloat scale = MIN(bounds.width / MAX(1.0, size.width), bounds.height / MAX(1.0, size.height));
|
||||
return CGSizeMake(floor(size.width * scale), floor(size.height * scale));
|
||||
}
|
||||
|
||||
@interface SvgXMLParsingDelegate : NSObject <NSXMLParserDelegate> {
|
||||
NSString *_elementName;
|
||||
NSString *_currentStyleString;
|
||||
@ -358,7 +363,7 @@ UIImage * _Nullable drawSvgImage(NSData * _Nonnull data, CGSize size, UIColor *b
|
||||
|
||||
@end
|
||||
|
||||
UIImage * _Nullable renderPreparedImage(NSData * _Nonnull data, CGSize size, UIColor *backgroundColor, CGFloat scale) {
|
||||
UIImage * _Nullable renderPreparedImage(NSData * _Nonnull data, CGSize size, UIColor *backgroundColor, CGFloat scale, bool fit) {
|
||||
NSDate *startTime = [NSDate date];
|
||||
|
||||
UIColor *foregroundColor = [UIColor whiteColor];
|
||||
@ -383,6 +388,15 @@ UIImage * _Nullable renderPreparedImage(NSData * _Nonnull data, CGSize size, UIC
|
||||
|
||||
bool isTransparent = [backgroundColor isEqual:[UIColor clearColor]];
|
||||
|
||||
CGSize svgSize = CGSizeMake(width, height);
|
||||
CGSize drawingSize;
|
||||
if (fit) {
|
||||
drawingSize = aspectFitSize(svgSize, size);
|
||||
size = drawingSize;
|
||||
} else {
|
||||
drawingSize = aspectFillSize(svgSize, size);
|
||||
}
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(size, !isTransparent, scale);
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
if (isTransparent) {
|
||||
@ -392,8 +406,7 @@ UIImage * _Nullable renderPreparedImage(NSData * _Nonnull data, CGSize size, UIC
|
||||
CGContextFillRect(context, CGRectMake(0.0f, 0.0f, size.width, size.height));
|
||||
}
|
||||
|
||||
CGSize svgSize = CGSizeMake(width, height);
|
||||
CGSize drawingSize = aspectFillSize(svgSize, size);
|
||||
|
||||
|
||||
CGFloat renderScale = MAX(size.width / MAX(1.0, svgSize.width), size.height / MAX(1.0, svgSize.height));
|
||||
|
||||
|
@ -1468,7 +1468,12 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
}
|
||||
|
||||
transition.updateFrame(node: self.backgroundNode, frame: contentBounds)
|
||||
self.backgroundNode.updateLayout(size: contentBounds.size, transition: transition)
|
||||
|
||||
var shouldTile = false
|
||||
if case .regular = layout.metrics.widthClass, layout.size.height == layout.deviceMetrics.screenSize.width {
|
||||
shouldTile = true
|
||||
}
|
||||
self.backgroundNode.updateLayout(size: contentBounds.size, tile: shouldTile, transition: transition)
|
||||
|
||||
transition.updateBounds(node: self.historyNodeContainer, bounds: contentBounds)
|
||||
transition.updatePosition(node: self.historyNodeContainer, position: contentBounds.center)
|
||||
|
@ -1852,7 +1852,7 @@ private class QrContentNode: ASDisplayNode, ContentNode {
|
||||
transition.updateFrame(node: self.containerNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
transition.updateFrame(node: self.wallpaperBackgroundNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
self.wallpaperBackgroundNode.updateLayout(size: size, transition: transition)
|
||||
self.wallpaperBackgroundNode.updateLayout(size: size, tile: false, transition: transition)
|
||||
|
||||
let textLength = self.codeTextNode.attributedText?.string.count ?? 0
|
||||
|
||||
@ -2195,7 +2195,7 @@ private class MessageContentNode: ASDisplayNode, ContentNode {
|
||||
transition.updateFrame(node: self.containerNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
transition.updateFrame(node: self.wallpaperBackgroundNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
self.wallpaperBackgroundNode.updateLayout(size: size, transition: transition)
|
||||
self.wallpaperBackgroundNode.updateLayout(size: size, tile: false, transition: transition)
|
||||
|
||||
let inset: CGFloat = 24.0
|
||||
let contentInset: CGFloat = 16.0
|
||||
|
@ -666,7 +666,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
||||
let cleanInsets = layout.insets(options: [])
|
||||
|
||||
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: layout.size))
|
||||
self.backgroundNode.updateLayout(size: self.backgroundNode.bounds.size, transition: transition)
|
||||
self.backgroundNode.updateLayout(size: self.backgroundNode.bounds.size, tile: false, transition: transition)
|
||||
|
||||
let intrinsicPanelHeight: CGFloat = 47.0
|
||||
let panelHeight = intrinsicPanelHeight + cleanInsets.bottom
|
||||
|
@ -138,7 +138,7 @@ final class MetalWallpaperBackgroundNode: ASDisplayNode, WallpaperBackgroundNode
|
||||
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
func updateLayout(size: CGSize, tile: Bool, transition: ContainedViewLayoutTransition) {
|
||||
if self.metalLayer.drawableSize != size {
|
||||
self.metalLayer.drawableSize = size
|
||||
|
||||
|
@ -60,7 +60,7 @@ public protocol WallpaperBackgroundNode: ASDisplayNode {
|
||||
|
||||
func update(wallpaper: TelegramWallpaper)
|
||||
func _internalUpdateIsSettingUpWallpaper()
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition)
|
||||
func updateLayout(size: CGSize, tile: Bool, transition: ContainedViewLayoutTransition)
|
||||
func updateIsLooping(_ isLooping: Bool)
|
||||
func animateEvent(transition: ContainedViewLayoutTransition, extendAnimation: Bool)
|
||||
func updateBubbleTheme(bubbleTheme: PresentationTheme, bubbleCorners: PresentationChatBubbleCorners)
|
||||
@ -599,7 +599,7 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
|
||||
|
||||
private let bakedBackgroundView: UIImageView
|
||||
|
||||
private var validLayout: CGSize?
|
||||
private var validLayout: (CGSize, Bool)?
|
||||
private var wallpaper: TelegramWallpaper?
|
||||
private var isSettingUpWallpaper: Bool = false
|
||||
|
||||
@ -884,8 +884,8 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
|
||||
}
|
||||
}
|
||||
|
||||
if let size = self.validLayout {
|
||||
self.updateLayout(size: size, transition: .immediate)
|
||||
if let (size, tile) = self.validLayout {
|
||||
self.updateLayout(size: size, tile: tile, transition: .immediate)
|
||||
self.updateBubbles()
|
||||
|
||||
if scheduleLoopingEvent {
|
||||
@ -953,7 +953,7 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
|
||||
}
|
||||
}
|
||||
|
||||
private func loadPatternForSizeIfNeeded(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
private func loadPatternForSizeIfNeeded(size: CGSize, tile: Bool, transition: ContainedViewLayoutTransition) {
|
||||
guard let wallpaper = self.wallpaper else {
|
||||
return
|
||||
}
|
||||
@ -1024,8 +1024,8 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
|
||||
|
||||
strongSelf.validPatternImage = ValidPatternImage(wallpaper: wallpaper, invertPattern: invertPattern, generate: generator)
|
||||
strongSelf.validPatternGeneratedImage = nil
|
||||
if let size = strongSelf.validLayout {
|
||||
strongSelf.loadPatternForSizeIfNeeded(size: size, transition: .immediate)
|
||||
if let (size, tile) = strongSelf.validLayout {
|
||||
strongSelf.loadPatternForSizeIfNeeded(size: size, tile: tile, transition: .immediate)
|
||||
} else {
|
||||
strongSelf._isReady.set(true)
|
||||
}
|
||||
@ -1067,7 +1067,7 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
|
||||
self.patternImageLayer.suspendCompositionUpdates = false
|
||||
self.patternImageLayer.updateCompositionIfNeeded()
|
||||
} else {
|
||||
let patternArguments = TransformImageArguments(corners: ImageCorners(), imageSize: size, boundingSize: size, intrinsicInsets: UIEdgeInsets(), custom: PatternWallpaperArguments(colors: [patternBackgroundColor], rotation: nil, customPatternColor: patternColor, preview: false), scale: min(2.0, UIScreenScale))
|
||||
let patternArguments = TransformImageArguments(corners: ImageCorners(), imageSize: size, boundingSize: size, intrinsicInsets: UIEdgeInsets(), custom: PatternWallpaperArguments(colors: [patternBackgroundColor], rotation: nil, customPatternColor: patternColor, preview: false, tile: tile), scale: min(2.0, UIScreenScale))
|
||||
if self.useSharedAnimationPhase || self.patternImageLayer.contents == nil {
|
||||
if let drawingContext = validPatternImage.generate(patternArguments) {
|
||||
if let image = drawingContext.generateImage() {
|
||||
@ -1121,9 +1121,9 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
|
||||
transition.updateFrame(layer: self.patternImageLayer, frame: CGRect(origin: CGPoint(), size: size))
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
func updateLayout(size: CGSize, tile: Bool, transition: ContainedViewLayoutTransition) {
|
||||
let isFirstLayout = self.validLayout == nil
|
||||
self.validLayout = size
|
||||
self.validLayout = (size, tile)
|
||||
|
||||
if let blurredBackgroundPortalSourceView = self.blurredBackgroundPortalSourceView {
|
||||
transition.updateFrame(view: blurredBackgroundPortalSourceView, frame: CGRect(origin: CGPoint(), size: size))
|
||||
@ -1151,7 +1151,7 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
|
||||
outgoingBubbleGradientBackgroundNode.updateLayout(size: size, transition: transition, extendAnimation: false, backwards: false, completion: {})
|
||||
}
|
||||
|
||||
self.loadPatternForSizeIfNeeded(size: size, transition: transition)
|
||||
self.loadPatternForSizeIfNeeded(size: size, tile: tile, transition: transition)
|
||||
|
||||
/*for (animationNode, relativePosition) in self.inlineAnimationNodes {
|
||||
let sizeNorm = CGSize(width: 1440, height: 2960)
|
||||
@ -1201,7 +1201,7 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
|
||||
if bubbleTheme.chat.message.outgoing.bubble.withoutWallpaper.fill.count >= 3 && bubbleTheme.chat.animateMessageColors {
|
||||
if self.outgoingBubbleGradientBackgroundNode == nil {
|
||||
let outgoingBubbleGradientBackgroundNode = GradientBackgroundNode(adjustSaturation: false)
|
||||
if let size = self.validLayout {
|
||||
if let (size, _) = self.validLayout {
|
||||
outgoingBubbleGradientBackgroundNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||
outgoingBubbleGradientBackgroundNode.updateLayout(size: size, transition: .immediate, extendAnimation: false, backwards: false, completion: {})
|
||||
}
|
||||
@ -2021,7 +2021,7 @@ final class WallpaperBackgroundNodeMergedImpl: ASDisplayNode, WallpaperBackgroun
|
||||
self.isSettingUpWallpaper = true
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
func updateLayout(size: CGSize, tile: Bool, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = size
|
||||
|
||||
self.staticView.frame = CGRect(origin: CGPoint(), size: size)
|
||||
|
@ -341,13 +341,15 @@ public struct PatternWallpaperArguments: TransformImageCustomArguments {
|
||||
let preview: Bool
|
||||
let customPatternColor: UIColor?
|
||||
let bakePatternAlpha: CGFloat
|
||||
let tile: Bool
|
||||
|
||||
public init(colors: [UIColor], rotation: Int32?, customPatternColor: UIColor? = nil, preview: Bool = false, bakePatternAlpha: CGFloat = 1.0) {
|
||||
public init(colors: [UIColor], rotation: Int32?, customPatternColor: UIColor? = nil, preview: Bool = false, bakePatternAlpha: CGFloat = 1.0, tile: Bool = false) {
|
||||
self.colors = colors
|
||||
self.rotation = rotation
|
||||
self.customPatternColor = customPatternColor
|
||||
self.preview = preview
|
||||
self.bakePatternAlpha = bakePatternAlpha
|
||||
self.tile = tile
|
||||
}
|
||||
|
||||
public func serialized() -> NSArray {
|
||||
@ -359,6 +361,7 @@ public struct PatternWallpaperArguments: TransformImageCustomArguments {
|
||||
}
|
||||
array.add(NSNumber(value: self.preview))
|
||||
array.add(NSNumber(value: Double(self.bakePatternAlpha)))
|
||||
array.add(NSNumber(value: self.tile))
|
||||
return array
|
||||
}
|
||||
}
|
||||
@ -539,12 +542,13 @@ private func patternWallpaperImageInternal(fullSizeData: Data?, fullSizeComplete
|
||||
c.restoreGState()
|
||||
}
|
||||
|
||||
let tile = customArguments.tile
|
||||
let overlayImage = generateImage(arguments.drawingRect.size, rotatedContext: { size, c in
|
||||
c.clear(CGRect(origin: CGPoint(), size: size))
|
||||
var image: UIImage?
|
||||
if let fullSizeData = fullSizeData {
|
||||
if mode == .screen {
|
||||
image = renderPreparedImage(fullSizeData, CGSize(width: size.width * context.scale, height: size.height * context.scale), .black, 1.0)
|
||||
image = renderPreparedImage(fullSizeData, CGSize(width: size.width * context.scale, height: size.height * context.scale), .black, 1.0, tile)
|
||||
} else {
|
||||
image = UIImage(data: fullSizeData)
|
||||
}
|
||||
@ -566,39 +570,57 @@ private func patternWallpaperImageInternal(fullSizeData: Data?, fullSizeComplete
|
||||
if abs(fittedSize.height - arguments.boundingSize.height).isLessThanOrEqualTo(CGFloat(1.0)) {
|
||||
fittedSize.height = arguments.boundingSize.height
|
||||
}
|
||||
fittedSize = fittedSize.aspectFilled(arguments.drawingRect.size)
|
||||
|
||||
let fittedRect = CGRect(origin: CGPoint(x: drawingRect.origin.x + (drawingRect.size.width - fittedSize.width) / 2.0, y: drawingRect.origin.y + (drawingRect.size.height - fittedSize.height) / 2.0), size: fittedSize)
|
||||
|
||||
c.interpolationQuality = customArguments.preview ? .low : .medium
|
||||
c.clip(to: fittedRect, mask: image.cgImage!)
|
||||
|
||||
if let customPatternColor = customArguments.customPatternColor {
|
||||
c.setFillColor(customPatternColor.cgColor)
|
||||
c.fill(CGRect(origin: CGPoint(), size: arguments.drawingRect.size))
|
||||
} else if colors.count >= 3 && customArguments.customPatternColor == nil {
|
||||
c.setFillColor(UIColor(white: 0.0, alpha: 0.5).cgColor)
|
||||
c.fill(CGRect(origin: CGPoint(), size: arguments.drawingRect.size))
|
||||
} else if colors.count == 1 {
|
||||
c.setFillColor(customArguments.customPatternColor?.cgColor ?? patternColor(for: color, intensity: intensity, prominent: prominent).cgColor)
|
||||
c.fill(CGRect(origin: CGPoint(), size: arguments.drawingRect.size))
|
||||
if tile {
|
||||
fittedSize = fittedSize.aspectFitted(arguments.drawingRect.size)
|
||||
} else {
|
||||
let gradientColors = colors.map { patternColor(for: $0, intensity: intensity, prominent: prominent).cgColor } as CFArray
|
||||
let delta: CGFloat = 1.0 / (CGFloat(colors.count) - 1.0)
|
||||
|
||||
var locations: [CGFloat] = []
|
||||
for i in 0 ..< colors.count {
|
||||
locations.append(delta * CGFloat(i))
|
||||
}
|
||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)!
|
||||
|
||||
c.translateBy(x: arguments.drawingSize.width / 2.0, y: arguments.drawingSize.height / 2.0)
|
||||
c.rotate(by: CGFloat(customArguments.rotation ?? 0) * CGFloat.pi / -180.0)
|
||||
c.translateBy(x: -arguments.drawingSize.width / 2.0, y: -arguments.drawingSize.height / 2.0)
|
||||
|
||||
c.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 0.0, y: arguments.drawingSize.height), options: [.drawsBeforeStartLocation, .drawsAfterEndLocation])
|
||||
fittedSize = fittedSize.aspectFilled(arguments.drawingRect.size)
|
||||
}
|
||||
|
||||
c.interpolationQuality = customArguments.preview ? .low : .medium
|
||||
|
||||
let drawTile: (CGRect) -> Void = { fittedRect in
|
||||
c.saveGState()
|
||||
c.clip(to: fittedRect, mask: image.cgImage!)
|
||||
|
||||
if let customPatternColor = customArguments.customPatternColor {
|
||||
c.setFillColor(customPatternColor.cgColor)
|
||||
c.fill(CGRect(origin: CGPoint(), size: arguments.drawingRect.size))
|
||||
} else if colors.count >= 3 && customArguments.customPatternColor == nil {
|
||||
c.setFillColor(UIColor(white: 0.0, alpha: 0.5).cgColor)
|
||||
c.fill(CGRect(origin: CGPoint(), size: arguments.drawingRect.size))
|
||||
} else if colors.count == 1 {
|
||||
c.setFillColor(customArguments.customPatternColor?.cgColor ?? patternColor(for: color, intensity: intensity, prominent: prominent).cgColor)
|
||||
c.fill(CGRect(origin: CGPoint(), size: arguments.drawingRect.size))
|
||||
} else {
|
||||
let gradientColors = colors.map { patternColor(for: $0, intensity: intensity, prominent: prominent).cgColor } as CFArray
|
||||
let delta: CGFloat = 1.0 / (CGFloat(colors.count) - 1.0)
|
||||
|
||||
var locations: [CGFloat] = []
|
||||
for i in 0 ..< colors.count {
|
||||
locations.append(delta * CGFloat(i))
|
||||
}
|
||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)!
|
||||
|
||||
c.translateBy(x: arguments.drawingSize.width / 2.0, y: arguments.drawingSize.height / 2.0)
|
||||
c.rotate(by: CGFloat(customArguments.rotation ?? 0) * CGFloat.pi / -180.0)
|
||||
c.translateBy(x: -arguments.drawingSize.width / 2.0, y: -arguments.drawingSize.height / 2.0)
|
||||
|
||||
c.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 0.0, y: arguments.drawingSize.height), options: [.drawsBeforeStartLocation, .drawsAfterEndLocation])
|
||||
}
|
||||
c.restoreGState()
|
||||
}
|
||||
|
||||
if tile {
|
||||
var fittedRect = CGRect(origin: CGPoint(x: drawingRect.origin.x, y: drawingRect.origin.y + (drawingRect.size.height - fittedSize.height) / 2.0), size: fittedSize)
|
||||
drawTile(fittedRect)
|
||||
fittedRect = fittedRect.offsetBy(dx: fittedSize.width, dy: 0.0)
|
||||
drawTile(fittedRect)
|
||||
} else {
|
||||
let fittedRect = CGRect(origin: CGPoint(x: drawingRect.origin.x + (drawingRect.size.width - fittedSize.width) / 2.0, y: drawingRect.origin.y + (drawingRect.size.height - fittedSize.height) / 2.0), size: fittedSize)
|
||||
drawTile(fittedRect)
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
if let customPatternColor = customArguments.customPatternColor, customPatternColor.alpha < 1.0 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user