mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2026-01-17 01:41:09 +00:00
Merge commit '33dd02f7a98f863c7bb6e3667b7014fe87918872'
This commit is contained in:
@@ -8,6 +8,9 @@
|
||||
|
||||
#import "TGPeerIdAdapter.h"
|
||||
|
||||
#import "TGImageInfo.h"
|
||||
#import "TGMediaOriginInfo.h"
|
||||
|
||||
@implementation TGEncryptedConversationData
|
||||
|
||||
- (BOOL)isEqualToEncryptedData:(TGEncryptedConversationData *)other
|
||||
@@ -1370,10 +1373,19 @@
|
||||
if (finalAvatarUrl.length == 0)
|
||||
return finalAvatarUrl;
|
||||
|
||||
if (self.chatPhotoFileReferenceSmall != nil)
|
||||
finalAvatarUrl = [finalAvatarUrl stringByAppendingFormat:@"_%@", [self.chatPhotoFileReferenceSmall stringByEncodingInHex]];
|
||||
else
|
||||
NSLog(@"");
|
||||
int64_t volumeId = 0;
|
||||
int32_t localId = 0;
|
||||
if (extractFileUrlComponents(self.chatPhotoSmall, NULL, &volumeId, &localId, NULL))
|
||||
{
|
||||
NSString *key = [NSString stringWithFormat:@"%lld_%d", volumeId, localId];
|
||||
NSDictionary *fileReferences = nil;
|
||||
if (self.chatPhotoFileReferenceSmall != nil) {
|
||||
fileReferences = @{ key: self.chatPhotoFileReferenceSmall };
|
||||
}
|
||||
TGMediaOriginInfo *originInfo = [TGMediaOriginInfo mediaOriginInfoWithFileReference:self.chatPhotoFileReferenceSmall fileReferences:fileReferences peerId:_conversationId];
|
||||
finalAvatarUrl = [finalAvatarUrl stringByAppendingFormat:@"_o%@", [originInfo stringRepresentation]];
|
||||
}
|
||||
|
||||
return finalAvatarUrl;
|
||||
}
|
||||
|
||||
@@ -1383,8 +1395,18 @@
|
||||
if (finalAvatarUrl.length == 0)
|
||||
return finalAvatarUrl;
|
||||
|
||||
if (self.chatPhotoFileReferenceBig != nil)
|
||||
finalAvatarUrl = [finalAvatarUrl stringByAppendingFormat:@"_%@", [self.chatPhotoFileReferenceBig stringByEncodingInHex]];
|
||||
int64_t volumeId = 0;
|
||||
int32_t localId = 0;
|
||||
if (extractFileUrlComponents(self.chatPhotoBig, NULL, &volumeId, &localId, NULL))
|
||||
{
|
||||
NSString *key = [NSString stringWithFormat:@"%lld_%d", volumeId, localId];
|
||||
NSDictionary *fileReferences = nil;
|
||||
if (self.chatPhotoFileReferenceBig != nil) {
|
||||
fileReferences = @{ key: self.chatPhotoFileReferenceBig };
|
||||
}
|
||||
TGMediaOriginInfo *originInfo = [TGMediaOriginInfo mediaOriginInfoWithFileReference:self.chatPhotoFileReferenceBig fileReferences:fileReferences peerId:_conversationId];
|
||||
finalAvatarUrl = [finalAvatarUrl stringByAppendingFormat:@"_o%@", [originInfo stringRepresentation]];
|
||||
}
|
||||
|
||||
return finalAvatarUrl;
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
|
||||
CGContextDrawLinearGradient(context, gradient, CGPointMake(0.0f, 0.0f), CGPointMake(0.0f, _size.height), 0);
|
||||
CGGradientRelease(gradient);
|
||||
|
||||
_backgroundImage = [UIGraphicsGetImageFromCurrentImageContext() resizableImageWithCapInsets:UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f) resizingMode:UIImageResizingModeTile];
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
@@ -115,7 +115,7 @@ NSString *const TGVinePlayerCallbackOnPlayback = @"onPlayback";
|
||||
[self _didBeginPlayback];
|
||||
}
|
||||
}
|
||||
else if ([action isEqualToString:@"onSrc"])
|
||||
else if ([action isEqualToString:@"onSrc"] && data != nil)
|
||||
{
|
||||
[self _setupCustomPlayerWithURL:[NSURL URLWithString:data]];
|
||||
}
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool extractFileUrlComponents(NSString *fileUrl, int *datacenterId, int64_t *volumeId, int *localId, int64_t *secret);
|
||||
bool extractFileUrlComponentsWithFileRef(NSString *fileUrl, int *datacenterId, int64_t *volumeId, int *localId, int64_t *secret, NSString **fileReferenceStr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@interface TGImageInfo : NSObject <NSCoding>
|
||||
|
||||
- (void)addImageWithSize:(CGSize)size url:(NSString *)url;
|
||||
|
||||
@@ -370,3 +370,64 @@ struct TGImageSizeRecord
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
bool extractFileUrlComponents(NSString *fileUrl, int *datacenterId, int64_t *volumeId, int *localId, int64_t *secret)
|
||||
{
|
||||
return extractFileUrlComponentsWithFileRef(fileUrl, datacenterId, volumeId, localId, secret, NULL);
|
||||
}
|
||||
|
||||
bool extractFileUrlComponentsWithFileRef(NSString *fileUrl, int *datacenterId, int64_t *volumeId, int *localId, int64_t *secret, NSString **fileReferenceStr)
|
||||
{
|
||||
if (fileUrl == nil || fileUrl.length == 0)
|
||||
return false;
|
||||
|
||||
NSRange datacenterIdRange = NSMakeRange(NSNotFound, 0);
|
||||
NSRange volumeIdRange = NSMakeRange(NSNotFound, 0);
|
||||
NSRange localIdRange = NSMakeRange(NSNotFound, 0);
|
||||
NSRange secretRange = NSMakeRange(NSNotFound, 0);
|
||||
NSRange fileReferenceRange = NSMakeRange(NSNotFound, 0);
|
||||
|
||||
int length = (int)fileUrl.length;
|
||||
for (int i = 0; i <= length; i++)
|
||||
{
|
||||
if (i == length)
|
||||
{
|
||||
if (secretRange.location == NSNotFound) {
|
||||
secretRange = NSMakeRange(localIdRange.location + localIdRange.length + 1, i - (localIdRange.location + localIdRange.length + 1));
|
||||
} else if (fileReferenceRange.location == NSNotFound) {
|
||||
fileReferenceRange = NSMakeRange(secretRange.location + secretRange.length + 1, i - (secretRange.location + secretRange.length + 1));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
unichar c = [fileUrl characterAtIndex:i];
|
||||
if (c == '_')
|
||||
{
|
||||
if (datacenterIdRange.location == NSNotFound)
|
||||
datacenterIdRange = NSMakeRange(0, i);
|
||||
else if (volumeIdRange.location == NSNotFound)
|
||||
volumeIdRange = NSMakeRange(datacenterIdRange.location + datacenterIdRange.length + 1, i - (datacenterIdRange.location + datacenterIdRange.length + 1));
|
||||
else if (localIdRange.location == NSNotFound)
|
||||
localIdRange = NSMakeRange(volumeIdRange.location + volumeIdRange.length + 1, i - (volumeIdRange.location + volumeIdRange.length + 1));
|
||||
else if (secretRange.location == NSNotFound)
|
||||
secretRange = NSMakeRange(localIdRange.location + localIdRange.length + 1, i - (localIdRange.location + localIdRange.length + 1));
|
||||
}
|
||||
}
|
||||
|
||||
if (datacenterIdRange.location == NSNotFound || volumeIdRange.location == NSNotFound || localIdRange.location == NSNotFound || secretRange.location == NSNotFound)
|
||||
return false;
|
||||
|
||||
if (datacenterId != NULL)
|
||||
*datacenterId = [[fileUrl substringWithRange:datacenterIdRange] intValue];
|
||||
if (volumeId != NULL)
|
||||
*volumeId = [[fileUrl substringWithRange:volumeIdRange] longLongValue];
|
||||
if (localId != NULL)
|
||||
*localId = [[fileUrl substringWithRange:localIdRange] intValue];
|
||||
if (secret != NULL)
|
||||
*secret = [[fileUrl substringWithRange:secretRange] longLongValue];
|
||||
if (fileReferenceStr != NULL && fileReferenceRange.location != NSNotFound)
|
||||
*fileReferenceStr = [fileUrl substringWithRange:fileReferenceRange];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
- (TGLocalization *)mergedWith:(NSDictionary<NSString *, NSString *> *)other version:(int32_t)version;
|
||||
|
||||
- (TGLocalization *)withUpdatedIsActive:(bool)isActive;
|
||||
|
||||
|
||||
- (NSLocale *)locale;
|
||||
|
||||
- (NSString *)get:(NSString *)key;
|
||||
- (NSString *)getPluralized:(NSString *)key count:(int32_t)count;
|
||||
- (bool)contains:(NSString *)key;
|
||||
|
||||
@@ -112,6 +112,18 @@ static NSString *fallbackString(NSString *key, NSString *code) {
|
||||
- (TGLocalization *)withUpdatedIsActive:(bool)isActive {
|
||||
return [[TGLocalization alloc] initWithVersion:_version code:_code dict:_dict isActive:isActive];
|
||||
}
|
||||
|
||||
- (NSLocale *)locale
|
||||
{
|
||||
NSString *suffix = @"";
|
||||
NSString *identifier = [[NSLocale currentLocale] localeIdentifier];
|
||||
NSRange range = [identifier rangeOfString:@"_"];
|
||||
if (range.location != NSNotFound)
|
||||
suffix = [identifier substringFromIndex:range.location];
|
||||
|
||||
identifier = [_code stringByAppendingString:suffix];
|
||||
return [NSLocale localeWithLocaleIdentifier:identifier];
|
||||
}
|
||||
|
||||
- (NSString *)get:(NSString *)key {
|
||||
if (key == nil) {
|
||||
|
||||
@@ -21,6 +21,7 @@ typedef enum
|
||||
TGMediaAssetSubtypePhotoHDR = (1UL << 1),
|
||||
TGMediaAssetSubtypePhotoScreenshot = (1UL << 2),
|
||||
TGMediaAssetSubtypePhotoLive = (1UL << 3),
|
||||
TGMediaAssetSubtypePhotoDepthEffect = (1UL << 4),
|
||||
TGMediaAssetSubtypeVideoStreamed = (1UL << 16),
|
||||
TGMediaAssetSubtypeVideoHighFrameRate = (1UL << 17),
|
||||
TGMediaAssetSubtypeVideoTimelapse = (1UL << 18)
|
||||
|
||||
@@ -198,7 +198,7 @@
|
||||
if (!self.isVideo)
|
||||
return [SSignal fail:nil];
|
||||
|
||||
if (!_cachedDuration)
|
||||
if (_cachedDuration == nil)
|
||||
{
|
||||
return [[TGMediaAssetImageSignals avAssetForVideoAsset:self] map:^id(AVAsset *asset)
|
||||
{
|
||||
@@ -277,6 +277,9 @@
|
||||
if (subtypes & PHAssetMediaSubtypePhotoLive)
|
||||
result |= TGMediaAssetSubtypePhotoLive;
|
||||
|
||||
if (subtypes & PHAssetMediaSubtypePhotoDepthEffect)
|
||||
result |= TGMediaAssetSubtypePhotoDepthEffect;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,9 @@
|
||||
{
|
||||
CGSize imageSize = size;
|
||||
if (imageType == TGMediaAssetImageTypeFullSize)
|
||||
imageSize = PHImageManagerMaximumSize;
|
||||
{
|
||||
imageSize = asset.dimensions;
|
||||
}
|
||||
|
||||
bool isScreenImage = (imageType == TGMediaAssetImageTypeScreen || imageType == TGMediaAssetImageTypeFastScreen);
|
||||
|
||||
@@ -358,7 +360,7 @@
|
||||
CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, (__bridge CFDictionaryRef)options);
|
||||
if (imageProperties != NULL)
|
||||
{
|
||||
NSDictionary *metadata = (__bridge NSDictionary *)imageProperties;
|
||||
NSDictionary *metadata = (__bridge_transfer NSDictionary *)imageProperties;
|
||||
CFRelease(imageProperties);
|
||||
CFRelease(imageSource);
|
||||
return metadata;
|
||||
@@ -561,7 +563,7 @@
|
||||
|
||||
case TGMediaAssetImageTypeFullSize:
|
||||
options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
|
||||
options.resizeMode = PHImageRequestOptionsResizeModeNone;
|
||||
options.resizeMode = PHImageRequestOptionsResizeModeExact;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -857,7 +859,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
if (asset != nil)
|
||||
if (asset != nil && livePhoto != nil)
|
||||
{
|
||||
NSArray *assetResources = [PHAssetResource assetResourcesForLivePhoto:livePhoto];
|
||||
PHAssetResource *videoResource = nil;
|
||||
|
||||
@@ -44,6 +44,7 @@ typedef enum
|
||||
@property (nonatomic, strong) TGMediaAssetsPallete *pallete;
|
||||
|
||||
@property (nonatomic, readonly) TGMediaEditingContext *editingContext;
|
||||
@property (nonatomic, readonly) TGMediaSelectionContext *selectionContext;
|
||||
@property (nonatomic, strong) TGSuggestionContext *suggestionContext;
|
||||
@property (nonatomic, assign) bool localMediaCacheEnabled;
|
||||
@property (nonatomic, assign) bool captionsEnabled;
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
TGMediaAssetsControllerIntent _intent;
|
||||
|
||||
TGMediaPickerToolbarView *_toolbarView;
|
||||
TGMediaSelectionContext *_selectionContext;
|
||||
|
||||
SMetaDisposable *_groupingChangedDisposable;
|
||||
SMetaDisposable *_selectionChangedDisposable;
|
||||
@@ -360,7 +359,7 @@
|
||||
_toolbarView.pallete = _pallete;
|
||||
_toolbarView.safeAreaInset = [TGViewController safeAreaInsetForOrientation:self.interfaceOrientation];
|
||||
_toolbarView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
|
||||
if ((_intent != TGMediaAssetsControllerSendFileIntent && _intent != TGMediaAssetsControllerSendMediaIntent) || _selectionContext == nil)
|
||||
if ((_intent != TGMediaAssetsControllerSendFileIntent && _intent != TGMediaAssetsControllerSendMediaIntent && _intent != TGMediaAssetsControllerPassportMultipleIntent) || _selectionContext == nil)
|
||||
[_toolbarView setRightButtonHidden:true];
|
||||
if (_selectionContext.allowGrouping)
|
||||
{
|
||||
|
||||
@@ -10,7 +10,11 @@ typedef enum {
|
||||
TGMediaOriginTypeRecentGif,
|
||||
TGMediaOriginTypeProfilePhoto,
|
||||
TGMediaOriginTypeWebpage,
|
||||
TGMediaOriginTypeWallpaper
|
||||
TGMediaOriginTypeWallpaper,
|
||||
TGMediaOriginTypeFavoriteSticker,
|
||||
TGMediaOriginTypeRecentMask,
|
||||
TGMediaOriginTypeChatPhoto,
|
||||
TGMediaOriginTypeRemoteSticker
|
||||
} TGMediaOriginType;
|
||||
|
||||
@interface TGMediaOriginInfo : NSObject <NSCoding>
|
||||
@@ -29,10 +33,14 @@ typedef enum {
|
||||
@property (nonatomic, readonly, strong) NSNumber *profilePhotoUserId;
|
||||
@property (nonatomic, readonly, strong) NSNumber *profilePhotoOffset;
|
||||
|
||||
@property (nonatomic, readonly, strong) NSNumber *chatPhotoPeerId;
|
||||
|
||||
@property (nonatomic, readonly, strong) NSString *webpageUrl;
|
||||
|
||||
@property (nonatomic, readonly, strong) NSNumber *wallpaperId;
|
||||
|
||||
@property (nonatomic, readonly, strong) NSString *remoteStickerEmoji;
|
||||
|
||||
- (NSData *)fileReferenceForVolumeId:(int64_t)volumeId localId:(int32_t)localId;
|
||||
- (NSData *)fileReferenceForDocumentId:(int64_t)documentId accessHash:(int64_t)accessHash;
|
||||
- (NSString *)key;
|
||||
@@ -44,11 +52,14 @@ typedef enum {
|
||||
+ (instancetype)mediaOriginInfoWithFileReference:(NSData *)fileReference fileReferences:(NSDictionary *)fileReferences cid:(int64_t)cid mid:(int32_t)mid;
|
||||
+ (instancetype)mediaOriginInfoWithFileReference:(NSData *)fileReference fileReferences:(NSDictionary *)fileReferences stickerPackId:(int64_t)packId accessHash:(int64_t)accessHash;
|
||||
+ (instancetype)mediaOriginInfoForRecentStickerWithFileReference:(NSData *)fileReference fileReferences:(NSDictionary *)fileReferences;
|
||||
+ (instancetype)mediaOriginInfoForFavoriteStickerWithFileReference:(NSData *)fileReference fileReferences:(NSDictionary *)fileReferences;
|
||||
+ (instancetype)mediaOriginInfoForRecentGifWithFileReference:(NSData *)fileReference fileReferences:(NSDictionary *)fileReferences;
|
||||
+ (instancetype)mediaOriginInfoForRecentMaskWithFileReference:(NSData *)fileReference fileReferences:(NSDictionary *)fileReferences;
|
||||
+ (instancetype)mediaOriginInfoWithFileReference:(NSData *)fileReference fileReferences:(NSDictionary *)fileReferences userId:(int32_t)userId offset:(int32_t)offset;
|
||||
+ (instancetype)mediaOriginInfoWithFileReference:(NSData *)fileReference fileReferences:(NSDictionary *)fileReferences url:(NSString *)url;
|
||||
|
||||
+ (instancetype)mediaOriginInfoWithFileReference:(NSData *)fileReference fileReferences:(NSDictionary *)fileReferences peerId:(int64_t)peerId;
|
||||
+ (instancetype)mediaOriginInfoWithFileReferences:(NSDictionary *)fileReferences wallpaperId:(int32_t)wallpaperId;
|
||||
+ (instancetype)mediaOriginInfoWithFileReference:(NSData *)fileReference fileReferences:(NSDictionary *)fileReferences emoji:(NSString *)emoji;
|
||||
|
||||
+ (instancetype)mediaOriginInfoForDocumentAttachment:(TGDocumentMediaAttachment *)document;
|
||||
|
||||
|
||||
@@ -24,9 +24,13 @@
|
||||
_profilePhotoUserId = [aDecoder decodeObjectForKey:@"pi"];
|
||||
_profilePhotoOffset = [aDecoder decodeObjectForKey:@"po"];
|
||||
|
||||
_chatPhotoPeerId = [aDecoder decodeObjectForKey:@"cp"];
|
||||
|
||||
_webpageUrl = [aDecoder decodeObjectForKey:@"wu"];
|
||||
|
||||
_wallpaperId = [aDecoder decodeObjectForKey:@"wi"];
|
||||
|
||||
_remoteStickerEmoji = [aDecoder decodeObjectForKey:@"re"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -46,9 +50,13 @@
|
||||
[aCoder encodeObject:_profilePhotoUserId forKey:@"pi"];
|
||||
[aCoder encodeObject:_profilePhotoOffset forKey:@"po"];
|
||||
|
||||
[aCoder encodeObject:_chatPhotoPeerId forKey:@"cp"];
|
||||
|
||||
[aCoder encodeObject:_webpageUrl forKey:@"wu"];
|
||||
|
||||
[aCoder encodeObject:_wallpaperId forKey:@"wi"];
|
||||
|
||||
[aCoder encodeObject:_remoteStickerEmoji forKey:@"re"];
|
||||
}
|
||||
|
||||
- (NSData *)fileReferenceForVolumeId:(int64_t)volumeId localId:(int32_t)localId
|
||||
@@ -77,6 +85,12 @@
|
||||
case TGMediaOriginTypeUndefined:
|
||||
case TGMediaOriginTypeRecentSticker:
|
||||
case TGMediaOriginTypeRecentGif:
|
||||
case TGMediaOriginTypeFavoriteSticker:
|
||||
case TGMediaOriginTypeRecentMask:
|
||||
break;
|
||||
|
||||
case TGMediaOriginTypeRemoteSticker:
|
||||
info->_remoteStickerEmoji = keyComponents[1];
|
||||
break;
|
||||
|
||||
case TGMediaOriginTypeMessage:
|
||||
@@ -94,8 +108,15 @@
|
||||
info->_profilePhotoOffset = @([keyComponents[2] integerValue]);
|
||||
break;
|
||||
|
||||
case TGMediaOriginTypeChatPhoto:
|
||||
info->_chatPhotoPeerId = @([keyComponents[1] integerValue]);
|
||||
break;
|
||||
|
||||
case TGMediaOriginTypeWebpage:
|
||||
info->_webpageUrl = keyComponents[1];
|
||||
{
|
||||
NSString *url = (__bridge_transfer NSString *)CFURLCreateStringByReplacingPercentEscapesUsingEncoding(NULL, (CFStringRef)keyComponents[1], CFSTR(""), kCFStringEncodingUTF8);
|
||||
info->_webpageUrl = url;
|
||||
}
|
||||
break;
|
||||
|
||||
case TGMediaOriginTypeWallpaper:
|
||||
@@ -105,11 +126,11 @@
|
||||
default:
|
||||
return nil;
|
||||
}
|
||||
if ([components[1] length] > 0)
|
||||
if (components.count > 1 && [components[1] length] > 0)
|
||||
info->_fileReference = [NSData dataWithHexString:components[1]];
|
||||
|
||||
NSMutableDictionary *fileReferences = [[NSMutableDictionary alloc] init];
|
||||
if ([components[2] length] > 0)
|
||||
if (components.count > 2 && [components[2] length] > 0)
|
||||
{
|
||||
NSArray *refComponents = [components[2] componentsSeparatedByString:@","];
|
||||
for (NSString *ref in refComponents)
|
||||
@@ -156,14 +177,25 @@
|
||||
return [NSString stringWithFormat:@"%d|%@|%@", _type, _stickerPackId, _stickerPackAccessHash];
|
||||
|
||||
case TGMediaOriginTypeRecentSticker:
|
||||
case TGMediaOriginTypeFavoriteSticker:
|
||||
case TGMediaOriginTypeRecentGif:
|
||||
case TGMediaOriginTypeRecentMask:
|
||||
return [NSString stringWithFormat:@"%d", _type];
|
||||
|
||||
case TGMediaOriginTypeRemoteSticker:
|
||||
return [NSString stringWithFormat:@"%d|%@", _type, _remoteStickerEmoji];
|
||||
|
||||
case TGMediaOriginTypeProfilePhoto:
|
||||
return [NSString stringWithFormat:@"%d|%@|%@", _type, _profilePhotoUserId, _profilePhotoOffset];
|
||||
|
||||
case TGMediaOriginTypeChatPhoto:
|
||||
return [NSString stringWithFormat:@"%d|%@", _type, _chatPhotoPeerId];
|
||||
|
||||
case TGMediaOriginTypeWebpage:
|
||||
return [NSString stringWithFormat:@"%d|%@", _type, _webpageUrl];
|
||||
{
|
||||
NSString *url = [TGStringUtils stringByEscapingForURL:_webpageUrl];
|
||||
return [NSString stringWithFormat:@"%d|%@", _type, url];
|
||||
}
|
||||
|
||||
case TGMediaOriginTypeWallpaper:
|
||||
return [NSString stringWithFormat:@"%d|%@", _type, _wallpaperId];
|
||||
@@ -213,6 +245,24 @@
|
||||
return info;
|
||||
}
|
||||
|
||||
+ (instancetype)mediaOriginInfoForRecentMaskWithFileReference:(NSData *)fileReference fileReferences:(NSDictionary *)fileReferences
|
||||
{
|
||||
TGMediaOriginInfo *info = [[TGMediaOriginInfo alloc] init];
|
||||
info->_type = TGMediaOriginTypeRecentMask;
|
||||
info->_fileReference = fileReference;
|
||||
info->_fileReferences = fileReferences;
|
||||
return info;
|
||||
}
|
||||
|
||||
+ (instancetype)mediaOriginInfoForFavoriteStickerWithFileReference:(NSData *)fileReference fileReferences:(NSDictionary *)fileReferences
|
||||
{
|
||||
TGMediaOriginInfo *info = [[TGMediaOriginInfo alloc] init];
|
||||
info->_type = TGMediaOriginTypeFavoriteSticker;
|
||||
info->_fileReference = fileReference;
|
||||
info->_fileReferences = fileReferences;
|
||||
return info;
|
||||
}
|
||||
|
||||
+ (instancetype)mediaOriginInfoForRecentGifWithFileReference:(NSData *)fileReference fileReferences:(NSDictionary *)fileReferences
|
||||
{
|
||||
TGMediaOriginInfo *info = [[TGMediaOriginInfo alloc] init];
|
||||
@@ -243,6 +293,16 @@
|
||||
return info;
|
||||
}
|
||||
|
||||
+ (instancetype)mediaOriginInfoWithFileReference:(NSData *)fileReference fileReferences:(NSDictionary *)fileReferences peerId:(int64_t)peerId
|
||||
{
|
||||
TGMediaOriginInfo *info = [[TGMediaOriginInfo alloc] init];
|
||||
info->_type = TGMediaOriginTypeChatPhoto;
|
||||
info->_fileReference = fileReference;
|
||||
info->_fileReferences = fileReferences;
|
||||
info->_chatPhotoPeerId = @(peerId);
|
||||
return info;
|
||||
}
|
||||
|
||||
+ (instancetype)mediaOriginInfoWithFileReferences:(NSDictionary *)fileReferences wallpaperId:(int32_t)wallpaperId
|
||||
{
|
||||
TGMediaOriginInfo *info = [[TGMediaOriginInfo alloc] init];
|
||||
@@ -252,6 +312,16 @@
|
||||
return info;
|
||||
}
|
||||
|
||||
+ (instancetype)mediaOriginInfoWithFileReference:(NSData *)fileReference fileReferences:(NSDictionary *)fileReferences emoji:(NSString *)emoji
|
||||
{
|
||||
TGMediaOriginInfo *info = [[TGMediaOriginInfo alloc] init];
|
||||
info->_type = TGMediaOriginTypeRemoteSticker;
|
||||
info->_fileReference = fileReference;
|
||||
info->_fileReferences = fileReferences;
|
||||
info->_remoteStickerEmoji = emoji;
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
+ (instancetype)mediaOriginInfoForDocumentAttachment:(TGDocumentMediaAttachment *)document
|
||||
{
|
||||
@@ -259,6 +329,10 @@
|
||||
{
|
||||
TGStickerPackIdReference *reference = (TGStickerPackIdReference *)document.stickerPackReference;
|
||||
return [TGMediaOriginInfo mediaOriginInfoWithFileReference:nil fileReferences:nil stickerPackId:reference.packId accessHash:reference.packAccessHash];
|
||||
}
|
||||
else if (document.isAnimated)
|
||||
{
|
||||
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
@@ -49,16 +49,4 @@
|
||||
+ (NSDictionary *)videoSettingsForPreset:(TGMediaVideoConversionPreset)preset dimensions:(CGSize)dimensions;
|
||||
+ (NSDictionary *)audioSettingsForPreset:(TGMediaVideoConversionPreset)preset;
|
||||
|
||||
|
||||
//REMOVE
|
||||
|
||||
+ (bool)showVMSize;
|
||||
+ (void)setShowVMSize:(bool)on;
|
||||
|
||||
+ (NSInteger)vmSide;
|
||||
+ (NSInteger)vmBitrate;
|
||||
|
||||
+ (void)setVMSide:(NSInteger)side;
|
||||
+ (void)setVMBitrate:(NSInteger)bitrate;
|
||||
|
||||
@end
|
||||
|
||||
@@ -982,8 +982,7 @@ static CGFloat progressOfSampleBufferInTimeRange(CMSampleBufferRef sampleBuffer,
|
||||
|
||||
case TGMediaVideoConversionPresetVideoMessage:
|
||||
{
|
||||
NSInteger side = [self vmSide];
|
||||
return (CGSize){ side, side };
|
||||
return (CGSize){ 240.0f, 240.0f };
|
||||
}
|
||||
|
||||
default:
|
||||
@@ -1067,7 +1066,7 @@ static CGFloat progressOfSampleBufferInTimeRange(CMSampleBufferRef sampleBuffer,
|
||||
return 4000;
|
||||
|
||||
case TGMediaVideoConversionPresetVideoMessage:
|
||||
return [self vmBitrate];
|
||||
return 300;
|
||||
|
||||
default:
|
||||
return 700;
|
||||
@@ -1125,56 +1124,4 @@ static CGFloat progressOfSampleBufferInTimeRange(CMSampleBufferRef sampleBuffer,
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSNumber *)_vmSide
|
||||
{
|
||||
return [[NSUserDefaults standardUserDefaults] objectForKey:@"videoMessageSide"];
|
||||
}
|
||||
|
||||
+ (NSInteger)vmSide
|
||||
{
|
||||
NSNumber *value = [self _vmSide];
|
||||
if (!value)
|
||||
value = @(240);
|
||||
|
||||
return value.integerValue;
|
||||
}
|
||||
|
||||
+ (void)setVMSide:(NSInteger)side
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@(side) forKey:@"videoMessageSide"];
|
||||
}
|
||||
|
||||
+ (NSNumber *)_vmBitrate
|
||||
{
|
||||
return [[NSUserDefaults standardUserDefaults] objectForKey:@"videoMessageBitrate"];
|
||||
}
|
||||
|
||||
+ (NSInteger)vmBitrate
|
||||
{
|
||||
NSNumber *value = [self _vmBitrate];
|
||||
if (!value)
|
||||
value = @(300);
|
||||
|
||||
return value.integerValue;
|
||||
}
|
||||
|
||||
+ (void)setVMBitrate:(NSInteger)bitrate
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@(bitrate) forKey:@"videoMessageBitrate"];
|
||||
}
|
||||
|
||||
+ (bool)showVMSize
|
||||
{
|
||||
NSNumber *value = [[NSUserDefaults standardUserDefaults] objectForKey:@"videoMessageShowSize"];
|
||||
if (value == nil)
|
||||
value = @false;
|
||||
|
||||
return value.boolValue;
|
||||
}
|
||||
|
||||
+ (void)setShowVMSize:(bool)on
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@(on) forKey:@"videoMessageShowSize"];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -19,6 +19,7 @@ typedef enum
|
||||
@property (nonatomic, assign) TGMenuSheetButtonType buttonType;
|
||||
@property (nonatomic, copy) void(^longPressAction)(void);
|
||||
@property (nonatomic, copy) void (^action)(void);
|
||||
@property (nonatomic, assign) bool thickDivider;
|
||||
|
||||
- (instancetype)initWithTitle:(NSString *)title type:(TGMenuSheetButtonType)type action:(void (^)(void))action;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ const CGFloat TGMenuSheetButtonItemViewHeight = 57.0f;
|
||||
{
|
||||
bool _dark;
|
||||
bool _requiresDivider;
|
||||
UIView *_customDivider;
|
||||
|
||||
TGMenuSheetPallete *_pallete;
|
||||
}
|
||||
@@ -66,6 +67,7 @@ const CGFloat TGMenuSheetButtonItemViewHeight = 57.0f;
|
||||
{
|
||||
_pallete = pallete;
|
||||
_button.highlightBackgroundColor = pallete.selectionColor;
|
||||
_customDivider.backgroundColor = _pallete.separatorColor;
|
||||
[self _updateForType:_buttonType];
|
||||
}
|
||||
|
||||
@@ -135,6 +137,21 @@ const CGFloat TGMenuSheetButtonItemViewHeight = 57.0f;
|
||||
return _collapsed ? 0.0f : TGMenuSheetButtonItemViewHeight;
|
||||
}
|
||||
|
||||
- (void)setThickDivider:(bool)thickDivider
|
||||
{
|
||||
if (thickDivider && _customDivider == nil)
|
||||
{
|
||||
_customDivider = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, self.bounds.size.width, TGScreenPixel)];
|
||||
_customDivider.backgroundColor = _pallete.separatorColor;
|
||||
[self addSubview:_customDivider];
|
||||
}
|
||||
else if (!thickDivider)
|
||||
{
|
||||
[_customDivider removeFromSuperview];
|
||||
_customDivider = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (bool)requiresDivider
|
||||
{
|
||||
return _requiresDivider;
|
||||
@@ -148,6 +165,7 @@ const CGFloat TGMenuSheetButtonItemViewHeight = 57.0f;
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
_button.frame = self.bounds;
|
||||
_customDivider.frame = CGRectMake(0.0f, 0.0f, self.bounds.size.width, TGScreenPixel);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
@class TGImageInfo;
|
||||
@class TGImageView;
|
||||
@class TGMediaOriginInfo;
|
||||
|
||||
@interface TGModernGalleryImageItem : NSObject <TGModernGalleryItem>
|
||||
|
||||
@@ -17,6 +18,7 @@
|
||||
@property (nonatomic) bool hasStickers;
|
||||
@property (nonatomic) int64_t imageId;
|
||||
@property (nonatomic) int64_t accessHash;
|
||||
@property (nonatomic, strong) TGMediaOriginInfo *originInfo;
|
||||
|
||||
- (instancetype)initWithUri:(NSString *)uri imageSize:(CGSize)imageSize;
|
||||
- (instancetype)initWithLoader:(dispatch_block_t (^)(TGImageView *, bool))loader imageSize:(CGSize)imageSize;
|
||||
|
||||
@@ -224,7 +224,8 @@
|
||||
__weak TGMediaAssetsController *weakController = controller;
|
||||
controller.singleCompletionBlock = ^(id<TGMediaEditableItem> currentItem, TGMediaEditingContext *editingContext)
|
||||
{
|
||||
uploadAction([TGPassportAttachMenu resultSignalForEditingContext:editingContext selectionContext:nil currentItem:(id<TGMediaEditableItem>)currentItem],
|
||||
__strong TGMediaAssetsController *strongController = weakController;
|
||||
uploadAction([TGPassportAttachMenu resultSignalForEditingContext:editingContext selectionContext:strongController.selectionContext currentItem:(id<TGMediaEditableItem>)currentItem],
|
||||
^{
|
||||
__strong TGMediaAssetsController *strongController = weakController;
|
||||
if (strongController != nil && strongController.dismissalBlock != nil)
|
||||
|
||||
@@ -5,8 +5,12 @@
|
||||
@property (nonatomic, readonly) NSString *documentType;
|
||||
@property (nonatomic, readonly) NSString *documentSubtype;
|
||||
@property (nonatomic, readonly) NSString *issuingCountry;
|
||||
@property (nonatomic, readonly) NSString *lastName;
|
||||
@property (nonatomic, readonly) NSString *firstName;
|
||||
@property (nonatomic, readonly) NSString *middleName;
|
||||
@property (nonatomic, readonly) NSString *lastName;
|
||||
@property (nonatomic, readonly) NSString *nativeFirstName;
|
||||
@property (nonatomic, readonly) NSString *nativeMiddleName;
|
||||
@property (nonatomic, readonly) NSString *nativeLastName;
|
||||
@property (nonatomic, readonly) NSString *documentNumber;
|
||||
@property (nonatomic, readonly) NSString *nationality;
|
||||
@property (nonatomic, readonly) NSDate *birthDate;
|
||||
@@ -18,6 +22,9 @@
|
||||
@property (nonatomic, readonly) NSString *mrz;
|
||||
|
||||
+ (instancetype)parseLines:(NSArray *)lines;
|
||||
+ (instancetype)parseBarcodePayload:(NSString *)data;
|
||||
|
||||
+ (NSString *)transliterateRussianName:(NSString *)string;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -6,6 +6,136 @@ NSString *const TGPassportEmptyCharacter = @"<";
|
||||
|
||||
@implementation TGPassportMRZ
|
||||
|
||||
+ (instancetype)parseBarcodePayload:(NSString *)data
|
||||
{
|
||||
if (data.length == 0)
|
||||
return nil;
|
||||
|
||||
if ([data rangeOfString:@"ANSI "].location != NSNotFound)
|
||||
{
|
||||
NSMutableDictionary *fields = [[NSMutableDictionary alloc] init];
|
||||
[data enumerateLinesUsingBlock:^(NSString *line, BOOL *stop)
|
||||
{
|
||||
if (line.length < 4 || ![line hasPrefix:@"D"])
|
||||
return;
|
||||
|
||||
NSString *field = [line substringToIndex:3];
|
||||
NSString *value = [line substringFromIndex:3];
|
||||
fields[field] = value;
|
||||
}];
|
||||
|
||||
if (fields.count == 0)
|
||||
return nil;
|
||||
|
||||
TGPassportMRZ *result = [[TGPassportMRZ alloc] init];
|
||||
result->_documentType = @"DL";
|
||||
|
||||
NSString *issuingCountry = fields[@"DCG"];
|
||||
result->_issuingCountry = issuingCountry;
|
||||
|
||||
result->_documentNumber = fields[@"DCF"];
|
||||
|
||||
NSString *firstName = fields[@"DAC"];
|
||||
if (firstName == nil)
|
||||
firstName = fields[@"DCT"];
|
||||
result->_firstName = firstName;
|
||||
|
||||
NSString *lastName = fields[@"DCS"];
|
||||
if (lastName == nil)
|
||||
lastName = fields[@"DAB"];
|
||||
result->_lastName = lastName;
|
||||
|
||||
NSString *middleName = fields[@"DAD"];
|
||||
result->_middleName = middleName;
|
||||
|
||||
NSString *gender = fields[@"DBC"];
|
||||
if ([gender isEqualToString:@"1"])
|
||||
result->_gender = @"M";
|
||||
else if ([gender isEqualToString:@"2"])
|
||||
result->_gender = @"F";
|
||||
|
||||
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
|
||||
[formatter setDateFormat:@"MMddyyyy"];
|
||||
|
||||
NSDateFormatter *fallbackFormatter = [[NSDateFormatter alloc] init];
|
||||
[fallbackFormatter setDateFormat:@"MMddyyyy"];
|
||||
|
||||
NSString *expiryDate = fields[@"DBA"];
|
||||
if (expiryDate.length > 0)
|
||||
{
|
||||
NSDate *date = [formatter dateFromString:expiryDate];
|
||||
if (date == nil)
|
||||
[fallbackFormatter dateFromString:expiryDate];
|
||||
|
||||
result->_expiryDate = date;
|
||||
}
|
||||
|
||||
NSString *birthDate = fields[@"DBB"];
|
||||
if (birthDate.length > 0)
|
||||
{
|
||||
NSDate *date = [formatter dateFromString:birthDate];
|
||||
if (date == nil)
|
||||
[fallbackFormatter dateFromString:birthDate];
|
||||
|
||||
result->_birthDate = date;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
NSCharacterSet *invertedBase64CharacterSet = [[NSCharacterSet characterSetWithCharactersInString:@"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="] invertedSet];
|
||||
|
||||
if ([data rangeOfCharacterFromSet:invertedBase64CharacterSet].location != NSNotFound)
|
||||
return nil;
|
||||
|
||||
NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:data options:0];
|
||||
if (decodedData.length == 0)
|
||||
return nil;
|
||||
|
||||
NSString *decodedString = [[NSString alloc] initWithData:decodedData encoding:NSWindowsCP1251StringEncoding];
|
||||
if (decodedString.length == 0)
|
||||
return nil;
|
||||
|
||||
NSArray *components = [decodedString componentsSeparatedByString:@"|"];
|
||||
if (components.count < 7)
|
||||
return nil;
|
||||
|
||||
TGPassportMRZ *result = [[TGPassportMRZ alloc] init];
|
||||
result->_documentType = @"DL";
|
||||
result->_issuingCountry = @"RUS";
|
||||
result->_nationality = @"RUS";
|
||||
result->_documentNumber = components[0];
|
||||
|
||||
NSString *nativeFirstName = components[4];
|
||||
result->_nativeFirstName = nativeFirstName;
|
||||
result->_firstName = [self transliterateRussianName:nativeFirstName];
|
||||
|
||||
NSString *nativeLastName = components[3];
|
||||
result->_nativeLastName = nativeLastName;
|
||||
result->_lastName = [self transliterateRussianName:nativeLastName];
|
||||
|
||||
NSString *nativeMiddleName = components[5];
|
||||
result->_nativeMiddleName = nativeMiddleName;
|
||||
result->_middleName = [self transliterateRussianName:nativeMiddleName];
|
||||
|
||||
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
|
||||
[dateFormatter setDateFormat:@"yyyyMMdd"];
|
||||
|
||||
NSString *birthDate = components[6];
|
||||
if (birthDate.length > 0)
|
||||
result->_birthDate = [dateFormatter dateFromString:birthDate];
|
||||
|
||||
NSString *expiryDate = components[2];
|
||||
if (expiryDate.length > 0)
|
||||
result->_expiryDate = [dateFormatter dateFromString:expiryDate];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (instancetype)parseLines:(NSArray<NSString *> *)lines
|
||||
{
|
||||
if (lines.count == 2)
|
||||
@@ -58,8 +188,10 @@ NSString *const TGPassportEmptyCharacter = @"<";
|
||||
if ([result->_documentType isEqualToString:@"P"] && [result->_documentSubtype isEqualToString:@"N"] && [result->_issuingCountry isEqualToString:@"RUS"])
|
||||
{
|
||||
NSString *lastName = [self transliterateRussianMRZString:result->_lastName];
|
||||
result->_nativeLastName = lastName;
|
||||
result->_lastName = [self transliterateRussianName:lastName];
|
||||
NSString *firstName = [self transliterateRussianMRZString:result->_firstName];
|
||||
result->_nativeFirstName = firstName;
|
||||
result->_firstName = [self transliterateRussianName:firstName];
|
||||
|
||||
NSString *lastSeriesDigit = [optional1 substringToIndex:1];
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
@interface TGPassportOCR : NSObject
|
||||
|
||||
+ (SSignal *)recognizeDataInImage:(UIImage *)image shouldBeDriversLicense:(bool)shouldBeDriversLicense;
|
||||
+ (SSignal *)recognizeMRZInImage:(UIImage *)image;
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,9 +1,29 @@
|
||||
#import "TGPassportOCR.h"
|
||||
|
||||
#import "LegacyComponentsInternal.h"
|
||||
#import <Vision/Vision.h>
|
||||
|
||||
#import "TGPassportMRZ.h"
|
||||
#import "ocr.h"
|
||||
|
||||
@implementation TGPassportOCR
|
||||
|
||||
+ (SSignal *)recognizeDataInImage:(UIImage *)image shouldBeDriversLicense:(bool)shouldBeDriversLicense
|
||||
{
|
||||
if (iosMajorVersion() < 11)
|
||||
return [self recognizeMRZInImage:image];
|
||||
|
||||
SSignal *initial = shouldBeDriversLicense ? [self recognizeBarcodeInImage:image] : [self recognizeMRZInImage:image];
|
||||
SSignal *fallback = shouldBeDriversLicense ? [self recognizeMRZInImage:image] : [self recognizeBarcodeInImage:image];
|
||||
|
||||
return [initial mapToSignal:^SSignal *(id value)
|
||||
{
|
||||
if (value != nil)
|
||||
return [SSignal single:value];
|
||||
return fallback;
|
||||
}];
|
||||
}
|
||||
|
||||
+ (SSignal *)recognizeMRZInImage:(UIImage *)image
|
||||
{
|
||||
return [[SSignal defer:^SSignal *
|
||||
@@ -18,4 +38,35 @@
|
||||
}] startOn:[SQueue concurrentDefaultQueue]];
|
||||
}
|
||||
|
||||
+ (SSignal *)recognizeBarcodeInImage:(UIImage *)image
|
||||
{
|
||||
return [[[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber) {
|
||||
VNDetectBarcodesRequest *barcodeRequest = [[VNDetectBarcodesRequest alloc] initWithCompletionHandler:^(VNRequest * _Nonnull request, NSError * _Nullable error)
|
||||
{
|
||||
TGPassportMRZ *mrz = nil;
|
||||
NSArray *results = request.results;
|
||||
for (VNBarcodeObservation *barcode in results)
|
||||
{
|
||||
if (![barcode isKindOfClass:[VNBarcodeObservation class]])
|
||||
continue;
|
||||
|
||||
if (barcode.symbology != VNBarcodeSymbologyPDF417)
|
||||
continue;
|
||||
|
||||
NSString *payload = barcode.payloadStringValue;
|
||||
mrz = [TGPassportMRZ parseBarcodePayload:payload];
|
||||
}
|
||||
|
||||
[subscriber putNext:mrz];
|
||||
[subscriber putCompletion];
|
||||
}];
|
||||
|
||||
NSError *error;
|
||||
VNImageRequestHandler *handler = [[VNImageRequestHandler alloc] initWithCGImage:image.CGImage options:@{}];
|
||||
[handler performRequests:@[barcodeRequest] error:&error];
|
||||
|
||||
return nil;
|
||||
}] startOn:[SQueue concurrentDefaultQueue]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -68,28 +68,22 @@
|
||||
__weak TGPassportScanView *weakSelf = self;
|
||||
[_camera captureNextFrameCompletion:^(UIImage *image)
|
||||
{
|
||||
NSLog(@"SS_frameComple");
|
||||
[_ocrDisposable setDisposable:[[[TGPassportOCR recognizeMRZInImage:image] deliverOn:[SQueue mainQueue]] startWithNext:^(TGPassportMRZ *next)
|
||||
[_ocrDisposable setDisposable:[[[TGPassportOCR recognizeDataInImage:image shouldBeDriversLicense:false] deliverOn:[SQueue mainQueue]] startWithNext:^(TGPassportMRZ *next)
|
||||
{
|
||||
__strong TGPassportScanView *strongSelf = weakSelf;
|
||||
if (strongSelf == nil)
|
||||
return;
|
||||
|
||||
NSLog(@"SS_recognized");
|
||||
|
||||
if (next != nil)
|
||||
{
|
||||
[strongSelf->_camera stopCaptureForPause:true completion:nil];
|
||||
|
||||
if (strongSelf.finishedWithMRZ != nil)
|
||||
strongSelf.finishedWithMRZ(next);
|
||||
|
||||
NSLog(@"SS_finished");
|
||||
}
|
||||
else
|
||||
{
|
||||
strongSelf->_timer = [TGTimerTarget scheduledMainThreadTimerWithTarget:self action:@selector(handleNextFrame) interval:0.45 repeat:false];
|
||||
NSLog(@"SS_scheduledNext");
|
||||
}
|
||||
}]];
|
||||
}];
|
||||
|
||||
@@ -13,6 +13,7 @@ static TGCache *sharedCache = nil;
|
||||
@interface TGRemoteImageView ()
|
||||
|
||||
@property (atomic, strong) NSString *path;
|
||||
@property (atomic, strong) NSString *currentCacheUrl;
|
||||
|
||||
@property (nonatomic, strong) UIImageView *placeholderView;
|
||||
|
||||
@@ -231,8 +232,13 @@ static TGCache *sharedCache = nil;
|
||||
|
||||
TGCache *cache = _cache != nil ? _cache : [TGRemoteImageView sharedCache];
|
||||
|
||||
NSString *cacheUrl = filter == nil ? url : [[NSString alloc] initWithFormat:@"{filter:%@}%@", filter, url];
|
||||
NSString *trimmedUrl = url;
|
||||
NSArray *components = [trimmedUrl componentsSeparatedByString:@"_"];
|
||||
if (components.count >= 5)
|
||||
trimmedUrl = [NSString stringWithFormat:@"%@_%@_%@_%@", components[0], components[1], components[2], components[3]];
|
||||
|
||||
NSString *cacheUrl = filter == nil ? trimmedUrl : [[NSString alloc] initWithFormat:@"{filter:%@}%@", filter, trimmedUrl];
|
||||
self.currentCacheUrl = cacheUrl;
|
||||
UIImage *image = [cache cachedImage:cacheUrl availability:TGCacheMemory];
|
||||
|
||||
if (image == nil)
|
||||
@@ -461,7 +467,7 @@ static TGCache *sharedCache = nil;
|
||||
if (_useCache)
|
||||
{
|
||||
TGCache *cache = _cache != nil ? _cache : [TGRemoteImageView sharedCache];
|
||||
[cache cacheImage:image withData:nil url:self.currentUrl availability:TGCacheMemory];
|
||||
[cache cacheImage:image withData:nil url:self.currentCacheUrl availability:TGCacheMemory];
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -62,7 +62,12 @@
|
||||
|
||||
- (NSData *)imageData
|
||||
{
|
||||
return [[NSData alloc] initWithContentsOfFile:[[TGRemoteImageView sharedCache] pathForCachedData:[self fullscreenUrl]]];
|
||||
NSString *trimmedUrl = [self fullscreenUrl];
|
||||
NSArray *components = [trimmedUrl componentsSeparatedByString:@"_"];
|
||||
if (components.count >= 5)
|
||||
trimmedUrl = [NSString stringWithFormat:@"%@_%@_%@_%@", components[0], components[1], components[2], components[3]];
|
||||
|
||||
return [[NSData alloc] initWithContentsOfFile:[[TGRemoteImageView sharedCache] pathForCachedData:trimmedUrl]];
|
||||
}
|
||||
|
||||
- (UIImage *)image
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
_timerValues = values;
|
||||
|
||||
if (selectedValue)
|
||||
if (selectedValue != nil)
|
||||
{
|
||||
NSInteger index = [_timerValues indexOfObject:selectedValue];
|
||||
if (index != NSNotFound)
|
||||
|
||||
@@ -109,6 +109,7 @@ typedef enum {
|
||||
@property (nonatomic) bool botInlineGeo;
|
||||
|
||||
@property (nonatomic, readonly) bool isBot;
|
||||
@property (nonatomic, readonly) bool isDeleted;
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone;
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#import "PSKeyValueCoder.h"
|
||||
|
||||
#import "TGConversation.h"
|
||||
#import "TGMediaOriginInfo.h"
|
||||
#import "TGImageInfo.h"
|
||||
|
||||
typedef enum {
|
||||
TGUserFlagVerified = (1 << 0),
|
||||
@@ -126,6 +128,10 @@ typedef enum {
|
||||
return _kind == TGUserKindBot || _kind == TGUserKindSmartBot;
|
||||
}
|
||||
|
||||
- (bool)isDeleted {
|
||||
return (_phonebookFirstName.length != 0 || _phonebookLastName.length != 0) ? false : ((_firstName.length != 0 || _lastName.length != 0) ? false : (_phoneNumber.length == 0 ? true : false));
|
||||
}
|
||||
|
||||
- (NSString *)firstName
|
||||
{
|
||||
return (_phonebookFirstName.length != 0 || _phonebookLastName.length != 0) ? _phonebookFirstName : ((_firstName.length != 0 || _lastName.length != 0) ? _firstName : (_phoneNumber.length == 0 ? TGLocalized(@"User.DeletedAccount") : [self formattedPhoneNumber]));
|
||||
@@ -423,8 +429,18 @@ typedef enum {
|
||||
if (finalAvatarUrl.length == 0)
|
||||
return finalAvatarUrl;
|
||||
|
||||
if (self.photoFileReferenceSmall != nil)
|
||||
finalAvatarUrl = [finalAvatarUrl stringByAppendingFormat:@"_%@", [self.photoFileReferenceSmall stringByEncodingInHex]];
|
||||
int64_t volumeId = 0;
|
||||
int32_t localId = 0;
|
||||
if (extractFileUrlComponents(self.photoUrlSmall, NULL, &volumeId, &localId, NULL))
|
||||
{
|
||||
NSString *key = [NSString stringWithFormat:@"%lld_%d", volumeId, localId];
|
||||
NSDictionary *fileReferences = nil;
|
||||
if (self.photoFileReferenceSmall != nil) {
|
||||
fileReferences = @{ key: self.photoFileReferenceSmall };
|
||||
}
|
||||
TGMediaOriginInfo *originInfo = [TGMediaOriginInfo mediaOriginInfoWithFileReference:self.photoFileReferenceSmall fileReferences:fileReferences userId:_uid offset:0];
|
||||
finalAvatarUrl = [finalAvatarUrl stringByAppendingFormat:@"_o%@", [originInfo stringRepresentation]];
|
||||
}
|
||||
|
||||
return finalAvatarUrl;
|
||||
}
|
||||
@@ -435,8 +451,18 @@ typedef enum {
|
||||
if (finalAvatarUrl.length == 0)
|
||||
return finalAvatarUrl;
|
||||
|
||||
if (self.photoFileReferenceBig != nil)
|
||||
finalAvatarUrl = [finalAvatarUrl stringByAppendingFormat:@"_%@", [self.photoFileReferenceBig stringByEncodingInHex]];
|
||||
int64_t volumeId = 0;
|
||||
int32_t localId = 0;
|
||||
if (extractFileUrlComponents(self.photoUrlBig, NULL, &volumeId, &localId, NULL))
|
||||
{
|
||||
NSString *key = [NSString stringWithFormat:@"%lld_%d", volumeId, localId];
|
||||
NSDictionary *fileReferences = nil;
|
||||
if (self.photoFileReferenceBig != nil) {
|
||||
fileReferences = @{ key: self.photoFileReferenceBig };
|
||||
}
|
||||
TGMediaOriginInfo *originInfo = [TGMediaOriginInfo mediaOriginInfoWithFileReference:self.photoFileReferenceBig fileReferences:fileReferences userId:_uid offset:0];
|
||||
finalAvatarUrl = [finalAvatarUrl stringByAppendingFormat:@"_o%@", [originInfo stringRepresentation]];
|
||||
}
|
||||
|
||||
return finalAvatarUrl;
|
||||
}
|
||||
|
||||
@@ -141,6 +141,60 @@ namespace ocr{
|
||||
delete[] cosCache;
|
||||
return lines;
|
||||
}
|
||||
|
||||
void binarizeBitmapPart(uint8_t* inPixels, unsigned char* outPixels, size_t width, size_t height, size_t inBytesPerRow, size_t outBytesPerRow){
|
||||
uint32_t histogram[256]={0};
|
||||
uint32_t intensitySum=0;
|
||||
for(unsigned int y=0;y<height;y++){
|
||||
for(unsigned int x=0;x<width;x++){
|
||||
uint8_t *px = inPixels + (inBytesPerRow * y) + x * 4;
|
||||
uint8_t r = *(px + 1);
|
||||
uint8_t g = *(px + 2);
|
||||
uint8_t b = *(px + 3);
|
||||
|
||||
int l = (r + g + b)/3.0;
|
||||
outPixels[(outBytesPerRow * y) + x]=l;
|
||||
histogram[l]++;
|
||||
intensitySum+=l;
|
||||
}
|
||||
}
|
||||
int threshold=0;
|
||||
double best_sigma = 0.0;
|
||||
|
||||
int first_class_pixel_count = 0;
|
||||
int first_class_intensity_sum = 0;
|
||||
|
||||
for (int thresh = 0; thresh < 255; ++thresh) {
|
||||
first_class_pixel_count += histogram[thresh];
|
||||
first_class_intensity_sum += thresh * histogram[thresh];
|
||||
|
||||
double first_class_prob = first_class_pixel_count / (double) (width*height);
|
||||
double second_class_prob = 1.0 - first_class_prob;
|
||||
|
||||
double first_class_mean = first_class_intensity_sum / (double) first_class_pixel_count;
|
||||
double second_class_mean = (intensitySum - first_class_intensity_sum)
|
||||
/ (double) ((width*height) - first_class_pixel_count);
|
||||
|
||||
double mean_delta = first_class_mean - second_class_mean;
|
||||
|
||||
double sigma = first_class_prob * second_class_prob * mean_delta * mean_delta;
|
||||
|
||||
if (sigma > best_sigma) {
|
||||
best_sigma = sigma;
|
||||
threshold = thresh;
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned int y=0;y<height;y++){
|
||||
for(unsigned int x=0;x<width;x++){
|
||||
uint8_t *px = inPixels + (inBytesPerRow * y) + x * 4;
|
||||
uint8_t r = *(px + 1);
|
||||
uint8_t g = *(px + 2);
|
||||
uint8_t b = *(px + 3);
|
||||
outPixels[(outBytesPerRow * y) + x]=(r<threshold && g<threshold && b<threshold) ? (unsigned char)255 : (unsigned char)0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NSDictionary *findCornerPoints(UIImage *bitmap) {
|
||||
@@ -328,66 +382,95 @@ NSArray *binarizeAndFindCharacters(UIImage *inBmp, UIImage **outBinaryImage) {
|
||||
|
||||
uint8_t *outPixels = (uint8_t *)malloc(width * height * 1);
|
||||
|
||||
uint32_t histogram[256]={0};
|
||||
uint32_t intensitySum=0;
|
||||
for(unsigned int y=0;y<height;y++){
|
||||
for(unsigned int x=0;x<width;x++){
|
||||
uint8_t *px = bitmapPixels + (bytesPerRow * y) + x * 4;
|
||||
uint8_t r = *(px + 1);
|
||||
uint8_t g = *(px + 2);
|
||||
uint8_t b = *(px + 3);
|
||||
int l = (r + g + b)/3.0;
|
||||
outPixels[(width * y) + x]=l;
|
||||
histogram[l]++;
|
||||
intensitySum+=l;
|
||||
}
|
||||
}
|
||||
uint32_t threshold=0;
|
||||
double best_sigma = 0.0;
|
||||
// uint32_t histogram[256]={0};
|
||||
// uint32_t intensitySum=0;
|
||||
// for(unsigned int y=0;y<height;y++){
|
||||
// for(unsigned int x=0;x<width;x++){
|
||||
// uint8_t *px = bitmapPixels + (bytesPerRow * y) + x * 4;
|
||||
// uint8_t r = *(px + 1);
|
||||
// uint8_t g = *(px + 2);
|
||||
// uint8_t b = *(px + 3);
|
||||
// int l = (r + g + b)/3.0;
|
||||
// outPixels[(width * y) + x]=l;
|
||||
// histogram[l]++;
|
||||
// intensitySum+=l;
|
||||
// }
|
||||
// }
|
||||
// uint32_t threshold=0;
|
||||
// double best_sigma = 0.0;
|
||||
//
|
||||
// int first_class_pixel_count = 0;
|
||||
// int first_class_intensity_sum = 0;
|
||||
//
|
||||
// for (int thresh = 0; thresh < 255; ++thresh) {
|
||||
// first_class_pixel_count += histogram[thresh];
|
||||
// first_class_intensity_sum += thresh * histogram[thresh];
|
||||
//
|
||||
// double first_class_prob = first_class_pixel_count / (double) (width*height);
|
||||
// double second_class_prob = 1.0 - first_class_prob;
|
||||
//
|
||||
// double first_class_mean = first_class_intensity_sum / (double) first_class_pixel_count;
|
||||
// double second_class_mean = (intensitySum - first_class_intensity_sum) / (double) ((width*height) - first_class_pixel_count);
|
||||
//
|
||||
// double mean_delta = first_class_mean - second_class_mean;
|
||||
|
||||
int first_class_pixel_count = 0;
|
||||
int first_class_intensity_sum = 0;
|
||||
|
||||
for (int thresh = 0; thresh < 255; ++thresh) {
|
||||
first_class_pixel_count += histogram[thresh];
|
||||
first_class_intensity_sum += thresh * histogram[thresh];
|
||||
|
||||
double first_class_prob = first_class_pixel_count / (double) (width*height);
|
||||
double second_class_prob = 1.0 - first_class_prob;
|
||||
|
||||
double first_class_mean = first_class_intensity_sum / (double) first_class_pixel_count;
|
||||
double second_class_mean = (intensitySum - first_class_intensity_sum) / (double) ((width*height) - first_class_pixel_count);
|
||||
|
||||
double mean_delta = first_class_mean - second_class_mean;
|
||||
|
||||
double sigma = first_class_prob * second_class_prob * mean_delta * mean_delta;
|
||||
|
||||
if (sigma > best_sigma) {
|
||||
best_sigma = sigma;
|
||||
threshold = thresh;
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned int y=0;y<height;y++){
|
||||
for(unsigned int x=0;x<width;x++){
|
||||
uint8_t *px = bitmapPixels + (bytesPerRow * y) + x * 4;
|
||||
uint8_t r = *(px + 1);
|
||||
uint8_t g = *(px + 2);
|
||||
uint8_t b = *(px + 3);
|
||||
outPixels[(width * y) + x]=(r<threshold && g<threshold && b<threshold) ? (unsigned char)255 : (unsigned char)0;
|
||||
}
|
||||
}
|
||||
// double sigma = first_class_prob * second_class_prob * mean_delta * mean_delta;
|
||||
//
|
||||
// if (sigma > best_sigma) {
|
||||
// best_sigma = sigma;
|
||||
// threshold = thresh;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// for(unsigned int y=0;y<height;y++){
|
||||
// for(unsigned int x=0;x<width;x++){
|
||||
// uint8_t *px = bitmapPixels + (bytesPerRow * y) + x * 4;
|
||||
// uint8_t r = *(px + 1);
|
||||
// uint8_t g = *(px + 2);
|
||||
// uint8_t b = *(px + 3);
|
||||
// outPixels[(width * y) + x]=(r<threshold && g<threshold && b<threshold) ? (unsigned char)255 : (unsigned char)0;
|
||||
// }
|
||||
// }
|
||||
|
||||
for(unsigned int y=0;y<height;y+=120){
|
||||
for(unsigned int x=0; x<width; x+=120){
|
||||
int partWidth=x+120<width ? 120 : (width-x);
|
||||
int partHeight=y+120<height ? 120 : (height-y);
|
||||
|
||||
ocr::binarizeBitmapPart((bitmapPixels + (y * bytesPerRow) + x * 4), outPixels + (width * y) + x, partWidth, partHeight, bytesPerRow, width);
|
||||
}
|
||||
}
|
||||
|
||||
// remove any single pixels without adjacent ones - these are usually noise
|
||||
for(unsigned int y=height/2;y<height-1;y++){
|
||||
unsigned int yOffset=y*width;
|
||||
unsigned int yOffsetPrev=(y-1)*width;
|
||||
unsigned int yOffsetNext=(y+1)*width;
|
||||
for(unsigned int x=1;x<width-1;x++){
|
||||
if(outPixels[width * y + x]>0
|
||||
&& outPixels[width * y + x +1]==0
|
||||
&& outPixels[width * y + x -1]==0
|
||||
&& outPixels[width * (y + 1) + x]==0
|
||||
&& outPixels[width * (y - 1) + x]==0){
|
||||
outPixels[width * y + x]=0;
|
||||
}
|
||||
int pixelCount=0;
|
||||
if(outPixels[yOffsetPrev+x-1]!=0)
|
||||
pixelCount++;
|
||||
if(outPixels[yOffsetPrev+x]!=0)
|
||||
pixelCount++;
|
||||
if(outPixels[yOffsetPrev+x+1]!=0)
|
||||
pixelCount++;
|
||||
|
||||
if(outPixels[yOffset+x-1]!=0)
|
||||
pixelCount++;
|
||||
if(outPixels[yOffset+x]!=0)
|
||||
pixelCount++;
|
||||
if(outPixels[yOffset+x+1]!=0)
|
||||
pixelCount++;
|
||||
|
||||
if(outPixels[yOffsetNext+x-1]!=0)
|
||||
pixelCount++;
|
||||
if(outPixels[yOffsetNext+x]!=0)
|
||||
pixelCount++;
|
||||
if(outPixels[yOffsetNext+x+1]!=0)
|
||||
pixelCount++;
|
||||
|
||||
if(pixelCount<3)
|
||||
outPixels[yOffset+x]=0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -452,8 +535,8 @@ NSArray *binarizeAndFindCharacters(UIImage *inBmp, UIImage **outBinaryImage) {
|
||||
bottomFilledPixels++;
|
||||
}
|
||||
}
|
||||
maxEmptyPixels=max(maxEmptyPixels, consecutiveEmptyPixels);
|
||||
if(lineHeight-maxEmptyPixels<lineHeight/10 && bottomFilledPixels==0){
|
||||
maxEmptyPixels=consecutiveEmptyPixels;
|
||||
if(lineHeight-maxEmptyPixels<=lineHeight/15 && bottomFilledPixels==0){
|
||||
consecutiveEmptyCols++;
|
||||
}else if(consecutiveEmptyCols>0){
|
||||
emptyAreaXs.emplace_back(x-consecutiveEmptyCols, x);
|
||||
@@ -506,7 +589,7 @@ NSArray *binarizeAndFindCharacters(UIImage *inBmp, UIImage **outBinaryImage) {
|
||||
if(found)
|
||||
break;
|
||||
}
|
||||
if(bottom-top<lineHeight/2)
|
||||
if(bottom-top<lineHeight/4)
|
||||
continue;
|
||||
if(rects.count < 44){
|
||||
CGRect rect = CGRectMake(h->second, top, nextH->first - h->second, bottom - top);
|
||||
|
||||
Reference in New Issue
Block a user