mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
562265997d
@ -614,7 +614,7 @@ private final class AnimatedStickerDirectFrameSource: AnimatedStickerFrameSource
|
||||
self.data = data
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.bytesPerRow = (4 * Int(width) + 15) & (~15)
|
||||
self.bytesPerRow = DeviceGraphicsContextSettings.shared.bytesPerRow(forWidth: Int(width))
|
||||
self.currentFrame = 0
|
||||
let rawData = TGGUnzipData(data, 8 * 1024 * 1024) ?? data
|
||||
let decompressedData = transformedWithFitzModifier(data: rawData, fitzModifier: fitzModifier)
|
||||
|
@ -13,7 +13,7 @@ final class SoftwareAnimationRenderer: ASDisplayNode, AnimationRenderer {
|
||||
queue.async { [weak self] in
|
||||
switch type {
|
||||
case .argb:
|
||||
let calculatedBytesPerRow = (4 * Int(width) + 15) & (~15)
|
||||
let calculatedBytesPerRow = DeviceGraphicsContextSettings.shared.bytesPerRow(forWidth: Int(width))
|
||||
assert(bytesPerRow == calculatedBytesPerRow)
|
||||
case .yuva:
|
||||
break
|
||||
|
@ -6,7 +6,7 @@
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import "ASCGImageBuffer.h"
|
||||
#import <AsyncDisplayKit/ASCGImageBuffer.h>
|
||||
|
||||
#import <sys/mman.h>
|
||||
#import <mach/mach_init.h>
|
||||
@ -32,7 +32,7 @@
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_length = length;
|
||||
_isVM = (length >= vm_page_size);
|
||||
_isVM = false;//(length >= vm_page_size);
|
||||
if (_isVM) {
|
||||
_mutableBytes = mmap(NULL, length, PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, VM_MAKE_TAG(VM_MEMORY_COREGRAPHICS_DATA), 0);
|
||||
if (_mutableBytes == MAP_FAILED) {
|
||||
@ -43,7 +43,7 @@
|
||||
|
||||
// Check the VM flag again because we may have failed above.
|
||||
if (!_isVM) {
|
||||
_mutableBytes = calloc(1, length);
|
||||
_mutableBytes = malloc(length);
|
||||
}
|
||||
}
|
||||
return self;
|
||||
|
@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
#import <AsyncDisplayKit/ASGraphicsContext.h>
|
||||
#import "ASCGImageBuffer.h"
|
||||
#import <AsyncDisplayKit/ASCGImageBuffer.h>
|
||||
#import <AsyncDisplayKit/ASAssert.h>
|
||||
#import <AsyncDisplayKit/ASConfigurationInternal.h>
|
||||
#import <AsyncDisplayKit/ASInternalHelpers.h>
|
||||
|
@ -161,7 +161,7 @@ public func peerAvatarImage(account: Account, peerReference: PeerReference?, aut
|
||||
}
|
||||
if shouldBlur {
|
||||
let imageContextSize = CGSize(width: 64.0, height: 64.0)
|
||||
let imageContext = DrawingContext(size: imageContextSize, scale: 1.0, premultiplied: true, clear: true)
|
||||
let imageContext = DrawingContext(size: imageContextSize, scale: 1.0, clear: true)
|
||||
imageContext.withFlippedContext { c in
|
||||
c.draw(dataImage, in: CGRect(origin: CGPoint(), size: imageContextSize))
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Accelerate
|
||||
import AsyncDisplayKit
|
||||
|
||||
public let deviceColorSpace: CGColorSpace = {
|
||||
if #available(iOSApplicationExtension 9.3, iOS 9.3, *) {
|
||||
@ -19,38 +20,20 @@ private let grayscaleColorSpace = CGColorSpaceCreateDeviceGray()
|
||||
let deviceScale = UIScreen.main.scale
|
||||
|
||||
public func generateImagePixel(_ size: CGSize, scale: CGFloat, pixelGenerator: (CGSize, UnsafeMutablePointer<UInt8>, Int) -> Void) -> UIImage? {
|
||||
let scaledSize = CGSize(width: size.width * scale, height: size.height * scale)
|
||||
let bytesPerRow = (4 * Int(scaledSize.width) + 15) & (~15)
|
||||
let length = bytesPerRow * Int(scaledSize.height)
|
||||
let bytes = malloc(length)!.assumingMemoryBound(to: UInt8.self)
|
||||
guard let provider = CGDataProvider(dataInfo: bytes, data: bytes, size: length, releaseData: { bytes, _, _ in
|
||||
free(bytes)
|
||||
})
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
pixelGenerator(scaledSize, bytes, bytesPerRow)
|
||||
|
||||
let bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue)
|
||||
|
||||
guard let image = CGImage(width: Int(scaledSize.width), height: Int(scaledSize.height), bitsPerComponent: 8, bitsPerPixel: 32, bytesPerRow: bytesPerRow, space: deviceColorSpace, bitmapInfo: bitmapInfo, provider: provider, decode: nil, shouldInterpolate: false, intent: .defaultIntent)
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return UIImage(cgImage: image, scale: scale, orientation: .up)
|
||||
let context = DrawingContext(size: size, scale: scale, opaque: false, clear: false)
|
||||
pixelGenerator(CGSize(width: size.width * scale, height: size.height * scale), context.bytes.assumingMemoryBound(to: UInt8.self), context.bytesPerRow)
|
||||
return context.generateImage()
|
||||
}
|
||||
|
||||
private func withImageBytes(image: UIImage, _ f: (UnsafePointer<UInt8>, Int, Int, Int) -> Void) {
|
||||
let selectedScale = image.scale
|
||||
let scaledSize = CGSize(width: image.size.width * selectedScale, height: image.size.height * selectedScale)
|
||||
let bytesPerRow = (4 * Int(scaledSize.width) + 15) & (~15)
|
||||
let bytesPerRow = DeviceGraphicsContextSettings.shared.bytesPerRow(forWidth: Int(scaledSize.width))
|
||||
let length = bytesPerRow * Int(scaledSize.height)
|
||||
let bytes = malloc(length)!.assumingMemoryBound(to: UInt8.self)
|
||||
memset(bytes, 0, length)
|
||||
|
||||
let bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue)
|
||||
let bitmapInfo = DeviceGraphicsContextSettings.shared.transparentBitmapInfo
|
||||
|
||||
guard let context = CGContext(data: bytes, width: Int(scaledSize.width), height: Int(scaledSize.height), bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: deviceColorSpace, bitmapInfo: bitmapInfo.rawValue) else {
|
||||
return
|
||||
@ -65,7 +48,7 @@ private func withImageBytes(image: UIImage, _ f: (UnsafePointer<UInt8>, Int, Int
|
||||
public func generateGrayscaleAlphaMaskImage(image: UIImage) -> UIImage? {
|
||||
let selectedScale = image.scale
|
||||
let scaledSize = CGSize(width: image.size.width * selectedScale, height: image.size.height * selectedScale)
|
||||
let bytesPerRow = (1 * Int(scaledSize.width) + 15) & (~15)
|
||||
let bytesPerRow = (1 * Int(scaledSize.width) + 31) & (~31)
|
||||
let length = bytesPerRow * Int(scaledSize.height)
|
||||
let bytes = malloc(length)!.assumingMemoryBound(to: UInt8.self)
|
||||
memset(bytes, 0, length)
|
||||
@ -111,69 +94,25 @@ public func generateGrayscaleAlphaMaskImage(image: UIImage) -> UIImage? {
|
||||
}
|
||||
|
||||
public func generateImage(_ size: CGSize, contextGenerator: (CGSize, CGContext) -> Void, opaque: Bool = false, scale: CGFloat? = nil) -> UIImage? {
|
||||
let selectedScale = scale ?? deviceScale
|
||||
let scaledSize = CGSize(width: size.width * selectedScale, height: size.height * selectedScale)
|
||||
let bytesPerRow = (4 * Int(scaledSize.width) + 15) & (~15)
|
||||
let length = bytesPerRow * Int(scaledSize.height)
|
||||
let bytes = malloc(length)!.assumingMemoryBound(to: Int8.self)
|
||||
|
||||
guard let provider = CGDataProvider(dataInfo: bytes, data: bytes, size: length, releaseData: { bytes, _, _ in
|
||||
free(bytes)
|
||||
})
|
||||
else {
|
||||
if size.width.isZero || size.height.isZero {
|
||||
return nil
|
||||
}
|
||||
|
||||
let bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo.byteOrder32Little.rawValue | (opaque ? CGImageAlphaInfo.noneSkipFirst.rawValue : CGImageAlphaInfo.premultipliedFirst.rawValue))
|
||||
|
||||
guard let context = CGContext(data: bytes, width: Int(scaledSize.width), height: Int(scaledSize.height), bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: deviceColorSpace, bitmapInfo: bitmapInfo.rawValue) else {
|
||||
return nil
|
||||
let context = DrawingContext(size: size, scale: scale ?? 0.0, opaque: opaque, clear: false)
|
||||
context.withFlippedContext { c in
|
||||
contextGenerator(context.size, c)
|
||||
}
|
||||
|
||||
context.scaleBy(x: selectedScale, y: selectedScale)
|
||||
|
||||
contextGenerator(size, context)
|
||||
|
||||
guard let image = CGImage(width: Int(scaledSize.width), height: Int(scaledSize.height), bitsPerComponent: 8, bitsPerPixel: 32, bytesPerRow: bytesPerRow, space: deviceColorSpace, bitmapInfo: bitmapInfo, provider: provider, decode: nil, shouldInterpolate: false, intent: .defaultIntent)
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return UIImage(cgImage: image, scale: selectedScale, orientation: .up)
|
||||
return context.generateImage()
|
||||
}
|
||||
|
||||
public func generateImage(_ size: CGSize, opaque: Bool = false, scale: CGFloat? = nil, rotatedContext: (CGSize, CGContext) -> Void) -> UIImage? {
|
||||
let selectedScale = scale ?? deviceScale
|
||||
let scaledSize = CGSize(width: size.width * selectedScale, height: size.height * selectedScale)
|
||||
let bytesPerRow = (4 * Int(scaledSize.width) + 15) & (~15)
|
||||
let length = bytesPerRow * Int(scaledSize.height)
|
||||
let bytes = malloc(length)!.assumingMemoryBound(to: Int8.self)
|
||||
|
||||
guard let provider = CGDataProvider(dataInfo: bytes, data: bytes, size: length, releaseData: { bytes, _, _ in
|
||||
free(bytes)
|
||||
}) else {
|
||||
if size.width.isZero || size.height.isZero {
|
||||
return nil
|
||||
}
|
||||
|
||||
let bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo.byteOrder32Little.rawValue | (opaque ? CGImageAlphaInfo.noneSkipFirst.rawValue : CGImageAlphaInfo.premultipliedFirst.rawValue))
|
||||
|
||||
guard let context = CGContext(data: bytes, width: Int(scaledSize.width), height: Int(scaledSize.height), bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: deviceColorSpace, bitmapInfo: bitmapInfo.rawValue) else {
|
||||
return nil
|
||||
let context = DrawingContext(size: size, scale: scale ?? 0.0, opaque: opaque, clear: false)
|
||||
context.withContext { c in
|
||||
rotatedContext(context.size, c)
|
||||
}
|
||||
|
||||
context.scaleBy(x: selectedScale, y: selectedScale)
|
||||
context.translateBy(x: size.width / 2.0, y: size.height / 2.0)
|
||||
context.scaleBy(x: 1.0, y: -1.0)
|
||||
context.translateBy(x: -size.width / 2.0, y: -size.height / 2.0)
|
||||
|
||||
rotatedContext(size, context)
|
||||
|
||||
guard let image = CGImage(width: Int(scaledSize.width), height: Int(scaledSize.height), bitsPerComponent: 8, bitsPerPixel: 32, bytesPerRow: bytesPerRow, space: deviceColorSpace, bitmapInfo: bitmapInfo, provider: provider, decode: nil, shouldInterpolate: false, intent: .defaultIntent)
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return UIImage(cgImage: image, scale: selectedScale, orientation: .up)
|
||||
return context.generateImage()
|
||||
}
|
||||
|
||||
public func generateFilledCircleImage(diameter: CGFloat, color: UIColor?, strokeColor: UIColor? = nil, strokeWidth: CGFloat? = nil, backgroundColor: UIColor? = nil) -> UIImage? {
|
||||
@ -433,6 +372,47 @@ public enum DrawingContextBltMode {
|
||||
case Alpha
|
||||
}
|
||||
|
||||
public struct DeviceGraphicsContextSettings {
|
||||
public static let shared: DeviceGraphicsContextSettings = {
|
||||
UIGraphicsBeginImageContextWithOptions(CGSize(width: 1.0, height: 1.0), true, 1.0)
|
||||
let refContext = UIGraphicsGetCurrentContext()!
|
||||
let bytesPerRow = refContext.bytesPerRow
|
||||
let bitsPerPixel = refContext.bitsPerPixel
|
||||
let bitsPerComponent = refContext.bitsPerComponent
|
||||
let opaqueBitmapInfo = refContext.bitmapInfo
|
||||
let image = UIGraphicsGetImageFromCurrentImageContext()!
|
||||
let colorSpace = image.cgImage!.colorSpace!
|
||||
assert(bytesPerRow == 32)
|
||||
UIGraphicsEndImageContext()
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(CGSize(width: 1.0, height: 1.0), false, 1.0)
|
||||
let refCtxTransparent = UIGraphicsGetCurrentContext()!
|
||||
let transparentBitmapInfo = refCtxTransparent.bitmapInfo
|
||||
UIGraphicsEndImageContext()
|
||||
|
||||
return DeviceGraphicsContextSettings(
|
||||
rowAlignment: bytesPerRow,
|
||||
bitsPerPixel: bitsPerPixel,
|
||||
bitsPerComponent: bitsPerComponent,
|
||||
opaqueBitmapInfo: opaqueBitmapInfo,
|
||||
transparentBitmapInfo: transparentBitmapInfo,
|
||||
colorSpace: colorSpace
|
||||
)
|
||||
}()
|
||||
|
||||
public let rowAlignment: Int
|
||||
public let bitsPerPixel: Int
|
||||
public let bitsPerComponent: Int
|
||||
public let opaqueBitmapInfo: CGBitmapInfo
|
||||
public let transparentBitmapInfo: CGBitmapInfo
|
||||
public let colorSpace: CGColorSpace
|
||||
|
||||
public func bytesPerRow(forWidth width: Int) -> Int {
|
||||
let baseValue = self.bitsPerPixel * width / 8
|
||||
return (baseValue + 31) & ~0x1F
|
||||
}
|
||||
}
|
||||
|
||||
public class DrawingContext {
|
||||
public let size: CGSize
|
||||
public let scale: CGFloat
|
||||
@ -440,46 +420,36 @@ public class DrawingContext {
|
||||
public let bytesPerRow: Int
|
||||
private let bitmapInfo: CGBitmapInfo
|
||||
public let length: Int
|
||||
public let bytes: UnsafeMutableRawPointer
|
||||
let provider: CGDataProvider?
|
||||
private let imageBuffer: ASCGImageBuffer
|
||||
public var bytes: UnsafeMutableRawPointer {
|
||||
if self.hasGeneratedImage {
|
||||
preconditionFailure()
|
||||
}
|
||||
return self.imageBuffer.mutableBytes
|
||||
}
|
||||
private let context: CGContext
|
||||
|
||||
private var _context: CGContext?
|
||||
private var hasGeneratedImage = false
|
||||
|
||||
public func withContext(_ f: (CGContext) -> ()) {
|
||||
if self._context == nil {
|
||||
if let c = CGContext(data: bytes, width: Int(scaledSize.width), height: Int(scaledSize.height), bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: deviceColorSpace, bitmapInfo: self.bitmapInfo.rawValue) {
|
||||
c.scaleBy(x: scale, y: scale)
|
||||
self._context = c
|
||||
}
|
||||
}
|
||||
let context = self.context
|
||||
|
||||
if let _context = self._context {
|
||||
_context.translateBy(x: self.size.width / 2.0, y: self.size.height / 2.0)
|
||||
_context.scaleBy(x: 1.0, y: -1.0)
|
||||
_context.translateBy(x: -self.size.width / 2.0, y: -self.size.height / 2.0)
|
||||
context.translateBy(x: self.size.width / 2.0, y: self.size.height / 2.0)
|
||||
context.scaleBy(x: 1.0, y: -1.0)
|
||||
context.translateBy(x: -self.size.width / 2.0, y: -self.size.height / 2.0)
|
||||
|
||||
f(_context)
|
||||
f(context)
|
||||
|
||||
_context.translateBy(x: self.size.width / 2.0, y: self.size.height / 2.0)
|
||||
_context.scaleBy(x: 1.0, y: -1.0)
|
||||
_context.translateBy(x: -self.size.width / 2.0, y: -self.size.height / 2.0)
|
||||
}
|
||||
context.translateBy(x: self.size.width / 2.0, y: self.size.height / 2.0)
|
||||
context.scaleBy(x: 1.0, y: -1.0)
|
||||
context.translateBy(x: -self.size.width / 2.0, y: -self.size.height / 2.0)
|
||||
}
|
||||
|
||||
public func withFlippedContext(_ f: (CGContext) -> ()) {
|
||||
if self._context == nil {
|
||||
if let c = CGContext(data: bytes, width: Int(scaledSize.width), height: Int(scaledSize.height), bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: deviceColorSpace, bitmapInfo: self.bitmapInfo.rawValue) {
|
||||
c.scaleBy(x: scale, y: scale)
|
||||
self._context = c
|
||||
}
|
||||
f(self.context)
|
||||
}
|
||||
|
||||
if let _context = self._context {
|
||||
f(_context)
|
||||
}
|
||||
}
|
||||
|
||||
public init(size: CGSize, scale: CGFloat = 0.0, premultiplied: Bool = true, opaque: Bool = false, clear: Bool = false) {
|
||||
public init(size: CGSize, scale: CGFloat = 0.0, opaque: Bool = false, clear: Bool = false) {
|
||||
let actualScale: CGFloat
|
||||
if scale.isZero {
|
||||
actualScale = deviceScale
|
||||
@ -490,35 +460,61 @@ public class DrawingContext {
|
||||
self.scale = actualScale
|
||||
self.scaledSize = CGSize(width: size.width * actualScale, height: size.height * actualScale)
|
||||
|
||||
self.bytesPerRow = (4 * Int(scaledSize.width) + 15) & (~15)
|
||||
self.bytesPerRow = DeviceGraphicsContextSettings.shared.bytesPerRow(forWidth: Int(scaledSize.width))
|
||||
self.length = bytesPerRow * Int(scaledSize.height)
|
||||
|
||||
self.imageBuffer = ASCGImageBuffer(length: UInt(self.length))
|
||||
|
||||
if opaque {
|
||||
self.bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.noneSkipFirst.rawValue)
|
||||
} else if premultiplied {
|
||||
self.bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue)
|
||||
self.bitmapInfo = DeviceGraphicsContextSettings.shared.opaqueBitmapInfo
|
||||
} else {
|
||||
self.bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.first.rawValue)
|
||||
self.bitmapInfo = DeviceGraphicsContextSettings.shared.transparentBitmapInfo
|
||||
}
|
||||
|
||||
self.bytes = malloc(length)!
|
||||
self.context = CGContext(
|
||||
data: self.imageBuffer.mutableBytes,
|
||||
width: Int(self.scaledSize.width),
|
||||
height: Int(self.scaledSize.height),
|
||||
bitsPerComponent: DeviceGraphicsContextSettings.shared.bitsPerComponent,
|
||||
bytesPerRow: self.bytesPerRow,
|
||||
space: DeviceGraphicsContextSettings.shared.colorSpace,
|
||||
bitmapInfo: self.bitmapInfo.rawValue,
|
||||
releaseCallback: nil,
|
||||
releaseInfo: nil
|
||||
)!
|
||||
self.context.scaleBy(x: self.scale, y: self.scale)
|
||||
|
||||
if clear {
|
||||
memset(self.bytes, 0, self.length)
|
||||
}
|
||||
self.provider = CGDataProvider(dataInfo: bytes, data: bytes, size: length, releaseData: { bytes, _, _ in
|
||||
free(bytes)
|
||||
})
|
||||
|
||||
assert(self.bytesPerRow % 16 == 0)
|
||||
assert(Int64(Int(bitPattern: self.bytes)) % 16 == 0)
|
||||
}
|
||||
|
||||
public func generateImage() -> UIImage? {
|
||||
if self.scaledSize.width.isZero || self.scaledSize.height.isZero {
|
||||
return nil
|
||||
}
|
||||
if let image = CGImage(width: Int(scaledSize.width), height: Int(scaledSize.height), bitsPerComponent: 8, bitsPerPixel: 32, bytesPerRow: bytesPerRow, space: deviceColorSpace, bitmapInfo: bitmapInfo, provider: provider!, decode: nil, shouldInterpolate: false, intent: .defaultIntent) {
|
||||
return UIImage(cgImage: image, scale: scale, orientation: .up)
|
||||
if self.hasGeneratedImage {
|
||||
preconditionFailure()
|
||||
return nil
|
||||
}
|
||||
self.hasGeneratedImage = true
|
||||
|
||||
let dataProvider = self.imageBuffer.createDataProviderAndInvalidate()
|
||||
|
||||
if let image = CGImage(
|
||||
width: Int(self.scaledSize.width),
|
||||
height: Int(self.scaledSize.height),
|
||||
bitsPerComponent: self.context.bitsPerComponent,
|
||||
bitsPerPixel: self.context.bitsPerPixel,
|
||||
bytesPerRow: self.context.bytesPerRow,
|
||||
space: DeviceGraphicsContextSettings.shared.colorSpace,
|
||||
bitmapInfo: self.context.bitmapInfo,
|
||||
provider: dataProvider,
|
||||
decode: nil,
|
||||
shouldInterpolate: true,
|
||||
intent: .defaultIntent
|
||||
) {
|
||||
return UIImage(cgImage: image, scale: self.scale, orientation: .up)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ var deviceScale: CGFloat {
|
||||
func generateImage(_ size: CGSize, contextGenerator: (CGSize, CGContext) -> Void, opaque: Bool = false, scale: CGFloat? = nil) -> GImage? {
|
||||
let selectedScale = scale ?? deviceScale
|
||||
let scaledSize = CGSize(width: size.width * selectedScale, height: size.height * selectedScale)
|
||||
let bytesPerRow = (4 * Int(scaledSize.width) + 15) & (~15)
|
||||
let bytesPerRow = (4 * Int(scaledSize.width) + 31) & (~31)
|
||||
let length = bytesPerRow * Int(scaledSize.height)
|
||||
let bytes = malloc(length)!.assumingMemoryBound(to: Int8.self)
|
||||
|
||||
|
@ -113,7 +113,7 @@
|
||||
|
||||
_offscreenContextWidth = offscreenWidth;
|
||||
_offscreenContextHeight = offscreenHeight;
|
||||
_offscreenContextStride = ((4 * _offscreenContextWidth + 15) & (~15));
|
||||
_offscreenContextStride = ((4 * _offscreenContextWidth + 31) & (~31));
|
||||
_offscreenMemory = malloc(_offscreenContextStride * _offscreenContextHeight);
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
|
@ -21,7 +21,7 @@ protocol LegacyPaintEntity {
|
||||
}
|
||||
|
||||
private func render(width: Int, height: Int, bytesPerRow: Int, data: Data, type: AnimationRendererFrameType) -> CIImage? {
|
||||
let calculatedBytesPerRow = (4 * Int(width) + 15) & (~15)
|
||||
let calculatedBytesPerRow = (4 * Int(width) + 31) & (~31)
|
||||
assert(bytesPerRow == calculatedBytesPerRow)
|
||||
|
||||
let image = generateImagePixel(CGSize(width: CGFloat(width), height: CGFloat(height)), scale: 1.0, pixelGenerator: { _, pixelData, bytesPerRow in
|
||||
|
@ -13,6 +13,8 @@ public final class ManagedAnimationState {
|
||||
public let item: ManagedAnimationItem
|
||||
private let instance: LottieInstance
|
||||
|
||||
private let displaySize: CGSize
|
||||
|
||||
let frameCount: Int
|
||||
let fps: Double
|
||||
|
||||
@ -21,15 +23,11 @@ public final class ManagedAnimationState {
|
||||
|
||||
public var executedCallbacks = Set<Int>()
|
||||
|
||||
private let renderContext: DrawingContext
|
||||
|
||||
public init?(displaySize: CGSize, item: ManagedAnimationItem, current: ManagedAnimationState?) {
|
||||
let resolvedInstance: LottieInstance
|
||||
let renderContext: DrawingContext
|
||||
|
||||
if let current = current {
|
||||
resolvedInstance = current.instance
|
||||
renderContext = current.renderContext
|
||||
} else {
|
||||
guard let path = item.source.path else {
|
||||
return nil
|
||||
@ -44,20 +42,21 @@ public final class ManagedAnimationState {
|
||||
return nil
|
||||
}
|
||||
resolvedInstance = instance
|
||||
renderContext = DrawingContext(size: displaySize, scale: UIScreenScale, premultiplied: true, clear: true)
|
||||
}
|
||||
|
||||
self.displaySize = displaySize
|
||||
self.item = item
|
||||
self.instance = resolvedInstance
|
||||
self.renderContext = renderContext
|
||||
|
||||
self.frameCount = Int(self.instance.frameCount)
|
||||
self.fps = Double(self.instance.frameRate)
|
||||
}
|
||||
|
||||
func draw() -> UIImage? {
|
||||
self.instance.renderFrame(with: Int32(self.frameIndex ?? 0), into: self.renderContext.bytes.assumingMemoryBound(to: UInt8.self), width: Int32(self.renderContext.size.width * self.renderContext.scale), height: Int32(self.renderContext.size.height * self.renderContext.scale), bytesPerRow: Int32(self.renderContext.bytesPerRow))
|
||||
return self.renderContext.generateImage()
|
||||
let renderContext = DrawingContext(size: self.displaySize, scale: UIScreenScale, clear: true)
|
||||
|
||||
self.instance.renderFrame(with: Int32(self.frameIndex ?? 0), into: renderContext.bytes.assumingMemoryBound(to: UInt8.self), width: Int32(renderContext.size.width * renderContext.scale), height: Int32(renderContext.size.height * renderContext.scale), bytesPerRow: Int32(renderContext.bytesPerRow))
|
||||
return renderContext.generateImage()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -222,7 +222,7 @@ public final class FFMpegMediaVideoFrameDecoder: MediaTrackFrameDecoder {
|
||||
var srcCb = vImage_Buffer(data: frame.data[1], height: vImagePixelCount(frame.height), width: vImagePixelCount(frame.width / 2), rowBytes: Int(frame.lineSize[1]))
|
||||
var srcCr = vImage_Buffer(data: frame.data[2], height: vImagePixelCount(frame.height), width: vImagePixelCount(frame.width / 2), rowBytes: Int(frame.lineSize[2]))
|
||||
|
||||
let argbBytesPerRow = (4 * Int(frame.width) + 15) & (~15)
|
||||
let argbBytesPerRow = (4 * Int(frame.width) + 31) & (~31)
|
||||
let argbLength = argbBytesPerRow * Int(frame.height)
|
||||
let argb = malloc(argbLength)!
|
||||
guard let provider = CGDataProvider(dataInfo: argb, data: argb, size: argbLength, releaseData: { bytes, _, _ in
|
||||
|
@ -70,7 +70,7 @@ NSData * _Nullable compressJPEGData(UIImage * _Nonnull sourceImage) {
|
||||
int width = (int)(sourceImage.size.width * sourceImage.scale);
|
||||
int height = (int)(sourceImage.size.height * sourceImage.scale);
|
||||
|
||||
int targetBytesPerRow = ((4 * (int)width) + 15) & (~15);
|
||||
int targetBytesPerRow = ((4 * (int)width) + 31) & (~31);
|
||||
uint8_t *targetMemory = malloc((int)(targetBytesPerRow * height));
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
@ -86,7 +86,7 @@ NSData * _Nullable compressJPEGData(UIImage * _Nonnull sourceImage) {
|
||||
|
||||
UIGraphicsPopContext();
|
||||
|
||||
int bufferBytesPerRow = ((3 * (int)width) + 15) & (~15);
|
||||
int bufferBytesPerRow = ((3 * (int)width) + 31) & (~31);
|
||||
uint8_t *buffer = malloc(bufferBytesPerRow * height);
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
@ -158,7 +158,7 @@ NSData * _Nullable compressMiniThumbnail(UIImage * _Nonnull image, CGSize size)
|
||||
int width = (int)fittedSize.width;
|
||||
int height = (int)fittedSize.height;
|
||||
|
||||
int targetBytesPerRow = ((4 * (int)width) + 15) & (~15);
|
||||
int targetBytesPerRow = ((4 * (int)width) + 31) & (~31);
|
||||
uint8_t *targetMemory = malloc((int)(targetBytesPerRow * height));
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
@ -174,7 +174,7 @@ NSData * _Nullable compressMiniThumbnail(UIImage * _Nonnull image, CGSize size)
|
||||
|
||||
UIGraphicsPopContext();
|
||||
|
||||
int bufferBytesPerRow = ((3 * (int)width) + 15) & (~15);
|
||||
int bufferBytesPerRow = ((3 * (int)width) + 31) & (~31);
|
||||
uint8_t *buffer = malloc(bufferBytesPerRow * height);
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
|
@ -74,7 +74,7 @@ final class ImageBasedPasscodeBackground: PasscodeBackground {
|
||||
}
|
||||
telegramFastBlurMore(Int32(contextSize.width), Int32(contextSize.height), Int32(backgroundContext.bytesPerRow), backgroundContext.bytes)
|
||||
telegramFastBlurMore(Int32(contextSize.width), Int32(contextSize.height), Int32(backgroundContext.bytesPerRow), backgroundContext.bytes)
|
||||
telegramFastBlurMore(Int32(contextSize.width), Int32(contextSize.height), Int32(foregroundContext.bytesPerRow), foregroundContext.bytes)
|
||||
telegramFastBlurMore(Int32(contextSize.width), Int32(contextSize.height), Int32(foregroundContext.bytesPerRow), backgroundContext.bytes)
|
||||
|
||||
backgroundContext.withFlippedContext { context in
|
||||
context.setFillColor(UIColor(white: 0.0, alpha: 0.35).cgColor)
|
||||
|
@ -46,7 +46,7 @@ public func qrCode(string: String, color: UIColor, backgroundColor: UIColor? = n
|
||||
|
||||
if let output = filter.outputImage {
|
||||
let size = Int(output.extent.width)
|
||||
let bytesPerRow = (4 * Int(size) + 15) & (~15)
|
||||
let bytesPerRow = DeviceGraphicsContextSettings.shared.bytesPerRow(forWidth: Int(size))
|
||||
let length = bytesPerRow * size
|
||||
let bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.noneSkipFirst.rawValue)
|
||||
|
||||
|
@ -280,6 +280,7 @@ final class WallpaperPatternPanelNode: ASDisplayNode {
|
||||
if existingIds.contains(file.file.fileId) {
|
||||
return false
|
||||
} else {
|
||||
print("slug: \(file.slug)")
|
||||
existingIds.insert(file.file.fileId)
|
||||
return true
|
||||
}
|
||||
@ -352,8 +353,10 @@ final class WallpaperPatternPanelNode: ASDisplayNode {
|
||||
} ?? 80
|
||||
|
||||
var selectedFileId: Int64?
|
||||
var selectedSlug: String?
|
||||
if let currentWallpaper = self.currentWallpaper, case let .file(file) = currentWallpaper {
|
||||
selectedFileId = file.id
|
||||
selectedSlug = file.slug
|
||||
}
|
||||
|
||||
for wallpaper in self.wallpapers {
|
||||
@ -368,7 +371,7 @@ final class WallpaperPatternPanelNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
var selected = false
|
||||
if case let .file(file) = wallpaper, file.id == selectedFileId {
|
||||
if case let .file(file) = wallpaper, (file.id == selectedFileId || file.slug == selectedSlug) {
|
||||
selected = true
|
||||
}
|
||||
|
||||
|
@ -136,7 +136,7 @@ public func experimentalConvertCompressedLottieToCombinedMp4(data: Data, size: C
|
||||
return
|
||||
}
|
||||
|
||||
let bytesPerRow = (4 * Int(size.width) + 15) & (~15)
|
||||
let bytesPerRow = DeviceGraphicsContextSettings.shared.bytesPerRow(forWidth: Int(size.width))
|
||||
|
||||
var currentFrame: Int32 = 0
|
||||
|
||||
|
@ -1572,6 +1572,15 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
return
|
||||
}
|
||||
|
||||
let transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.2, curve: .easeInOut) : .immediate
|
||||
let replyAlpha: CGFloat = item.controllerInteraction.selectionState == nil ? 1.0 : 0.0
|
||||
if let replyInfoNode = self.replyInfoNode {
|
||||
transition.updateAlpha(node: replyInfoNode, alpha: replyAlpha)
|
||||
}
|
||||
if let replyBackgroundNode = self.replyBackgroundNode {
|
||||
transition.updateAlpha(node: replyBackgroundNode, alpha: replyAlpha)
|
||||
}
|
||||
|
||||
if let selectionState = item.controllerInteraction.selectionState {
|
||||
var selected = false
|
||||
var incoming = true
|
||||
|
@ -1088,6 +1088,15 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
isEmoji = true
|
||||
}
|
||||
|
||||
let transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.2, curve: .easeInOut) : .immediate
|
||||
let replyAlpha: CGFloat = item.controllerInteraction.selectionState == nil ? 1.0 : 0.0
|
||||
if let replyInfoNode = self.replyInfoNode {
|
||||
transition.updateAlpha(node: replyInfoNode, alpha: replyAlpha)
|
||||
}
|
||||
if let replyBackgroundNode = self.replyBackgroundNode {
|
||||
transition.updateAlpha(node: replyBackgroundNode, alpha: replyAlpha)
|
||||
}
|
||||
|
||||
if let selectionState = item.controllerInteraction.selectionState {
|
||||
let selected = selectionState.selectedIds.contains(item.message.id)
|
||||
|
||||
|
@ -16,7 +16,7 @@ private let motionAmount: CGFloat = 32.0
|
||||
|
||||
private func generateBlurredContents(image: UIImage) -> UIImage? {
|
||||
let size = image.size.aspectFitted(CGSize(width: 64.0, height: 64.0))
|
||||
let context = DrawingContext(size: size, scale: 1.0, premultiplied: true, opaque: true, clear: false)
|
||||
let context = DrawingContext(size: size, scale: 1.0, opaque: true, clear: false)
|
||||
context.withFlippedContext { c in
|
||||
c.draw(image.cgImage!, in: CGRect(origin: CGPoint(), size: size))
|
||||
}
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
const struct { int width, height; } targetContextSize = { width, height};
|
||||
|
||||
size_t targetBytesPerRow = ((4 * (int)targetContextSize.width) + 15) & (~15);
|
||||
size_t targetBytesPerRow = ((4 * (int)targetContextSize.width) + 31) & (~31);
|
||||
|
||||
void *targetMemory = malloc((int)(targetBytesPerRow * targetContextSize.height));
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user