Merge commit '33dd02f7a98f863c7bb6e3667b7014fe87918872'

This commit is contained in:
Peter
2018-08-31 04:24:35 +03:00
31 changed files with 626 additions and 165 deletions

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -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]];
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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;

View File

@@ -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)

View File

@@ -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

View File

@@ -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];

View File

@@ -3,6 +3,7 @@
@interface TGPassportOCR : NSObject
+ (SSignal *)recognizeDataInImage:(UIImage *)image shouldBeDriversLicense:(bool)shouldBeDriversLicense;
+ (SSignal *)recognizeMRZInImage:(UIImage *)image;
@end

View File

@@ -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

View File

@@ -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");
}
}]];
}];

View File

@@ -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

View File

@@ -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

View File

@@ -34,7 +34,7 @@
_timerValues = values;
if (selectedValue)
if (selectedValue != nil)
{
NSInteger index = [_timerValues indexOfObject:selectedValue];
if (index != NSNotFound)

View File

@@ -109,6 +109,7 @@ typedef enum {
@property (nonatomic) bool botInlineGeo;
@property (nonatomic, readonly) bool isBot;
@property (nonatomic, readonly) bool isDeleted;
- (id)copyWithZone:(NSZone *)zone;

View File

@@ -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;
}

View File

@@ -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);