Autoscale builtin pattern thumbnail

This commit is contained in:
Ali 2021-06-17 13:29:29 +04:00
parent dad3eca855
commit 01c5299c00
7 changed files with 37 additions and 19 deletions

View File

@ -121,22 +121,28 @@ public final class CachedPatternWallpaperMaskRepresentation: CachedMediaResource
public let keepDuration: CachedMediaRepresentationKeepDuration = .general public let keepDuration: CachedMediaRepresentationKeepDuration = .general
public let size: CGSize? public let size: CGSize?
public let scaleFromCenter: CGFloat?
public var uniqueId: String { public var uniqueId: String {
if let size = self.size { if let size = self.size {
return "pattern-wallpaper-mask-\(Int(size.width))x\(Int(size.height))" var result = "pattern-wallpaper-mask-\(Int(size.width))x\(Int(size.height))"
if let scaleFromCenter = self.scaleFromCenter {
result.append("-scale\(scaleFromCenter)")
}
return result
} else { } else {
return "pattern-wallpaper-mask" return "pattern-wallpaper-mask"
} }
} }
public init(size: CGSize?) { public init(size: CGSize?, scaleFromCenter: CGFloat?) {
self.size = size self.size = size
self.scaleFromCenter = scaleFromCenter
} }
public func isEqual(to: CachedMediaResourceRepresentation) -> Bool { public func isEqual(to: CachedMediaResourceRepresentation) -> Bool {
if let to = to as? CachedPatternWallpaperMaskRepresentation { if let to = to as? CachedPatternWallpaperMaskRepresentation {
return self.size == to.size return self.size == to.size && self.scaleFromCenter == to.scaleFromCenter
} else { } else {
return false return false
} }

View File

@ -412,6 +412,10 @@ final class ThemeGridControllerNode: ASDisplayNode {
} }
} }
/*if !entries.isEmpty {
entries = [entries[0]]
}*/
let previous = previousEntries.swap(entries) let previous = previousEntries.swap(entries)
return (preparedThemeGridEntryTransition(context: context, from: previous ?? [], to: entries, interaction: interaction), previous == nil) return (preparedThemeGridEntryTransition(context: context, from: previous ?? [], to: entries, interaction: interaction), previous == nil)
} }

View File

@ -851,7 +851,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
let dimensions = file.file.dimensions ?? PixelDimensions(width: 1440, height: 2960) let dimensions = file.file.dimensions ?? PixelDimensions(width: 1440, height: 2960)
let size = dimensions.cgSize.fitted(CGSize(width: 1280.0, height: 1280.0)) let size = dimensions.cgSize.fitted(CGSize(width: 1280.0, height: 1280.0))
let _ = self.context.account.postbox.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedPatternWallpaperMaskRepresentation(size: size), complete: false, fetch: true).start() let _ = self.context.account.postbox.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedPatternWallpaperMaskRepresentation(size: size, scaleFromCenter: nil), complete: false, fetch: true).start()
} }
} }

View File

@ -4,6 +4,6 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
UIImage * _Nullable drawSvgImage(NSData * _Nonnull data, CGSize size, UIColor *backgroundColor, UIColor *foregroundColor); UIImage * _Nullable drawSvgImage(NSData * _Nonnull data, CGSize size, UIColor *backgroundColor, UIColor *foregroundColor, CGFloat scaleFromCenter);
#endif /* Lottie_h */ #endif /* Lottie_h */

View File

@ -83,7 +83,7 @@ CGSize aspectFillSize(CGSize size, CGSize bounds) {
@end @end
UIImage * _Nullable drawSvgImage(NSData * _Nonnull data, CGSize size, UIColor *backgroundColor, UIColor *foregroundColor) { UIImage * _Nullable drawSvgImage(NSData * _Nonnull data, CGSize size, UIColor *backgroundColor, UIColor *foregroundColor, CGFloat scaleFromCenter) {
NSDate *startTime = [NSDate date]; NSDate *startTime = [NSDate date];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data]; NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
@ -104,9 +104,9 @@ UIImage * _Nullable drawSvgImage(NSData * _Nonnull data, CGSize size, UIColor *b
[xmlString replaceOccurrencesOfString:[NSString stringWithFormat:@"class=\"%@\"", styleName] withString:[NSString stringWithFormat:@"style=\"%@\"", styleValue] options:0 range:NSMakeRange(0, xmlString.length)]; [xmlString replaceOccurrencesOfString:[NSString stringWithFormat:@"class=\"%@\"", styleName] withString:[NSString stringWithFormat:@"style=\"%@\"", styleValue] options:0 range:NSMakeRange(0, xmlString.length)];
} }
char *zeroTerminatedData = xmlString.UTF8String; const char *zeroTerminatedData = xmlString.UTF8String;
NSVGimage *image = nsvgParse(zeroTerminatedData, "px", 96); NSVGimage *image = nsvgParse((char *)zeroTerminatedData, "px", 96);
if (image == nil || image->width < 1.0f || image->height < 1.0f) { if (image == nil || image->width < 1.0f || image->height < 1.0f) {
return nil; return nil;
} }
@ -129,13 +129,16 @@ UIImage * _Nullable drawSvgImage(NSData * _Nonnull data, CGSize size, UIColor *b
CGContextScaleCTM(context, scale, scale); CGContextScaleCTM(context, scale, scale);
CGContextTranslateCTM(context, (size.width - drawingSize.width) / 2.0, (size.height - drawingSize.height) / 2.0); CGContextTranslateCTM(context, (size.width - drawingSize.width) / 2.0, (size.height - drawingSize.height) / 2.0);
CGContextTranslateCTM(context, size.width / 2.0f, size.height / 2.0f);
CGContextScaleCTM(context, scaleFromCenter, scaleFromCenter);
CGContextTranslateCTM(context, -size.width / 2.0f, -size.height / 2.0f);
for (NSVGshape *shape = image->shapes; shape != NULL; shape = shape->next) { for (NSVGshape *shape = image->shapes; shape != NULL; shape = shape->next) {
if (!(shape->flags & NSVG_FLAGS_VISIBLE)) { if (!(shape->flags & NSVG_FLAGS_VISIBLE)) {
continue; continue;
} }
if (shape->fill.type != NSVG_PAINT_NONE) { if (shape->fill.type != NSVG_PAINT_NONE) {
//CGContextSetFillColorWithColor(context, UIColorRGBA(shape->fill.color, shape->opacity).CGColor);
CGContextSetFillColorWithColor(context, [foregroundColor colorWithAlphaComponent:shape->opacity].CGColor); CGContextSetFillColorWithColor(context, [foregroundColor colorWithAlphaComponent:shape->opacity].CGColor);
bool isFirst = true; bool isFirst = true;
@ -173,7 +176,6 @@ UIImage * _Nullable drawSvgImage(NSData * _Nonnull data, CGSize size, UIColor *b
} }
if (shape->stroke.type != NSVG_PAINT_NONE) { if (shape->stroke.type != NSVG_PAINT_NONE) {
//CGContextSetStrokeColorWithColor(context, UIColorRGBA(shape->fill.color, shape->opacity).CGColor);
CGContextSetStrokeColorWithColor(context, [foregroundColor colorWithAlphaComponent:shape->opacity].CGColor); CGContextSetStrokeColorWithColor(context, [foregroundColor colorWithAlphaComponent:shape->opacity].CGColor);
CGContextSetMiterLimit(context, shape->miterLimit); CGContextSetMiterLimit(context, shape->miterLimit);
@ -196,10 +198,10 @@ UIImage * _Nullable drawSvgImage(NSData * _Nonnull data, CGSize size, UIColor *b
CGContextSetLineJoin(context, kCGLineJoinBevel); CGContextSetLineJoin(context, kCGLineJoinBevel);
break; break;
case NSVG_JOIN_MITER: case NSVG_JOIN_MITER:
CGContextSetLineCap(context, kCGLineJoinMiter); CGContextSetLineJoin(context, kCGLineJoinMiter);
break; break;
case NSVG_JOIN_ROUND: case NSVG_JOIN_ROUND:
CGContextSetLineCap(context, kCGLineJoinRound); CGContextSetLineJoin(context, kCGLineJoinRound);
break; break;
default: default:
break; break;

View File

@ -424,7 +424,7 @@ private func fetchCachedPatternWallpaperMaskRepresentation(resource: MediaResour
if data.count > 5, let string = String(data: data.subdata(in: 0 ..< 5), encoding: .utf8), string == "<?xml" { if data.count > 5, let string = String(data: data.subdata(in: 0 ..< 5), encoding: .utf8), string == "<?xml" {
let size = representation.size ?? CGSize(width: 1440.0, height: 2960.0) let size = representation.size ?? CGSize(width: 1440.0, height: 2960.0)
if let image = drawSvgImage(data, size, .black, .white) { if let image = drawSvgImage(data, size, .black, .white, representation.scaleFromCenter ?? 1.0) {
if let alphaDestination = CGImageDestinationCreateWithURL(url as CFURL, kUTTypeJPEG, 1, nil) { if let alphaDestination = CGImageDestinationCreateWithURL(url as CFURL, kUTTypeJPEG, 1, nil) {
CGImageDestinationSetProperties(alphaDestination, [:] as CFDictionary) CGImageDestinationSetProperties(alphaDestination, [:] as CFDictionary)
@ -490,7 +490,7 @@ private func fetchCachedPatternWallpaperRepresentation(resource: MediaResource,
if data.count > 5, let string = String(data: data.subdata(in: 0 ..< 5), encoding: .utf8), string == "<?xml" { if data.count > 5, let string = String(data: data.subdata(in: 0 ..< 5), encoding: .utf8), string == "<?xml" {
let defaultSize = CGSize(width: 1440.0, height: 2960.0) let defaultSize = CGSize(width: 1440.0, height: 2960.0)
size = defaultSize size = defaultSize
if let image = drawSvgImage(data, defaultSize, .black, .white) { if let image = drawSvgImage(data, defaultSize, .black, .white, 1.0) {
maskImage = image maskImage = image
} }
} else if let image = UIImage(data: data) { } else if let image = UIImage(data: data) {

View File

@ -362,13 +362,18 @@ private func patternWallpaperDatas(account: Account, accountManager: AccountMana
if let smallestRepresentation = smallestImageRepresentation(representations.map({ $0.representation })), let largestRepresentation = largestImageRepresentation(representations.map({ $0.representation })), let smallestIndex = representations.firstIndex(where: { $0.representation == smallestRepresentation }), let largestIndex = representations.firstIndex(where: { $0.representation == largestRepresentation }) { if let smallestRepresentation = smallestImageRepresentation(representations.map({ $0.representation })), let largestRepresentation = largestImageRepresentation(representations.map({ $0.representation })), let smallestIndex = representations.firstIndex(where: { $0.representation == smallestRepresentation }), let largestIndex = representations.firstIndex(where: { $0.representation == largestRepresentation }) {
let size: CGSize? let size: CGSize?
var scaleFromCenter: CGFloat?
switch mode { switch mode {
case .thumbnail: case .thumbnail:
size = largestRepresentation.dimensions.cgSize.fitted(CGSize(width: 640.0, height: 640.0)) size = largestRepresentation.dimensions.cgSize.fitted(CGSize(width: 640.0, height: 640.0))
let factor = smallestRepresentation.dimensions.cgSize.width / largestRepresentation.dimensions.cgSize.width
if smallestRepresentation.dimensions.height >= 700 && abs(factor - 1.0) <= .ulpOfOne {
scaleFromCenter = 2.1
}
default: default:
size = nil size = nil
} }
let maybeFullSize = combineLatest(accountManager.mediaBox.cachedResourceRepresentation(largestRepresentation.resource, representation: CachedPatternWallpaperMaskRepresentation(size: size), complete: false, fetch: false), account.postbox.mediaBox.cachedResourceRepresentation(largestRepresentation.resource, representation: CachedPatternWallpaperMaskRepresentation(size: size), complete: false, fetch: false)) let maybeFullSize = combineLatest(accountManager.mediaBox.cachedResourceRepresentation(largestRepresentation.resource, representation: CachedPatternWallpaperMaskRepresentation(size: size, scaleFromCenter: scaleFromCenter), complete: false, fetch: false), account.postbox.mediaBox.cachedResourceRepresentation(largestRepresentation.resource, representation: CachedPatternWallpaperMaskRepresentation(size: size, scaleFromCenter: scaleFromCenter), complete: false, fetch: false))
let signal = maybeFullSize let signal = maybeFullSize
|> take(1) |> take(1)
@ -388,12 +393,12 @@ private func patternWallpaperDatas(account: Account, accountManager: AccountMana
let thumbnailData = Signal<Data?, NoError> { subscriber in let thumbnailData = Signal<Data?, NoError> { subscriber in
let fetchedDisposable = fetchedThumbnail.start() let fetchedDisposable = fetchedThumbnail.start()
let thumbnailDisposable = account.postbox.mediaBox.cachedResourceRepresentation(representations[smallestIndex].representation.resource, representation: CachedPatternWallpaperMaskRepresentation(size: size), complete: false, fetch: true).start(next: { next in let thumbnailDisposable = account.postbox.mediaBox.cachedResourceRepresentation(representations[smallestIndex].representation.resource, representation: CachedPatternWallpaperMaskRepresentation(size: size, scaleFromCenter: scaleFromCenter), complete: false, fetch: true).start(next: { next in
subscriber.putNext(next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: [])) subscriber.putNext(next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: []))
if next.complete, let data = try? Data(contentsOf: URL(fileURLWithPath: next.path), options: .mappedRead) { if next.complete, let data = try? Data(contentsOf: URL(fileURLWithPath: next.path), options: .mappedRead) {
accountManager.mediaBox.storeResourceData(representations[smallestIndex].representation.resource.id, data: data) accountManager.mediaBox.storeResourceData(representations[smallestIndex].representation.resource.id, data: data)
let _ = accountManager.mediaBox.cachedResourceRepresentation(representations[smallestIndex].representation.resource, representation: CachedPatternWallpaperMaskRepresentation(size: size), complete: false, fetch: true).start() let _ = accountManager.mediaBox.cachedResourceRepresentation(representations[smallestIndex].representation.resource, representation: CachedPatternWallpaperMaskRepresentation(size: size, scaleFromCenter: scaleFromCenter), complete: false, fetch: true).start()
} }
}, error: subscriber.putError, completed: subscriber.putCompletion) }, error: subscriber.putError, completed: subscriber.putCompletion)
@ -405,12 +410,12 @@ private func patternWallpaperDatas(account: Account, accountManager: AccountMana
let fullSizeData = Signal<(Data?, Bool), NoError> { subscriber in let fullSizeData = Signal<(Data?, Bool), NoError> { subscriber in
let fetchedFullSizeDisposable = fetchedFullSize.start() let fetchedFullSizeDisposable = fetchedFullSize.start()
let fullSizeDisposable = account.postbox.mediaBox.cachedResourceRepresentation(representations[largestIndex].representation.resource, representation: CachedPatternWallpaperMaskRepresentation(size: size), complete: false, fetch: true).start(next: { next in let fullSizeDisposable = account.postbox.mediaBox.cachedResourceRepresentation(representations[largestIndex].representation.resource, representation: CachedPatternWallpaperMaskRepresentation(size: size, scaleFromCenter: scaleFromCenter), complete: false, fetch: true).start(next: { next in
subscriber.putNext((next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: []), next.complete)) subscriber.putNext((next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: []), next.complete))
if next.complete, let data = try? Data(contentsOf: URL(fileURLWithPath: next.path), options: .mappedRead) { if next.complete, let data = try? Data(contentsOf: URL(fileURLWithPath: next.path), options: .mappedRead) {
accountManager.mediaBox.storeResourceData(representations[largestIndex].representation.resource.id, data: data) accountManager.mediaBox.storeResourceData(representations[largestIndex].representation.resource.id, data: data)
let _ = accountManager.mediaBox.cachedResourceRepresentation(representations[largestIndex].representation.resource, representation: CachedPatternWallpaperMaskRepresentation(size: size), complete: false, fetch: true).start() let _ = accountManager.mediaBox.cachedResourceRepresentation(representations[largestIndex].representation.resource, representation: CachedPatternWallpaperMaskRepresentation(size: size, scaleFromCenter: scaleFromCenter), complete: false, fetch: true).start()
} }
}, error: subscriber.putError, completed: subscriber.putCompletion) }, error: subscriber.putError, completed: subscriber.putCompletion)
@ -535,6 +540,7 @@ public func patternWallpaperImageInternal(thumbnailData: Data?, fullSizeData: Da
let overlayImage = generateImage(arguments.drawingRect.size, rotatedContext: { size, c in let overlayImage = generateImage(arguments.drawingRect.size, rotatedContext: { size, c in
c.clear(CGRect(origin: CGPoint(), size: size)) c.clear(CGRect(origin: CGPoint(), size: size))
let image = customArguments.preview ? (scaledSizeImage ?? fullSizeImage) : fullSizeImage let image = customArguments.preview ? (scaledSizeImage ?? fullSizeImage) : fullSizeImage
if let image = image { if let image = image {
var fittedSize = CGSize(width: image.width, height: image.height) var fittedSize = CGSize(width: image.width, height: image.height)
if abs(fittedSize.width - arguments.boundingSize.width).isLessThanOrEqualTo(CGFloat(1.0)) { if abs(fittedSize.width - arguments.boundingSize.width).isLessThanOrEqualTo(CGFloat(1.0)) {