1
0
mirror of https://github.com/danog/Telegram.git synced 2024-12-12 09:29:55 +01:00
Telegram/legacy/TelegraphKit/TGImageInfo.mm
2015-10-01 19:19:52 +03:00

359 lines
9.6 KiB
Plaintext

#import "TGImageInfo.h"
#import <vector>
struct TGImageSizeRecord
{
CGSize size;
NSString *url;
int fileSize;
TGImageSizeRecord(CGSize size_, NSString *url_, int fileSize_) :
size(size_), fileSize(fileSize_)
{
url = url_;
}
TGImageSizeRecord(const TGImageSizeRecord &other)
{
url = other.url;
size = other.size;
fileSize = other.fileSize;
}
TGImageSizeRecord & operator= (const TGImageSizeRecord &other)
{
if (this != &other)
{
url = other.url;
size = other.size;
fileSize = other.fileSize;
}
return *this;
}
~TGImageSizeRecord()
{
url = nil;
}
};
@interface TGImageInfo ()
{
std::vector<TGImageSizeRecord> sizes;
}
@end
@implementation TGImageInfo
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self != nil)
{
for (NSDictionary *sizeDict in [aDecoder decodeObjectForKey:@"sizes"])
{
[self addImageWithSize:CGSizeMake([sizeDict[@"width"] floatValue], [sizeDict[@"height"] floatValue]) url:sizeDict[@"url"] fileSize:[sizeDict[@"fileSize"] intValue]];
}
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
NSMutableArray *array = [[NSMutableArray alloc] init];
for (auto it : sizes)
{
[array addObject:@{@"width": @(it.size.width), @"height": @(it.size.height), @"url": it.url == nil ? @"" : it.url, @"fileSize": @(it.fileSize)}];
}
[aCoder encodeObject:array forKey:@"sizes"];
}
- (BOOL)isEqual:(id)object
{
if (![object isKindOfClass:[TGImageInfo class]])
return false;
TGImageInfo *other = (TGImageInfo *)object;
if (sizes.size() != other->sizes.size())
return false;
for (int i = 0; i < (int)sizes.size(); i++)
{
if (!CGSizeEqualToSize(sizes[i].size, other->sizes[i].size))
return false;
if (![sizes[i].url isEqualToString:other->sizes[i].url])
return false;
}
return true;
}
- (void)addImageWithSize:(CGSize)size url:(NSString *)url
{
sizes.push_back(TGImageSizeRecord(size, url, 0));
}
- (void)addImageWithSize:(CGSize)size url:(NSString *)url fileSize:(int)fileSize
{
sizes.push_back(TGImageSizeRecord(size, url, fileSize));
}
- (NSString *)closestImageUrlWithWidth:(int)width resultingSize:(CGSize *)resultingSize
{
CGSize closestSize = CGSizeZero;
NSString *closestUrl = nil;
for (std::vector<TGImageSizeRecord>::iterator it = sizes.begin(); it != sizes.end(); it++)
{
if (closestUrl == nil)
{
closestUrl = it->url;
closestSize = it->size;
}
else
{
if (ABS(width - it->size.width) < ABS(width - closestSize.width))
{
closestUrl = it->url;
closestSize = it->size;
}
}
}
if (resultingSize != NULL)
*resultingSize = closestSize;
return closestUrl;
}
- (NSString *)closestImageUrlWithHeight:(int)height resultingSize:(CGSize *)resultingSize
{
CGSize closestSize = CGSizeZero;
NSString *closestUrl = nil;
for (std::vector<TGImageSizeRecord>::iterator it = sizes.begin(); it != sizes.end(); it++)
{
if (closestUrl == nil)
{
closestUrl = it->url;
closestSize = it->size;
}
else
{
if (ABS(height - it->size.height) < ABS(height - closestSize.height))
{
closestUrl = it->url;
closestSize = it->size;
}
}
}
if (resultingSize != NULL)
*resultingSize = closestSize;
return closestUrl;
}
- (NSString *)closestImageUrlWithSize:(CGSize)size resultingSize:(CGSize *)resultingSize
{
return [self closestImageUrlWithSize:size resultingSize:resultingSize pickLargest:false];
}
- (NSString *)closestImageUrlWithSize:(CGSize)size resultingSize:(CGSize *)resultingSize resultingFileSize:(int *)resultingFileSize
{
return [self closestImageUrlWithSize:size resultingSize:resultingSize resultingFileSize:resultingFileSize pickLargest:false];
}
- (NSString *)closestImageUrlWithSize:(CGSize)size resultingSize:(CGSize *)resultingSize pickLargest:(bool)pickLargest
{
return [self closestImageUrlWithSize:size resultingSize:resultingSize resultingFileSize:NULL pickLargest:pickLargest];
}
- (NSString *)closestImageUrlWithSize:(CGSize)size resultingSize:(CGSize *)resultingSize resultingFileSize:(int *)resultingFileSize pickLargest:(bool)pickLargest
{
CGSize closestSize = CGSizeZero;
int closestFileSize = 0;
CGFloat closestDeltaSquared = FLT_MAX;
NSString *closestUrl = nil;
for (std::vector<TGImageSizeRecord>::iterator it = sizes.begin(); it != sizes.end(); it++)
{
CGFloat deltaWidth = ABS(size.width - it->size.width);
CGFloat deltaHeight = ABS(size.height - it->size.height);
CGFloat currentDeltaSquared = deltaWidth * deltaWidth + deltaHeight * deltaHeight;
if (closestUrl == nil || currentDeltaSquared < closestDeltaSquared || (pickLargest && currentDeltaSquared <= closestDeltaSquared + FLT_EPSILON))
{
closestUrl = it->url;
closestSize = it->size;
closestFileSize = it->fileSize;
closestDeltaSquared = deltaWidth * deltaWidth + deltaHeight * deltaHeight;
}
}
if (resultingSize != NULL)
*resultingSize = closestSize;
if (resultingFileSize != NULL)
*resultingFileSize = closestFileSize;
return closestUrl;
}
- (NSString *)imageUrlWithExactSize:(CGSize)size
{
for (std::vector<TGImageSizeRecord>::iterator it = sizes.begin(); it != sizes.end(); it++)
{
CGFloat deltaWidth = ABS(size.width - it->size.width);
CGFloat deltaHeight = ABS(size.height - it->size.height);
if (deltaWidth < 1 + FLT_EPSILON && deltaHeight < 1 + FLT_EPSILON)
{
return it->url;
}
}
return nil;
}
- (NSString *)imageUrlForLargestSize:(CGSize *)actualSize
{
NSString *largestUrl = nil;
CGSize largestSize = CGSizeZero;
for (auto it = sizes.begin(); it != sizes.end(); it++)
{
if (it->size.width > largestSize.width)
{
largestUrl = it->url;
largestSize = it->size;
}
}
if (actualSize != NULL)
*actualSize = largestSize;
return largestUrl;
}
- (NSString *)imageUrlForSizeLargerThanSize:(CGSize)size actualSize:(CGSize *)actualSize
{
NSString *largestUrl = nil;
CGSize largestSize = CGSizeZero;
for (auto it = sizes.begin(); it != sizes.end(); it++)
{
if (it->size.width > size.width && (largestUrl == nil || it->size.width < largestSize.width))
{
largestUrl = it->url;
largestSize = it->size;
break;
}
}
if (largestUrl == nil)
largestUrl = [self closestImageUrlWithSize:size resultingSize:actualSize pickLargest:true];
else if (actualSize)
*actualSize = largestSize;
return largestUrl;
}
- (bool)containsSizeWithUrl:(NSString *)url
{
if (url == nil)
return false;
for (std::vector<TGImageSizeRecord>::iterator it = sizes.begin(); it != sizes.end(); it++)
{
if ([url isEqualToString:it->url])
return true;
}
return false;
}
- (NSDictionary *)allSizes
{
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
for (std::vector<TGImageSizeRecord>::iterator it = sizes.begin(); it != sizes.end(); it++)
{
[dict setObject:[NSValue valueWithCGSize:it->size] forKey:it->url];
}
return dict;
}
- (bool)empty
{
return sizes.empty();
}
- (void)serialize:(NSMutableData *)data
{
int writtenCount = (int)sizes.size();
writtenCount |= (1 << 31);
[data appendBytes:&writtenCount length:4];
uint16_t version = 1;
[data appendBytes:&version length:2];
for (std::vector<TGImageSizeRecord>::iterator it = sizes.begin(); it != sizes.end(); it++)
{
NSData *urlData = [it->url dataUsingEncoding:NSUTF8StringEncoding];
int length = (int)urlData.length;
[data appendBytes:&length length:4];
[data appendData:urlData];
float width = (float)it->size.width;
float height = (float)it->size.height;
[data appendBytes:&width length:4];
[data appendBytes:&height length:4];
[data appendBytes:&it->fileSize length:4];
}
}
+ (TGImageInfo *)deserialize:(NSInputStream *)is
{
TGImageInfo *info = [[TGImageInfo alloc] init];
uint16_t version = 0;
int count = 0;
[is read:(uint8_t *)&count maxLength:4];
if (count & (1 << 31))
{
count &= ~(1 << 31);
[is read:(uint8_t *)&version maxLength:2];
}
for (int i = 0; i < count; i++)
{
int length = 0;
[is read:(uint8_t *)&length maxLength:4];
uint8_t *urlBytes = (uint8_t *)malloc(length);
[is read:urlBytes maxLength:length];
NSString *url = [[NSString alloc] initWithBytesNoCopy:urlBytes length:length encoding:NSUTF8StringEncoding freeWhenDone:true];
float sizeWidth = 0.0f;
float sizeHeight = 0.0f;
[is read:(uint8_t *)&sizeWidth maxLength:4];
[is read:(uint8_t *)&sizeHeight maxLength:4];
int fileSize = 0;
if (version >= 1)
[is read:(uint8_t *)&fileSize maxLength:4];
[info addImageWithSize:CGSizeMake(sizeWidth, sizeHeight) url:url fileSize:fileSize];
}
return info;
}
@end