Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: refactor iOS project, add async compress() API #337

Open
wants to merge 4 commits into
base: stable
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 33 additions & 25 deletions ios/Classes/TiImagefactoryModule.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,17 @@ @implementation TiImagefactoryModule

#pragma mark Internal

// this is generated for your module, please do not change it
- (id)moduleGUID
{
return @"0aab25d7-0486-40ab-94a3-ed4f9a293414";
}

// this is generated for your module, please do not change it
- (NSString *)moduleId
{
return @"ti.imagefactory";
}

#pragma mark Lifecycle

- (void)startup
{
// this method is called when the module is first loaded
// you *must* call the superclass
[super startup];

NSLog(@"[DEBUG] %@ loaded", self);
}

#pragma system properties
#pragma System Properties

typedef enum {
kTransformNone = 0,
Expand Down Expand Up @@ -184,24 +171,45 @@ - (id)imageTransform:(id)args

- (id)compress:(id)args
{
TiBlob *blob;
NSNumber *qualityObject;
ENSURE_ARG_AT_INDEX(blob, args, 0, TiBlob);
ENSURE_ARG_AT_INDEX(qualityObject, args, 1, NSNumber);
if (![args[0] isKindOfClass:[NSDictionary class]]) {
DEPRECATED_REPLACED(@"ImageFactory.compress(file, quality)", @"3.0.0", @"ImageFactory.compress({ file, quality, callback })");

UIImage *image = [blob image];
image = [TiImageFactory imageUpright:image];
TiBlob *blob = nil;
NSNumber *qualityObject = @-1;
ENSURE_ARG_AT_INDEX(blob, args, 0, TiBlob);
ENSURE_ARG_AT_INDEX(qualityObject, args, 1, NSNumber);

UIImage *image = [blob image];
image = [TiImageFactory imageUpright:image];

float qualityValue = [TiUtils floatValue:qualityObject def:1.0];
return [[[TiBlob alloc] initWithData:UIImageJPEGRepresentation(image, qualityValue) mimetype:@"image/jpeg"] autorelease];
}

ENSURE_SINGLE_ARG(args, NSDictionary);

dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
TiBlob *blob = args[@"file"];
float quality = [TiUtils floatValue:@"quality" properties:args def:1.0];
KrollCallback *callback = args[@"callback"];

UIImage *image = [TiImageFactory imageUpright:[blob image]];
TiBlob *result = [[[TiBlob alloc] initWithData:UIImageJPEGRepresentation(image, quality) mimetype:@"image/jpeg"] autorelease];

float qualityValue = [TiUtils floatValue:qualityObject def:1.0];
return [[[TiBlob alloc] initWithData:UIImageJPEGRepresentation(image, qualityValue) mimetype:@"image/jpeg"] autorelease];
TiThreadPerformOnMainThread(
^{
[callback call:@[ @{ @"file" : result } ] thisObject:self];
},
NO);
});
}

- (id)compressToFile:(id)args
{
// Fetch arguments.
TiBlob *blob;
NSNumber *qualityObject;
NSString *filePath;
TiBlob *blob = nil;
NSNumber *qualityObject = @-1;
NSString *filePath = nil;
ENSURE_ARG_AT_INDEX(blob, args, 0, TiBlob);
ENSURE_ARG_AT_INDEX(qualityObject, args, 1, NSNumber);
ENSURE_ARG_AT_INDEX(filePath, args, 2, NSString);
Expand Down
4 changes: 3 additions & 1 deletion ios/Classes/TiImagefactoryModuleAssets.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@
*/
#import "TiImagefactoryModuleAssets.h"

extern NSData *filterDataInRange(NSData *thedata, NSRange range);
extern NSData* filterDataInRange(NSData* thedata, NSRange range);

@implementation TiImagefactoryModuleAssets

- (NSData *)moduleAsset
{


return nil;
}

- (NSData *)resolveModuleAsset:(NSString *)path
{


return nil;
}
Expand Down
198 changes: 98 additions & 100 deletions ios/Classes/UIImage/TiUIImage+Alpha.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,121 +8,119 @@
@implementation TiUIImageAlpha

// Returns true if the image has an alpha layer
+ (BOOL)hasAlpha:(UIImage*)image {
CGImageAlphaInfo alpha = CGImageGetAlphaInfo(image.CGImage);
return (alpha == kCGImageAlphaFirst ||
alpha == kCGImageAlphaLast ||
alpha == kCGImageAlphaPremultipliedFirst ||
alpha == kCGImageAlphaPremultipliedLast);
+ (BOOL)hasAlpha:(UIImage *)image
{
CGImageAlphaInfo alpha = CGImageGetAlphaInfo(image.CGImage);
return (alpha == kCGImageAlphaFirst || alpha == kCGImageAlphaLast || alpha == kCGImageAlphaPremultipliedFirst || alpha == kCGImageAlphaPremultipliedLast);
}

// Returns a copy of the given image, adding an alpha channel if it doesn't already have one
+ (UIImage *)imageWithAlpha:(UIImage*)image {
if ([TiUIImageAlpha hasAlpha:image]) {
return image;
}

CGImageRef imageRef = image.CGImage;
size_t width = CGImageGetWidth(imageRef);
size_t height = CGImageGetHeight(imageRef);

// The bitsPerComponent and bitmapInfo values are hard-coded to prevent an "unsupported parameter combination" error
CGContextRef offscreenContext = CGBitmapContextCreate(NULL,
width,
height,
8,
0,
CGImageGetColorSpace(imageRef),
kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst);

// Draw the image into the context and retrieve the new image, which will now have an alpha layer
CGContextDrawImage(offscreenContext, CGRectMake(0, 0, width, height), imageRef);
CGImageRef imageRefWithAlpha = CGBitmapContextCreateImage(offscreenContext);
UIImage *imageWithAlpha = [UIImage imageWithCGImage:imageRefWithAlpha];

// Clean up
CGContextRelease(offscreenContext);
CGImageRelease(imageRefWithAlpha);

return imageWithAlpha;
+ (UIImage *)imageWithAlpha:(UIImage *)image
{
if ([TiUIImageAlpha hasAlpha:image]) {
return image;
}

CGImageRef imageRef = image.CGImage;
size_t width = CGImageGetWidth(imageRef);
size_t height = CGImageGetHeight(imageRef);

// The bitsPerComponent and bitmapInfo values are hard-coded to prevent an "unsupported parameter combination" error
CGContextRef offscreenContext = CGBitmapContextCreate(NULL,
width,
height,
8,
0,
CGImageGetColorSpace(imageRef),
kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst);

// Draw the image into the context and retrieve the new image, which will now have an alpha layer
CGContextDrawImage(offscreenContext, CGRectMake(0, 0, width, height), imageRef);
CGImageRef imageRefWithAlpha = CGBitmapContextCreateImage(offscreenContext);
UIImage *imageWithAlpha = [UIImage imageWithCGImage:imageRefWithAlpha];

// Clean up
CGContextRelease(offscreenContext);
CGImageRelease(imageRefWithAlpha);

return imageWithAlpha;
}

// Creates a mask that makes the outer edges transparent and everything else opaque
// The size must include the entire mask (opaque part + transparent border)
// The caller is responsible for releasing the returned reference by calling CGImageRelease
+ (CGImageRef)newBorderMask:(NSUInteger)borderSize size:(CGSize)size image:(UIImage*)image
+ (CGImageRef)newBorderMask:(NSUInteger)borderSize size:(CGSize)size image:(UIImage *)image
{
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();

// Build a context that's the same dimensions as the new size
CGContextRef maskContext = CGBitmapContextCreate(NULL,
size.width,
size.height,
8, // 8-bit grayscale
0,
colorSpace,
kCGBitmapByteOrderDefault | kCGImageAlphaNone);

// Start with a mask that's entirely transparent
CGContextSetFillColorWithColor(maskContext, [UIColor blackColor].CGColor);
CGContextFillRect(maskContext, CGRectMake(0, 0, size.width, size.height));

// Make the inner part (within the border) opaque
CGContextSetFillColorWithColor(maskContext, [UIColor whiteColor].CGColor);
CGContextFillRect(maskContext, CGRectMake(borderSize, borderSize, size.width - borderSize * 2, size.height - borderSize * 2));

// Get an image of the context
CGImageRef maskImageRef = CGBitmapContextCreateImage(maskContext);

// Clean up
CGContextRelease(maskContext);
CGColorSpaceRelease(colorSpace);

return maskImageRef;
}
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();

// Build a context that's the same dimensions as the new size
CGContextRef maskContext = CGBitmapContextCreate(NULL,
size.width,
size.height,
8, // 8-bit grayscale
0,
colorSpace,
kCGBitmapByteOrderDefault | kCGImageAlphaNone);

// Start with a mask that's entirely transparent
CGContextSetFillColorWithColor(maskContext, [UIColor blackColor].CGColor);
CGContextFillRect(maskContext, CGRectMake(0, 0, size.width, size.height));

// Make the inner part (within the border) opaque
CGContextSetFillColorWithColor(maskContext, [UIColor whiteColor].CGColor);
CGContextFillRect(maskContext, CGRectMake(borderSize, borderSize, size.width - borderSize * 2, size.height - borderSize * 2));

// Get an image of the context
CGImageRef maskImageRef = CGBitmapContextCreateImage(maskContext);

// Clean up
CGContextRelease(maskContext);
CGColorSpaceRelease(colorSpace);

return maskImageRef;
}

// Returns a copy of the image with a transparent border of the given size added around its edges.
// If the image has no alpha layer, one will be added to it.
+ (UIImage *)transparentBorderImage:(NSUInteger)borderSize image:(UIImage*)image_{
// If the image does not have an alpha layer, add one
UIImage *image = [TiUIImageAlpha imageWithAlpha:image_];

CGRect newRect = CGRectMake(0, 0, image.size.width + borderSize * 2, image.size.height + borderSize * 2);

// Build a context that's the same dimensions as the new size
CGContextRef bitmap = CGBitmapContextCreate(NULL,
newRect.size.width,
newRect.size.height,
CGImageGetBitsPerComponent(image_.CGImage),
0,
CGImageGetColorSpace(image_.CGImage),
CGImageGetBitmapInfo(image_.CGImage));

// Draw the image in the center of the context, leaving a gap around the edges
CGRect imageLocation = CGRectMake(borderSize, borderSize, image.size.width, image.size.height);
CGContextDrawImage(bitmap, imageLocation, image_.CGImage);
CGImageRef borderImageRef = CGBitmapContextCreateImage(bitmap);

// Create a mask to make the border transparent, and combine it with the image
CGImageRef maskImageRef = [TiUIImageAlpha newBorderMask:borderSize size:newRect.size image:image_];
if((maskImageRef == NULL) || (borderImageRef == NULL))
{
CGContextRelease(bitmap);
CGImageRelease(maskImageRef);
CGImageRelease(borderImageRef);
return nil;
}
CGImageRef transparentBorderImageRef = CGImageCreateWithMask(borderImageRef, maskImageRef);
UIImage *transparentBorderImage = [UIImage imageWithCGImage:transparentBorderImageRef];

// Clean up
+ (UIImage *)transparentBorderImage:(NSUInteger)borderSize image:(UIImage *)image_
{
// If the image does not have an alpha layer, add one
UIImage *image = [TiUIImageAlpha imageWithAlpha:image_];

CGRect newRect = CGRectMake(0, 0, image.size.width + borderSize * 2, image.size.height + borderSize * 2);

// Build a context that's the same dimensions as the new size
CGContextRef bitmap = CGBitmapContextCreate(NULL,
newRect.size.width,
newRect.size.height,
CGImageGetBitsPerComponent(image_.CGImage),
0,
CGImageGetColorSpace(image_.CGImage),
CGImageGetBitmapInfo(image_.CGImage));

// Draw the image in the center of the context, leaving a gap around the edges
CGRect imageLocation = CGRectMake(borderSize, borderSize, image.size.width, image.size.height);
CGContextDrawImage(bitmap, imageLocation, image_.CGImage);
CGImageRef borderImageRef = CGBitmapContextCreateImage(bitmap);

// Create a mask to make the border transparent, and combine it with the image
CGImageRef maskImageRef = [TiUIImageAlpha newBorderMask:borderSize size:newRect.size image:image_];
if ((maskImageRef == NULL) || (borderImageRef == NULL)) {
CGContextRelease(bitmap);
CGImageRelease(borderImageRef);
CGImageRelease(maskImageRef);
CGImageRelease(transparentBorderImageRef);

return transparentBorderImage;
CGImageRelease(borderImageRef);
return nil;
}
CGImageRef transparentBorderImageRef = CGImageCreateWithMask(borderImageRef, maskImageRef);
UIImage *transparentBorderImage = [UIImage imageWithCGImage:transparentBorderImageRef];

// Clean up
CGContextRelease(bitmap);
CGImageRelease(borderImageRef);
CGImageRelease(maskImageRef);
CGImageRelease(transparentBorderImageRef);

return transparentBorderImage;
}

@end
Loading