VLCThumbnailsCache.m 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. /*****************************************************************************
  2. * VLCThumbnailsCache.m
  3. * VLC for iOS
  4. *****************************************************************************
  5. * Copyright (c) 2013-2014 VideoLAN. All rights reserved.
  6. * $Id$
  7. *
  8. * Authors: Gleb Pinigin <gpinigin # gmail.com>
  9. * Felix Paul Kühne <fkuehne # videolan.org>
  10. *
  11. * Refer to the COPYING file of the official project for license.
  12. *****************************************************************************/
  13. #import "VLCThumbnailsCache.h"
  14. #import <CommonCrypto/CommonDigest.h>
  15. static NSInteger MaxCacheSize;
  16. static NSCache *_thumbnailCache;
  17. @implementation VLCThumbnailsCache
  18. #define MAX_CACHE_SIZE_IPHONE 21 // three times the number of items shown on iPhone 5
  19. #define MAX_CACHE_SIZE_IPAD 27 // three times the number of items shown on iPad
  20. +(void)initialize
  21. {
  22. MaxCacheSize = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)?
  23. MAX_CACHE_SIZE_IPAD: MAX_CACHE_SIZE_IPHONE;
  24. _thumbnailCache = [[NSCache alloc] init];
  25. [_thumbnailCache setCountLimit: MaxCacheSize];
  26. }
  27. + (NSString *)_md5FromString:(NSString *)string
  28. {
  29. const char *ptr = [string UTF8String];
  30. unsigned char md5Buffer[CC_MD5_DIGEST_LENGTH];
  31. CC_MD5(ptr, (unsigned int)strlen(ptr), md5Buffer);
  32. NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
  33. for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++)
  34. [output appendFormat:@"%02x",md5Buffer[i]];
  35. return [NSString stringWithString:output];
  36. }
  37. + (UIImage *)thumbnailForMediaItemWithTitle:(NSString *)title Artist:(NSString*)artist andAlbumName:(NSString*)albumname
  38. {
  39. return [UIImage imageWithContentsOfFile:[self artworkPathForMediaItemWithTitle:title Artist:artist andAlbumName:albumname]];
  40. }
  41. + (NSString *)artworkPathForMediaItemWithTitle:(NSString *)title Artist:(NSString*)artist andAlbumName:(NSString*)albumname
  42. {
  43. NSString *artworkURL;
  44. NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
  45. NSString *cacheDir = searchPaths[0];
  46. cacheDir = [cacheDir stringByAppendingFormat:@"/%@", [[NSBundle mainBundle] bundleIdentifier]];
  47. if (artist.length == 0 || albumname.length == 0) {
  48. /* Use generated hash to find art */
  49. artworkURL = [cacheDir stringByAppendingFormat:@"/art/arturl/%@/art.jpg", [self _md5FromString:title]];
  50. } else {
  51. /* Otherwise, it was cached by artist and album */
  52. artworkURL = [cacheDir stringByAppendingFormat:@"/art/artistalbum/%@/%@/art.jpg", artist, albumname];
  53. }
  54. return artworkURL;
  55. }
  56. + (NSString *)_getArtworkPathFromMedia:(MLFile *)file
  57. {
  58. NSString *artist, *album, *title;
  59. if (file.isAlbumTrack) {
  60. artist = file.albumTrack.artist;
  61. album = file.albumTrack.album.name;
  62. }
  63. title = file.title;
  64. return [self artworkPathForMediaItemWithTitle:title Artist:artist andAlbumName:album];
  65. }
  66. + (UIImage *)thumbnailForMediaFile:(MLFile *)mediaFile
  67. {
  68. if (mediaFile == nil || mediaFile.objectID == nil)
  69. return nil;
  70. NSManagedObjectID *objID = mediaFile.objectID;
  71. UIImage *displayedImage = [_thumbnailCache objectForKey:objID];
  72. if (displayedImage)
  73. return displayedImage;
  74. if (mediaFile.isAlbumTrack || mediaFile.isShowEpisode)
  75. displayedImage = [UIImage imageWithContentsOfFile:[self _getArtworkPathFromMedia:mediaFile]];
  76. if (!displayedImage)
  77. displayedImage = mediaFile.computedThumbnail;
  78. if (displayedImage)
  79. [_thumbnailCache setObject:displayedImage forKey:objID];
  80. return displayedImage;
  81. }
  82. + (UIImage *)thumbnailForLabel:(MLLabel *)mediaLabel
  83. {
  84. NSManagedObjectID *objID = mediaLabel.objectID;
  85. UIImage *displayedImage = [_thumbnailCache objectForKey:objID];
  86. if (displayedImage)
  87. return displayedImage;
  88. NSUInteger fileNumber = [mediaLabel.files count] > 3 ? 3 : [mediaLabel.files count];
  89. NSArray *files = [mediaLabel.files allObjects];
  90. CGSize imageSize;
  91. if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
  92. if ([UIScreen mainScreen].scale==2.0)
  93. imageSize = CGSizeMake(540., 405.);
  94. else
  95. imageSize = CGSizeMake(272, 204.);
  96. } else {
  97. if (SYSTEM_RUNS_IOS7_OR_LATER)
  98. imageSize = CGSizeMake(480., 270.);
  99. else {
  100. if ([UIScreen mainScreen].scale==2.0)
  101. imageSize = CGSizeMake(480., 270.);
  102. else
  103. imageSize = CGSizeMake(540., 405.);
  104. }
  105. }
  106. UIGraphicsBeginImageContext(imageSize);
  107. for (NSUInteger i = 0; i < fileNumber; i++) {
  108. MLFile *file = [files objectAtIndex:i];
  109. displayedImage = [VLCThumbnailsCache thumbnailForMediaFile:file];
  110. CGContextRef context = UIGraphicsGetCurrentContext();
  111. CGFloat imagePartWidth = (imageSize.width / fileNumber);
  112. //the rect in which the image should be drawn
  113. CGRect clippingRect = CGRectMake(imagePartWidth * i, 0, imagePartWidth, imageSize.height);
  114. CGContextSaveGState(context);
  115. CGContextClipToRect(context, clippingRect);
  116. //take the center of the clippingRect and calculate the offset from the original center
  117. CGFloat centerOffset = (imagePartWidth * i + imagePartWidth / 2) - imageSize.width / 2;
  118. //shift the rect to draw the middle of the image in the clippingrect
  119. CGRect drawingRect = CGRectMake(centerOffset, 0, imageSize.width, imageSize.height);
  120. [displayedImage drawInRect:drawingRect];
  121. //get rid of the old clippingRect
  122. CGContextRestoreGState(context);
  123. }
  124. displayedImage = UIGraphicsGetImageFromCurrentImageContext();
  125. UIGraphicsEndImageContext();
  126. [_thumbnailCache setObject:displayedImage forKey:objID];
  127. return displayedImage;
  128. }
  129. @end