Skip to content

Commit 37e59e3

Browse files
author
Mallory Paine
committed
Support for 16-bit color and 8 bit grayscale thumbnails
1 parent 209ec52 commit 37e59e3

File tree

5 files changed

+100
-36
lines changed

5 files changed

+100
-36
lines changed

FastImageCache/FICImageFormat.h

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ typedef NS_OPTIONS(NSUInteger, FICImageFormatDevices) {
2020
All images associated with a particular format must have the same image dimentions and opacity preference. You can define the maximum number of entries that an image format can accommodate to
2121
prevent the image cache from consuming too much disk space. Each `<FICImageTable>` managed by the image cache is associated with a single image format.
2222
*/
23+
24+
25+
typedef NS_OPTIONS(NSUInteger, FICImageFormatStyle) {
26+
FICImageFormatStyle32BitBGRA,
27+
FICImageFormatStyle16BitBGR,
28+
FICImageFormatStyle8BitGrayscale,
29+
};
30+
2331
@interface FICImageFormat : NSObject <NSCopying>
2432

2533
///------------------------------
@@ -56,10 +64,12 @@ typedef NS_OPTIONS(NSUInteger, FICImageFormatDevices) {
5664
*/
5765
@property (nonatomic, assign, readonly) CGSize pixelSize;
5866

59-
/**
60-
Whether or not the bitmap of the image table created by this format needs to include an alpha channel.
61-
*/
62-
@property (nonatomic, assign, getter = isOpaque) BOOL opaque;
67+
@property (nonatomic, assign) FICImageFormatStyle style;
68+
69+
@property (nonatomic, readonly) CGBitmapInfo bitmapInfo;
70+
@property (nonatomic, readonly) NSInteger bytesPerPixel;
71+
@property (nonatomic, readonly) NSInteger bitsPerComponent;
72+
@property (nonatomic, readonly) BOOL isGrayscale;
6373

6474
/**
6575
The maximum number of entries that an image table can contain for this image format.
@@ -103,6 +113,6 @@ typedef NS_OPTIONS(NSUInteger, FICImageFormatDevices) {
103113
104114
@return An autoreleased instance of `<FICImageFormat>` or one of its subclasses, if any exist.
105115
*/
106-
+ (instancetype)formatWithName:(NSString *)name family:(NSString *)family imageSize:(CGSize)imageSize isOpaque:(BOOL)isOpaque maximumCount:(NSInteger)maximumCount devices:(FICImageFormatDevices)devices;
116+
+ (instancetype)formatWithName:(NSString *)name family:(NSString *)family imageSize:(CGSize)imageSize style:(FICImageFormatStyle)style maximumCount:(NSInteger)maximumCount devices:(FICImageFormatDevices)devices;
107117

108118
@end

FastImageCache/FICImageFormat.m

Lines changed: 67 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
static NSString *const FICImageFormatFamilyKey = @"family";
1717
static NSString *const FICImageFormatWidthKey = @"width";
1818
static NSString *const FICImageFormatHeightKey = @"height";
19-
static NSString *const FICImageFormatIsOpaqueKey = @"isOpaque";
19+
static NSString *const FICImageFormatStyleKey = @"style";
2020
static NSString *const FICImageFormatMaximumCountKey = @"maximumCount";
2121
static NSString *const FICImageFormatDevicesKey = @"devices";
2222

@@ -27,7 +27,7 @@ @interface FICImageFormat () {
2727
NSString *_family;
2828
CGSize _imageSize;
2929
CGSize _pixelSize;
30-
BOOL _isOpaque;
30+
FICImageFormatStyle _style;
3131
NSInteger _maximumCount;
3232
FICImageFormatDevices _devices;
3333
}
@@ -42,7 +42,7 @@ @implementation FICImageFormat
4242
@synthesize family = _family;
4343
@synthesize imageSize = _imageSize;
4444
@synthesize pixelSize = _pixelSize;
45-
@synthesize opaque = _isOpaque;
45+
@synthesize style = _style;
4646
@synthesize maximumCount = _maximumCount;
4747
@synthesize devices = _devices;
4848

@@ -58,15 +58,75 @@ - (void)setImageSize:(CGSize)imageSize {
5858
}
5959
}
6060

61+
- (CGBitmapInfo)bitmapInfo {
62+
CGBitmapInfo info;
63+
switch (_style) {
64+
case FICImageFormatStyle32BitBGRA:
65+
info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
66+
break;
67+
case FICImageFormatStyle16BitBGR:
68+
info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder16Host;
69+
break;
70+
case FICImageFormatStyle8BitGrayscale:
71+
info = (CGBitmapInfo)kCGImageAlphaNone;
72+
break;
73+
}
74+
return info;
75+
}
76+
77+
- (NSInteger)bytesPerPixel {
78+
NSInteger bytesPerPixel;
79+
switch (_style) {
80+
case FICImageFormatStyle32BitBGRA:
81+
bytesPerPixel = 4;
82+
break;
83+
case FICImageFormatStyle16BitBGR:
84+
bytesPerPixel = 2;
85+
break;
86+
case FICImageFormatStyle8BitGrayscale:
87+
bytesPerPixel = 1;
88+
break;
89+
}
90+
return bytesPerPixel;
91+
}
92+
93+
- (NSInteger)bitsPerComponent {
94+
NSInteger bitsPerComponent;
95+
switch (_style) {
96+
case FICImageFormatStyle32BitBGRA:
97+
case FICImageFormatStyle8BitGrayscale:
98+
bitsPerComponent = 8;
99+
break;
100+
case FICImageFormatStyle16BitBGR:
101+
bitsPerComponent = 5;
102+
break;
103+
}
104+
return bitsPerComponent;
105+
}
106+
107+
- (BOOL)isGrayscale {
108+
BOOL isGrayscale;
109+
switch (_style) {
110+
case FICImageFormatStyle32BitBGRA:
111+
case FICImageFormatStyle16BitBGR:
112+
isGrayscale = NO;
113+
break;
114+
case FICImageFormatStyle8BitGrayscale:
115+
isGrayscale = YES;
116+
break;
117+
}
118+
return isGrayscale;
119+
}
120+
61121
#pragma mark - Object Lifecycle
62122

63-
+ (instancetype)formatWithName:(NSString *)name family:(NSString *)family imageSize:(CGSize)imageSize isOpaque:(BOOL)isOpaque maximumCount:(NSInteger)maximumCount devices:(FICImageFormatDevices)devices {
123+
+ (instancetype)formatWithName:(NSString *)name family:(NSString *)family imageSize:(CGSize)imageSize style:(FICImageFormatStyle)style maximumCount:(NSInteger)maximumCount devices:(FICImageFormatDevices)devices {
64124
FICImageFormat *imageFormat = [[FICImageFormat alloc] init];
65125

66126
[imageFormat setName:name];
67127
[imageFormat setFamily:family];
68128
[imageFormat setImageSize:imageSize];
69-
[imageFormat setOpaque:isOpaque];
129+
[imageFormat setStyle:style];
70130
[imageFormat setMaximumCount:maximumCount];
71131
[imageFormat setDevices:devices];
72132

@@ -82,7 +142,7 @@ - (NSDictionary *)dictionaryRepresentation {
82142
[dictionaryRepresentation setValue:_family forKey:FICImageFormatFamilyKey];
83143
[dictionaryRepresentation setValue:[NSNumber numberWithUnsignedInteger:_imageSize.width] forKey:FICImageFormatWidthKey];
84144
[dictionaryRepresentation setValue:[NSNumber numberWithUnsignedInteger:_imageSize.height] forKey:FICImageFormatHeightKey];
85-
[dictionaryRepresentation setValue:[NSNumber numberWithBool:_isOpaque] forKey:FICImageFormatIsOpaqueKey];
145+
[dictionaryRepresentation setValue:[NSNumber numberWithInt:_style] forKey:FICImageFormatStyleKey];
86146
[dictionaryRepresentation setValue:[NSNumber numberWithUnsignedInteger:_maximumCount] forKey:FICImageFormatMaximumCountKey];
87147
[dictionaryRepresentation setValue:[NSNumber numberWithInt:_devices] forKey:FICImageFormatDevicesKey];
88148
[dictionaryRepresentation setValue:[NSNumber numberWithFloat:[[UIScreen mainScreen] scale]] forKey:FICImageTableScreenScaleKey];
@@ -101,7 +161,7 @@ - (id)copyWithZone:(NSZone *)zone {
101161
[imageFormatCopy setName:[self name]];
102162
[imageFormatCopy setFamily:[self family]];
103163
[imageFormatCopy setImageSize:[self imageSize]];
104-
[imageFormatCopy setOpaque:[self isOpaque]];
164+
[imageFormatCopy setStyle:[self style]];
105165
[imageFormatCopy setMaximumCount:[self maximumCount]];
106166
[imageFormatCopy setDevices:[self devices]];
107167

FastImageCache/FICImageTable.m

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,10 @@ - (instancetype)initWithFormat:(FICImageFormat *)imageFormat {
132132

133133
_screenScale = [[UIScreen mainScreen] scale];
134134

135-
int bytesPerPixel = 4;
136-
_imageRowLength = FICByteAlignForCoreAnimation([_imageFormat pixelSize].width * bytesPerPixel);
137-
_imageLength = _imageRowLength * (NSInteger)[_imageFormat pixelSize].height;
135+
CGSize pixelSize = [_imageFormat pixelSize];
136+
NSInteger bytesPerPixel = [_imageFormat bytesPerPixel];
137+
_imageRowLength = FICByteAlignForCoreAnimation(pixelSize.width * bytesPerPixel);
138+
_imageLength = _imageRowLength * (NSInteger)pixelSize.height;
138139

139140
_chunkMapTable = [NSMapTable mapTableWithKeyOptions:NSMapTableStrongMemory valueOptions:NSMapTableWeakMemory];
140141

@@ -259,21 +260,16 @@ - (void)setEntryForEntityUUID:(NSString *)entityUUID sourceImageUUID:(NSString *
259260

260261
if (newEntryIndex < _entryCount) {
261262
CGSize pixelSize = [_imageFormat pixelSize];
262-
CGBitmapInfo bitmapInfo;
263-
if ([_imageFormat isOpaque]) {
264-
bitmapInfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host;
265-
} else {
266-
bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
267-
}
268-
269-
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
263+
CGBitmapInfo bitmapInfo = [_imageFormat bitmapInfo];
264+
CGColorSpaceRef colorSpace = [_imageFormat isGrayscale] ? CGColorSpaceCreateDeviceGray() : CGColorSpaceCreateDeviceRGB();
265+
NSInteger bitsPerComponent = [_imageFormat bitsPerComponent];
270266

271267
// Create context whose backing store *is* the mapped file data
272268
FICImageTableEntry *entryData = [self _entryDataAtIndex:newEntryIndex];
273-
CGContextRef context = CGBitmapContextCreate([entryData bytes], pixelSize.width, pixelSize.height, 8, _imageRowLength, colorSpace, bitmapInfo);
269+
CGContextRef context = CGBitmapContextCreate([entryData bytes], pixelSize.width, pixelSize.height, bitsPerComponent, _imageRowLength, colorSpace, bitmapInfo);
274270
CGColorSpaceRelease(colorSpace);
275271

276-
CGContextTranslateCTM(context, 0, [_imageFormat pixelSize].height);
272+
CGContextTranslateCTM(context, 0, pixelSize.height);
277273
CGContextScaleCTM(context, _screenScale, -_screenScale);
278274

279275
// Call drawing block to allow client to draw into the context
@@ -321,18 +317,15 @@ - (UIImage *)newImageForEntityUUID:(NSString *)entityUUID sourceImageUUID:(NSStr
321317
[self _entryWasAccessedWithEntityUUID:entityUUID];
322318

323319
// Create CGImageRef whose backing store *is* the mapped image table entry. We avoid a memcpy this way.
324-
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
325320
CGDataProviderRef dataProvider = CGDataProviderCreateWithData((__bridge_retained void *)entryData, [entryData bytes], [entryData imageLength], _FICReleaseImageData);
326321

327322
CGSize pixelSize = [_imageFormat pixelSize];
328-
CGBitmapInfo bitmapInfo;
329-
if ([_imageFormat isOpaque]) {
330-
bitmapInfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host;
331-
} else {
332-
bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
333-
}
334-
335-
CGImageRef imageRef = CGImageCreate(pixelSize.width, pixelSize.height, 8, 32, _imageRowLength, colorSpace, bitmapInfo, dataProvider, NULL, false, (CGColorRenderingIntent)0);
323+
CGBitmapInfo bitmapInfo = [_imageFormat bitmapInfo];
324+
NSInteger bitsPerComponent = [_imageFormat bitsPerComponent];
325+
NSInteger bitsPerPixel = [_imageFormat bytesPerPixel] * 8;
326+
CGColorSpaceRef colorSpace = [_imageFormat isGrayscale] ? CGColorSpaceCreateDeviceGray() : CGColorSpaceCreateDeviceRGB();
327+
328+
CGImageRef imageRef = CGImageCreate(pixelSize.width, pixelSize.height, bitsPerComponent, bitsPerPixel, _imageRowLength, colorSpace, bitmapInfo, dataProvider, NULL, false, (CGColorRenderingIntent)0);
336329
CGDataProviderRelease(dataProvider);
337330
CGColorSpaceRelease(colorSpace);
338331

FastImageCacheDemo/Classes/FICDAppDelegate.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
3030
NSInteger squareImageFormatMaximumCount = 400;
3131
FICImageFormatDevices squareImageFormatDevices = FICImageFormatDevicePhone | FICImageFormatDevicePad;
3232

33-
FICImageFormat *squareImageFormat = [FICImageFormat formatWithName:FICDPhotoSquareImageFormatName family:FICDPhotoImageFormatFamily imageSize:FICDPhotoSquareImageSize isOpaque:NO
33+
FICImageFormat *squareImageFormat = [FICImageFormat formatWithName:FICDPhotoSquareImageFormatName family:FICDPhotoImageFormatFamily imageSize:FICDPhotoSquareImageSize style:FICImageFormatStyle32BitBGRA
3434
maximumCount:squareImageFormatMaximumCount devices:squareImageFormatDevices];
3535

3636
[mutableImageFormats addObject:squareImageFormat];
@@ -40,7 +40,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
4040
NSInteger pixelImageFormatMaximumCount = 1000;
4141
FICImageFormatDevices pixelImageFormatDevices = FICImageFormatDevicePhone | FICImageFormatDevicePad;
4242

43-
FICImageFormat *pixelImageFormat = [FICImageFormat formatWithName:FICDPhotoPixelImageFormatName family:FICDPhotoImageFormatFamily imageSize:FICDPhotoPixelImageSize isOpaque:YES
43+
FICImageFormat *pixelImageFormat = [FICImageFormat formatWithName:FICDPhotoPixelImageFormatName family:FICDPhotoImageFormatFamily imageSize:FICDPhotoPixelImageSize style:FICImageFormatStyle32BitBGRA
4444
maximumCount:pixelImageFormatMaximumCount devices:pixelImageFormatDevices];
4545

4646
[mutableImageFormats addObject:pixelImageFormat];

FastImageCacheDemo/FastImageCacheDemo.xcodeproj/project.pbxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@
324324
ASSETCATALOG_COMPILER_APPICON_NAME = Icon;
325325
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = "Launch Image";
326326
"CODE_SIGN_IDENTITY[sdk=iphonesimulator*]" = "";
327+
GCC_OPTIMIZATION_LEVEL = 0;
327328
GCC_PRECOMPILE_PREFIX_HEADER = YES;
328329
GCC_PREFIX_HEADER = "Supporting Files/FastImageCacheDemo-Prefix.pch";
329330
INFOPLIST_FILE = "$(SRCROOT)/Supporting Files/FastImageCacheDemo-Info.plist";

0 commit comments

Comments
 (0)