I've been using AFNetworking for downloading UIImage async with placeholder, it works fine with JPEG and PNG, however I'm using a library for my GIF pictures. It works well when I'm doing it in sync. However I would like to use AFNetworking to download the image in async while showing a placeholder image in the ImageView. How can I do that? Thanks!
Here are my codes:
- (void) downloadAllImagesForComment
{
if (_imageLinkList.count > 0)
{
if (images == nil)
images = [[NSMutableDictionary alloc] init];
for (NSDictionary *URL in _imageLinkList) {
if ([images objectForKey:[URL objectForKey:#"link"]] == nil)
{
/*
* imageType = 0 <= other
* imageType = 1 <= gif
*/
int imageType = 0;
NSURL *url = [NSURL URLWithString:[URL objectForKey:#"link"]];
NSError *error = [[NSError alloc] init];
NSLog(#"Retrieving imageData...");
NSData *imageData = [NSData dataWithContentsOfURL:url options:NSDataReadingMappedIfSafe error:&error];
NSLog(#"Retrived imageData.");
uint8_t c;
[imageData getBytes:&c length:1];
switch (c) {
case 0xFF:
NSLog(#"image/jpeg");
imageType = 0;
break;
case 0x89:
NSLog(#"image/png");
imageType = 0;
break;
case 0x47:
NSLog(#"image/gif");
imageType = 1;
break;
case 0x49:
imageType = 0;
break;
case 0x4D:
NSLog(#"image/tiff");
imageType = 0;
break;
}
UIImageView *temp_imageView;
if (imageType == 1)
{
// GIF IMAGE SHOULD BE INITIALIZED HERE!!!!!!
// image = [UIImage animatedImageWithAnimatedGIFData:imageData];
}
else
{
temp_imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 280, 250)];
[temp_imageView setImageWithURL:url placeholderImage:[UIImage imageNamed:#"patch_la"]];
}
[images setValue:temp_imageView forKey:[URL objectForKey:#"link"]];
NSLog(#"Done downloading image: %#", [URL objectForKey:#"link"]);
}
}
}
}
I'd recommend using the SDWebImage library. It has async animated Gif support built in.
After including the library, it's simple (just have the NSURL point to the remote Gif):
[imageView setImageWithURL:[NSURL] completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType){}];
Related
I need to save multiple images in the photo library, the user can multiple selects the images from the app gallery then can save them in iPhone Photo Gallery. I am showing the UIActivityViewController for the purpose.
Suppose a user selects 10 or more images and choose to save them into photo library then only 7-8 images are saved.
Is there any way by which i can save array of images in the photo library without any failure ?
Thanks
let images = Generic.fetchImagesFromMediaFiles(self.selectedMediaObj) // to fetch selected images
let activityViewController = UIActivityViewController(activityItems: images, applicationActivities: nil)
self.present(activityViewController, animated: true, completion: nil);
if let popoverPresentationController = activityViewController.popoverPresentationController {
popoverPresentationController.sourceView = self.shareAllView
}
iOS system write photo save to album use single thread, one by one to do.
if you want to save more photos same time, it maybe loss some data.
-(void)saveBtn
{
[SSGOTools againRequestPhotoWithblock:^(BOOL isAgree) {
if (isAgree) {
self.listOfImages = [NSMutableArray new];
int photoNum ;
photoNum = (int)_photoArray.count;
if (_photoArray.count > 9) {
photoNum = 9;
}
for (int i = 0; i < photoNum; i++) {
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:_photoArray[i]]];
UIImage *myImage = [UIImage imageWithData:data];
//[self.listOfImages addObject:myImage];
[self loadImageFinished:myImage];
}
}
}];
}
- (void)loadImageFinished:(UIImage *)image
{
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
//write photo save to album
[PHAssetChangeRequest creationRequestForAssetFromImage:image];
} completionHandler:^(BOOL success, NSError * _Nullable error) {
NSLog(#"success = %d, error = %#", success, error);
if(success){
dispatch_async(dispatch_get_main_queue(), ^{
[SSGOTools showInfoPopHint:#"Success"];
});
}
}];
}
you will need to use the completion block here for ensuring all images are saved.. try this :
-(void)saveBtn{
[SSGOTools againRequestPhotoWithblock:^(BOOL isAgree) {
if (isAgree) {
self.listOfImages = [NSMutableArray new];
int photoNum ;
photoNum = (int)_photoArray.count;
if (_photoArray.count > 9) {
photoNum = 9;
}
for (int i = 0; i < photoNum; i++) {
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:_photoArray[i]]];
UIImage *myImage = [UIImage imageWithData:data];
[self.listOfImages addObject:myImage];
// [self loadImageFinished:myImage];
}
[self saveAllImages:self.listOfImages];
}
}];
}
-(void)saveAllImages:(NSMutableArray *)images {
UIImage *image = [images firstObject];
[images removeObject:image];
[self loadImageFinished:image :^(bool success) {
if (success){
if (images.count > 0){
[self saveAllImages:images];
}else{
// all images saved do whatever you want;
}
}else{
NSLog(#"failed saving image");
}
}];
}
- (void)loadImageFinished:(UIImage *)image :(void(^)(bool success))completion{
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
//write photo save to album
[PHAssetChangeRequest creationRequestForAssetFromImage:image];
} completionHandler:^(BOOL success, NSError * _Nullable error) {
NSLog(#"success = %d, error = %#", success, error);
if(success){
dispatch_async(dispatch_get_main_queue(), ^{
[SSGOTools showInfoPopHint:#"Success"];
});
}
completion(success);
}];
}
I'm implementing a share extension the extension is dying before the processing of the image finishes.
2018-02-22 15:11:20.327673-0500 ContentShare[9491:649748] [core] SheetViewController didReceiveMemoryWarning
2018-02-22 15:11:20.367087-0500 ContentShare[9491:649748] [core] SheetViewController didReceiveMemoryWarning
Program ended with exit code: 0
I haven't created anything called SheetViewController, and even more frustrating I've eliminated any memory intensive actions and see this in the console when I'm resizing and compressing the image to be shared. I have not even begun the process of uploading the image to a server.
How should I be processing the image to put it onto the server?
I have user session data stored in shared NSUserDefaults to check if a user has a valid login. Because the whole NSUserDefaults is loaded into memory, is this a valid way of passing this auth data?
Is it correct to initialize another file for image processing and upload?
Can AFNetworking even be utilized or that the use beyond the
recommendable amount of memory for the processing/uploading as well?
Is there a defined best practice to process shared items? Apple's documentation seems quite sparse.
ShareViewController.m DID SELECT POST CODE:
- (void)didSelectPost {
// This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments.
NSExtensionItem *inputItem = self.extensionContext.inputItems.firstObject;
NSExtensionItem *outputItem = [inputItem copy];
outputItem.attributedContentText = [[NSAttributedString alloc] initWithString:self.contentText attributes:nil];
// Complete this implementation by setting the appropriate value on the output item.
[self.extensionContext.inputItems enumerateObjectsUsingBlock:^(NSExtensionItem * _Nonnull item, NSUInteger idx, BOOL * _Nonnull stop) {
[item.attachments enumerateObjectsUsingBlock:^(NSItemProvider * _Nonnull itemProvider, NSUInteger idx, BOOL * _Nonnull stop) {
NSString *extension = nil;
NSString *identifier = nil;
MESSAGE_TYPE type = TEXT;
if ([itemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeImage]) {
extension = #".jpg";
identifier = (NSString *)kUTTypeImage;
type = PHOTO;
} else if ([itemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeAudio]) {
extension = #".mp3";
identifier = (NSString *)kUTTypeAudio;
type = AUDIO;
} else if ([itemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeVideo]) {
extension = #".mp4";
identifier = (NSString *)kUTTypeVideo;
type = VID;
} else if ([itemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeData]) {
extension = #".data";
identifier = (NSString *)kUTTypeData;
type = DOWNLOAD;
}
if (identifier != nil) {
[itemProvider loadItemForTypeIdentifier:identifier
options:nil
completionHandler:^(id<NSSecureCoding> _Nullable item, NSError * _Null_unspecified error) {
if ([(NSObject *)item isKindOfClass:[NSURL class]])
{
if ([(NSURL *)item isFileURL] == YES) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(#"PROCESS ON BACKGROUND THREAD");
MyWebServices *services = [[MyWebServices alloc] init];
[services processSharedItemWithReceiver:self.receiver
message:self.contentText
andContent:item
withCompletionBlock:^(NSMutableArray *resultsArray) {
NSLog(#"RESULTS ARRAY: %#", resultsArray);
NSLog(#"IN COMPLETION BLOCK TO CLOSE SHARE UI");
}];
});
[self.extensionContext completeRequestReturningItems:#[] completionHandler:nil];
}
}
}];
}
}];
}];
}
MyWebServices.m Code
- (void)processSharedItemWithReceiver:(NSString*)receiver
message:(NSString*)contentMessage
andContent:(id<NSSecureCoding>)item
withCompletionBlock:(void (^)(NSMutableArray *resultsArray))completion{
NSData *data = [NSData dataWithContentsOfURL:(NSURL *)item];
NSString *fname = [(NSURL *)item lastPathComponent];
NSString *mimeType = [self mimeTypeForData:[NSData dataWithContentsOfURL:(NSURL *)item]];
NSLog(#"SENDING FILE: %# WITH FILETYPE: %#", fname, mimeType);
//Compress and rotate image so that it is in correct pixel orientation because not all EXIF is respected
NSData *compressedImg = [self compressJPEGImage:[UIImage imageWithData:[NSData dataWithContentsOfURL:(NSURL *)item]]];
//Convert compressed image into base64 data to POST to server
//NSString *base64String = [compressedImg base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
if(data){
/* [self setUserShareMessageToUser:receiver withMessage:contentMessage postFileContent:base64String fileType:mimeType fileName:fname CompletionBlock:^(NSMutableArray *resultsArray) {
NSLog(#"IN COMPLETION BLOCK: %#", resultsArray);
if(completion) {
//[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
completion([resultsArray[0] valueForKey:#"CONTENT"]);
}
}]; */
NSMutableArray *arr = [NSMutableArray arrayWithObjects:fname, mimeType, nil];
completion(arr);
}
}
-(NSString *)mimeTypeForData:(NSData *)data {
uint8_t c;
[data getBytes:&c length:1];
switch (c) {
case 0xFF:
return #"image/jpeg";
break;
case 0x89:
return #"image/png";
break;
case 0x47:
return #"image/gif";
break;
case 0x49:
case 0x4D:
return #"image/tiff";
break;
case 0x25:
return #"application/pdf";
break;
case 0xD0:
return #"application/vnd";
break;
case 0x46:
return #"text/plain";
break;
default:
return #"application/octet-stream";
}
return nil;
}
-(NSData *)compressJPEGImage:(UIImage*)image{
UIImageOrientation o = image.imageOrientation;
float degreesOfRotation = 0.0;
NSLog(#"IMAGE ORIENTATION: %li", o);
//UIImageOrientationUp, // default orientation
//UIImageOrientationDown, // 180 deg rotation
//UIImageOrientationLeft, // 90 deg CCW
//UIImageOrientationRight, // 90 deg CW
switch (o) {
case UIImageOrientationDown:
degreesOfRotation = 180.0;
break;
case UIImageOrientationLeft:
degreesOfRotation = 270.0;
break;
case UIImageOrientationRight:
degreesOfRotation = 90.0;
break;
default:
//UIImageOrientationUp -- Default
break;
}
CGRect rect = CGRectMake(0.0, 0.0, image.size.width, image.size.height);
UIGraphicsBeginImageContext(rect.size);
[image drawInRect:rect];
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
//Compress Image
NSData *imageData = UIImageJPEGRepresentation(img, .8);
UIGraphicsEndImageContext();
//Rotate Image
UIImage *rotatedImg = [[UIImage imageWithData:imageData] imageRotatedByDegrees:degreesOfRotation];
NSData *rotatedImageData = UIImageJPEGRepresentation(rotatedImg, 1.0);
return rotatedImageData;
}
Earlier i used SDWebimage third party to display images, now i removed that 3rd party due some other reason. is there any other way to Display GIF image from URL in Imageview without using third party...
Well you can do it simply by following next steps:
Add the following functions
#import <ImageIO/ImageIO.h>
#import <MobileCoreServices/MobileCoreServices.h>
UIImage *GIFFromData(NSData *data) {
if (!data) {
return nil;
}
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)(data), NULL);
UIImage *image = nil;
if (GIFSourceContainsAnimatedGIF(source)) {
image = GIFFromImageSource(source);
} else {
image = [UIImage imageWithData:data];
}
if (source) {
CFRelease(source);
}
return image;
}
BOOL GIFSourceContainsAnimatedGIF(CGImageSourceRef source) {
return (source && UTTypeConformsTo(CGImageSourceGetType(source), kUTTypeGIF) && CGImageSourceGetCount(source) > 1);
}
UIImage *GIFFromImageSource(CGImageSourceRef source) {
CFRetain(source);
NSUInteger numberOfFrames = CGImageSourceGetCount(source);
NSMutableArray<UIImage *> *images = [NSMutableArray arrayWithCapacity:numberOfFrames];
NSTimeInterval duration = 0.0;
for (NSUInteger i = 0; i < numberOfFrames; ++i) {
CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL);
if (image) {
UIImage *frameImage = [UIImage imageWithCGImage:image scale:1.0 orientation:UIImageOrientationUp];
[images addObject:frameImage];
CFRelease(image);
} else {
continue;
}
duration += GIFSourceGetFrameDelay(source, i);
}
CFRelease(source);
return [UIImage animatedImageWithImages:images duration:duration];
}
NSTimeInterval GIFSourceGetFrameDelay(CGImageSourceRef source, NSUInteger index) {
NSTimeInterval frameDelay = 0;
CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(source, index, NULL);
if (!imageProperties) {
return frameDelay;
}
CFDictionaryRef gifProperties = nil;
if (CFDictionaryGetValueIfPresent(imageProperties, kCGImagePropertyGIFDictionary, (const void **)&gifProperties)) {
const void *durationValue = nil;
if (CFDictionaryGetValueIfPresent(gifProperties, kCGImagePropertyGIFUnclampedDelayTime, &durationValue)) {
frameDelay = [(__bridge NSNumber *)durationValue doubleValue];
if (frameDelay <= 0) {
if (CFDictionaryGetValueIfPresent(gifProperties, kCGImagePropertyGIFDelayTime, &durationValue)) {
frameDelay = [(__bridge NSNumber *)durationValue doubleValue];
}
}
}
}
CFRelease(imageProperties);
return frameDelay;
}
Download your GIF with NSURLSession
Display it
UIImage *image = GIFFromData(data);
UIImageView *view = [[UIImageView alloc] initWithImage:image];
Hope this helps :)
UIImageView* animatedImageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
animatedImageView.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"image1.gif"],
[UIImage imageNamed:#"image2.gif"],
[UIImage imageNamed:#"image3.gif"],
[UIImage imageNamed:#"image4.gif"], nil];
animatedImageView.animationDuration = 1.0f;
animatedImageView.animationRepeatCount = 0;
[animatedImageView startAnimating];
[self.view addSubview: animatedImageView];
Add animated Gif image in Iphone UIImageView
I get this error when loading multi images from disk. I used SDWebImage to load image but still get this error then app crashed. I dont know what this error is. Pls give me adivse. Thanks much.
Communications error: <OS_xpc_error: <error: 0x322eb614> { count = 1, contents =
"XPCErrorDescription" => <string: 0x322eb86c> { length = 22, contents = "Connection interrupted" }
}>
Here is the code I used to create the list thumbnail for scrollview
-(void) createPropertyThumbnails:(NSArray*) array
{
int xCoord=10;
int yCoord=7;
int buffer = 7;
for (int pos = 0; pos < array.count; pos++) {
// CREATE VIEW CONTAINS UIIMAGEVIEW HERE
ThumbnailView* thumbnaiCell = [[humbnailView alloc] initWithFrame:CGRectMake(xCoord, yCoord,THUMBNAIL_WIDTH , THUMBNAIL_HEIGHT) andURLImage:array[pos]];
thumbnaiCell.delegate = self;
//set selected for 1st item
if(pos ==0)
{
_selectedCell =thumbnaiCell;
[_selectedCell setSelectedCell:YES];
}
xCoord = xCoord + THUMBNAIL_WIDTH + buffer;
[self.thumbnailScrollView addSubview:thumbnaiCell];
}
[self.thumbnailScrollView setContentSize:CGSizeMake(xCoord, self.thumbnailScrollView.frame.size.height)];
}
- (id)initWithFrame:(CGRect)frame andURLImage:(NSString*) url
{
self = [super initWithFrame:frame];
if (self) {
[self setupProjectThumbnail:frame andURLImage:url];
}
return self;
}
-(void) setupProjectThumbnail:(CGRect) frame andURLImage:(NSString*) url
{
//create load image from cache
NSString *filePath = [[NSBundle mainBundle] pathForResource:url ofType:nil];
NSURL *ImageURL = [NSURL fileURLWithPath:filePath];
if (ImageURL) {
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadImageWithURL:ImageURL
options:0
progress:^(NSInteger receivedSize, NSInteger expectedSize) {
// progression tracking code
}
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (image) {
// do something with image
// imageview
UIImageView* imageview = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, frame.size.width, frame.size.height)];
imageview.contentMode = UIViewContentModeScaleToFill;
[self addSubview:imageview];
}
}];
}
}
I want to set cropped image in PhotoEditing Extension
I provided that facility for cropping and rotate facility now I want to make that effect on Photos of simulator
// Adjustment data
PHContentEditingOutput *contentEditingOutput = [[PHContentEditingOutput alloc] initWithContentEditingInput:self.input];
NSData *archivedData = [NSKeyedArchiver archivedDataWithRootObject:self.strSelectedFilterName];
PHAdjustmentData *adjustmentData = [[PHAdjustmentData alloc] initWithFormatIdentifier:#"com.test.PhotoEditingExtensionDemo"
formatVersion:#"1.0"
data:archivedData];
contentEditingOutput.adjustmentData = adjustmentData;
switch (self.input.mediaType)
{
case PHAssetMediaTypeImage:
{
// Get full size image
NSURL *url = self.input.fullSizeImageURL;
int orientation = self.input.fullSizeImageOrientation;
// Generate rendered JPEG data
UIImage *image = [UIImage imageWithContentsOfFile:url.path];
image = [self transformedImage:image withOrientation:orientation usingFilter:self.ciFilter];
NSData *renderedJPEGData = UIImageJPEGRepresentation(image, 0.9f);
// Save JPEG data
NSError *error = nil;
BOOL success = [renderedJPEGData writeToURL:contentEditingOutput.renderedContentURL options:NSDataWritingAtomic error:&error];
if (success) {
completionHandler(contentEditingOutput);
} else {
NSLog(#"An error occured: %#", error);
completionHandler(nil);
}
break;
}
case PHAssetMediaTypeVideo: {
// Get AV asset
AAPLAVReaderWriter *avReaderWriter = [[AAPLAVReaderWriter alloc] initWithAsset:self.input.avAsset];
avReaderWriter.delegate = self;
// Save filtered video
[avReaderWriter writeToURL:contentEditingOutput.renderedContentURL
progress:^(float progress) {
}
completion:^(NSError *error) {
if (!error) {
completionHandler(contentEditingOutput);
} else {
NSLog(#"An error occured: %#", error);
completionHandler(nil);
}
}];
break;
}
default:
break;
}