diff --git a/submodules/StickerPackPreviewUI/Sources/StickerPreviewControllerNode.swift b/submodules/StickerPackPreviewUI/Sources/StickerPreviewControllerNode.swift index f0cda8dd1c4..ff2be8f498c 100644 --- a/submodules/StickerPackPreviewUI/Sources/StickerPreviewControllerNode.swift +++ b/submodules/StickerPackPreviewUI/Sources/StickerPreviewControllerNode.swift @@ -138,7 +138,7 @@ final class StickerPreviewControllerNode: ASDisplayNode, ASScrollViewDelegate { self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(32.0), textColor: .black) break } - self.imageNode.setSignal(chatMessageSticker(account: context.account, userLocation: .other, file: itemFile, small: false, onlyFullSize: false)) + self.imageNode.setSignal(chatMessageSticker(account: context.account, userLocation: .other, file: itemFile, small: false, fetched: true, onlyFullSize: false, blurThumbnail: false)) if let (layout, navigationBarHeight) = self.containerLayout { self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate) diff --git a/submodules/StickerPeekUI/Sources/StickerPreviewPeekContent.swift b/submodules/StickerPeekUI/Sources/StickerPreviewPeekContent.swift index 0d8028d905e..7453e666104 100644 --- a/submodules/StickerPeekUI/Sources/StickerPreviewPeekContent.swift +++ b/submodules/StickerPeekUI/Sources/StickerPreviewPeekContent.swift @@ -164,12 +164,10 @@ public final class StickerPreviewPeekContentNode: ASDisplayNode, PeekControllerC self.animationNode = animationNode let dimensions = file.dimensions ?? PixelDimensions(width: 512, height: 512) - let fitSize: CGSize - if file.isCustomEmoji { - fitSize = CGSize(width: 200.0, height: 200.0) - } else { - fitSize = CGSize(width: 400.0, height: 400.0) - } + // Decode at native sticker size (capped 512) for peek/enlarged presentation. + // Previously custom emoji used a ~200px buffer while displayed on Retina, + // which upscaled a soft raster — same class of bug as Desktop media viewer. + let fitSize = CGSize(width: 512.0, height: 512.0) let fittedDimensions = dimensions.cgSize.aspectFitted(fitSize) if file.isCustomTemplateEmoji { @@ -194,7 +192,7 @@ public final class StickerPreviewPeekContentNode: ASDisplayNode, PeekControllerC self.animationNode = nil } - self.imageNode.setSignal(chatMessageSticker(account: context.account, userLocation: .other, file: file, small: false, fetched: true)) + self.imageNode.setSignal(chatMessageSticker(account: context.account, userLocation: .other, file: file, small: false, fetched: true, onlyFullSize: false, blurThumbnail: false)) } else if case .portal = item { self._ready.set(.single(true)) } @@ -267,7 +265,7 @@ public final class StickerPreviewPeekContentNode: ASDisplayNode, PeekControllerC public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) -> CGSize { let boundingSize: CGSize if self.item.file?.isCustomEmoji == true { - boundingSize = CGSize(width: 120.0, height: 120.0) + boundingSize = CGSize(width: 180.0, height: 180.0).fitted(size) } else if let _ = self.additionalAnimationNode { boundingSize = CGSize(width: 240.0, height: 240.0).fitted(size) } else { diff --git a/submodules/StickerResources/Sources/StickerResources.swift b/submodules/StickerResources/Sources/StickerResources.swift index d435924b581..d136173dec5 100644 --- a/submodules/StickerResources/Sources/StickerResources.swift +++ b/submodules/StickerResources/Sources/StickerResources.swift @@ -261,8 +261,8 @@ public func chatMessageAnimatedStickerBackingData(postbox: Postbox, fileReferenc } -public func chatMessageSticker(account: Account, userLocation: MediaResourceUserLocation, file: TelegramMediaFile, small: Bool, fetched: Bool = false, onlyFullSize: Bool = false, thumbnail: Bool = false, synchronousLoad: Bool = false, colorSpace: CGColorSpace? = nil) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { - return chatMessageSticker(postbox: account.postbox, userLocation: userLocation, file: file, small: small, fetched: fetched, onlyFullSize: onlyFullSize, thumbnail: thumbnail, synchronousLoad: synchronousLoad, colorSpace: colorSpace) +public func chatMessageSticker(account: Account, userLocation: MediaResourceUserLocation, file: TelegramMediaFile, small: Bool, fetched: Bool = false, onlyFullSize: Bool = false, thumbnail: Bool = false, synchronousLoad: Bool = false, colorSpace: CGColorSpace? = nil, blurThumbnail: Bool = true) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { + return chatMessageSticker(postbox: account.postbox, userLocation: userLocation, file: file, small: small, fetched: fetched, onlyFullSize: onlyFullSize, thumbnail: thumbnail, synchronousLoad: synchronousLoad, colorSpace: colorSpace, blurThumbnail: blurThumbnail) } public func chatMessageStickerPackThumbnail(postbox: Postbox, resource: MediaResource, animated: Bool = false, synchronousLoad: Bool = false, nilIfEmpty: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { @@ -318,7 +318,7 @@ public func chatMessageStickerPackThumbnail(postbox: Postbox, resource: MediaRes } } -public func chatMessageSticker(postbox: Postbox, userLocation: MediaResourceUserLocation, file: TelegramMediaFile, small: Bool, fetched: Bool = false, onlyFullSize: Bool = false, thumbnail: Bool = false, synchronousLoad: Bool = false, colorSpace: CGColorSpace? = nil) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { +public func chatMessageSticker(postbox: Postbox, userLocation: MediaResourceUserLocation, file: TelegramMediaFile, small: Bool, fetched: Bool = false, onlyFullSize: Bool = false, thumbnail: Bool = false, synchronousLoad: Bool = false, colorSpace: CGColorSpace? = nil, blurThumbnail: Bool = true) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { let signal: Signal, NoError> if thumbnail { @@ -367,7 +367,9 @@ public func chatMessageSticker(postbox: Postbox, userLocation: MediaResourceUser var blurredThumbnailImage: UIImage? let thumbnailInset: CGFloat = 10.0 - if let thumbnailImage = thumbnailImage { + // Enlarged/peek viewers pass blurThumbnail: false so a waiting thumb is + // sharp-upscaled instead of Blur-softened (matches Desktop media viewer). + if blurThumbnail, let thumbnailImage = thumbnailImage { let thumbnailSize = thumbnailImage.0.size var thumbnailContextSize = thumbnailSize.aspectFitted(CGSize(width: 150.0, height: 150.0)) let thumbnailDrawingSize = thumbnailContextSize @@ -403,6 +405,11 @@ public func chatMessageSticker(postbox: Postbox, userLocation: MediaResourceUser c.interpolationQuality = .low let thumbnailScaledInset = thumbnailInset * (fittedRect.width / blurredThumbnailImage.size.width) c.draw(blurredThumbnailImage.cgImage!, in: fittedRect.insetBy(dx: -thumbnailScaledInset, dy: -thumbnailScaledInset)) + } else if let thumbnailImage = thumbnailImage, let cgImage = thumbnailImage.0.cgImage, let cgImageAlpha = thumbnailImage.1.cgImage { + c.setBlendMode(.normal) + c.interpolationQuality = .medium + let mask = CGImage(maskWidth: cgImageAlpha.width, height: cgImageAlpha.height, bitsPerComponent: cgImageAlpha.bitsPerComponent, bitsPerPixel: cgImageAlpha.bitsPerPixel, bytesPerRow: cgImageAlpha.bytesPerRow, provider: cgImageAlpha.dataProvider!, decode: nil, shouldInterpolate: true) + c.draw(cgImage.masking(mask!)!, in: fittedRect) } if let fullSizeImage = fullSizeImage, let cgImage = fullSizeImage.0.cgImage, let cgImageAlpha = fullSizeImage.1.cgImage { @@ -420,7 +427,7 @@ public func chatMessageSticker(postbox: Postbox, userLocation: MediaResourceUser } } -public func chatMessageAnimatedSticker(postbox: Postbox, userLocation: MediaResourceUserLocation, file: TelegramMediaFile, small: Bool, size: CGSize, fitzModifier: EmojiFitzModifier? = nil, fetched: Bool = false, onlyFullSize: Bool = false, thumbnail: Bool = false, synchronousLoad: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { +public func chatMessageAnimatedSticker(postbox: Postbox, userLocation: MediaResourceUserLocation, file: TelegramMediaFile, small: Bool, size: CGSize, fitzModifier: EmojiFitzModifier? = nil, fetched: Bool = false, onlyFullSize: Bool = false, thumbnail: Bool = false, synchronousLoad: Bool = false, blurThumbnail: Bool = true) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { let signal: Signal, NoError> if thumbnail { signal = chatMessageStickerThumbnailData(postbox: postbox, userLocation: userLocation, file: file, synchronousLoad: synchronousLoad) @@ -464,7 +471,7 @@ public func chatMessageAnimatedSticker(postbox: Postbox, userLocation: MediaReso var blurredThumbnailImage: UIImage? let thumbnailInset: CGFloat = 10.0 - if let thumbnailImage = thumbnailImage { + if blurThumbnail, let thumbnailImage = thumbnailImage { let thumbnailSize = thumbnailImage.0.size var thumbnailContextSize = thumbnailSize.aspectFitted(CGSize(width: 150.0, height: 150.0)) let thumbnailDrawingSize = thumbnailContextSize @@ -502,6 +509,11 @@ public func chatMessageAnimatedSticker(postbox: Postbox, userLocation: MediaReso let thumbnailFittedRect = CGRect(origin: CGPoint(x: fittedRect.origin.x - (thumbnailFittedSize.width - fittedRect.width) / 2.0, y: fittedRect.origin.y - (thumbnailFittedSize.height - fittedRect.height) / 2.0), size: thumbnailFittedSize) let thumbnailScaledInset = thumbnailInset * (fittedRect.width / blurredThumbnailImage.size.width) c.draw(blurredThumbnailImage.cgImage!, in: thumbnailFittedRect.insetBy(dx: -thumbnailScaledInset, dy: -thumbnailScaledInset)) + } else if let thumbnailImage = thumbnailImage, let cgImage = thumbnailImage.0.cgImage, let cgImageAlpha = thumbnailImage.1.cgImage { + c.setBlendMode(.normal) + c.interpolationQuality = .medium + let mask = CGImage(maskWidth: cgImageAlpha.width, height: cgImageAlpha.height, bitsPerComponent: cgImageAlpha.bitsPerComponent, bitsPerPixel: cgImageAlpha.bitsPerPixel, bytesPerRow: cgImageAlpha.bytesPerRow, provider: cgImageAlpha.dataProvider!, decode: nil, shouldInterpolate: true) + c.draw(cgImage.masking(mask!)!, in: fittedRect) } if let fullSizeImage = fullSizeImage, let cgImage = fullSizeImage.0.cgImage, let cgImageAlpha = fullSizeImage.1.cgImage {