Get QuickLook preview image for file - objective-c

Is there any way to get the quick look preview image for a file?
I'm looking for something like this:
NSImage *image = [QuickLookPreviewer quickLookPreviewForFile:path];

See QLThumbnailRequest in the docs: https://developer.apple.com/library/mac/#documentation/UserExperience/Reference/QLThumbnailRequest_Ref/Reference/reference.html
NSURL *path = aFileUrl;
NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO] forKey:(NSString *)kQLThumbnailOptionIconModeKey];
CGImageRef ref = QLThumbnailImageCreate(kCFAllocatorDefault, (CFURLRef)path, CGSizeMake(600, 800 /* Or whatever size you want */), (CFDictionaryRef)options);

In Swift I ended up with something like this (the force unwraps should be replaced):
let options = [
kQLThumbnailOptionIconModeKey: false
]
let ref = QLThumbnailCreate(
kCFAllocatorDefault,
url as NSURL,
CGSize(width: 150, height: 150),
options as CFDictionary
)
let thumbnail = ref!.takeRetainedValue()
let cgImageRef = QLThumbnailCopyImage(thumbnail)
let cgImage = cgImageRef!.takeRetainedValue()
let image = NSImage(cgImage: cgImage, size: CGSize(width: cgImage.width, height: cgImage.height))

Related

Get Thumbnail Image from PHAsset

I want to get the Thumbnail Image of my PHAsset. I already extracted a PHAsset from the Photo Library and want to get the Thumbnail Image now.
Can you help me in Objective-C?
Thanks!
In case someone is looking for a swift solution, here is an extension:
extension PHAsset {
var thumbnailImage : UIImage {
get {
let manager = PHImageManager.default()
let option = PHImageRequestOptions()
var thumbnail = UIImage()
option.isSynchronous = true
manager.requestImage(for: self, targetSize: CGSize(width: 300, height: 300), contentMode: .aspectFit, options: option, resultHandler: {(result, info)->Void in
thumbnail = result!
})
return thumbnail
}
}
}
The PHImageManagerClass has the method:
- requestImageForAsset:targetSize:contentMode:options:resultHandler:
Here is a complete answer for Swift 4 showing the function & call against it. Also, make sure you have the photos privacy flag set in your plist.
import Photos
func requestImage(for asset: PHAsset,
targetSize: CGSize,
contentMode: PHImageContentMode,
completionHandler: #escaping (UIImage?) -> ()) {
let imageManager = PHImageManager()
imageManager.requestImage(for: asset,
targetSize: targetSize,
contentMode: contentMode,
options: nil) { (image, _) in
completionHandler(image)
}
}
let asset = // your existing PHAsset
let targetSize = CGSize(width: 100, height: 100)
let contentModel = PHImageContentMode.aspectFit
requestImage(for: asset, targetSize: targetSize, contentMode: contentModel, completionHandler: { image in
// Do something with your image if it exists
})
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.resizeMode = PHImageRequestOptionsResizeModeExact;
NSInteger retinaMultiplier = [UIScreen mainScreen].scale;
CGSize retinaSquare = CGSizeMake(imageView.bounds.size.width * retinaMultiplier, imageView.bounds.size.height * retinaMultiplier);
[[PHImageManager defaultManager]
requestImageForAsset:(PHAsset *)_asset
targetSize:retinaSquare
contentMode:PHImageContentModeAspectFill
options:options
resultHandler:^(UIImage *result, NSDictionary *info) {
imageView.image =[UIImage imageWithCGImage:result.CGImage scale:retinaMultiplier orientation:result.imageOrientation];
}];
i get this answer from How to fetch squared thumbnails from PHImageManager?

How to get Image size from URL in ios

How can I get the size(height/width) of an image from URL in objective-C? I want my container size according to the image. I am using AFNetworking 3.0.
I could use SDWebImage if it fulfills my requirement.
Knowing the size of an image before actually loading it can be necessary in a number of cases. For example, setting the height of a tableView cell in the heightForRowAtIndexPath method while loading the actual image later in the cellForRowAtIndexPath (this is a very frequent catch 22).
One simple way to do it, is to read the image header from the server URL using the Image I/O interface:
#import <ImageIO/ImageIO.h>
NSMutableString *imageURL = [NSMutableString stringWithFormat:#"http://www.myimageurl.com/image.png"];
CGImageSourceRef source = CGImageSourceCreateWithURL((CFURLRef)[NSURL URLWithString:imageURL], NULL);
NSDictionary* imageHeader = (__bridge NSDictionary*) CGImageSourceCopyPropertiesAtIndex(source, 0, NULL);
NSLog(#"Image header %#",imageHeader);
NSLog(#"PixelHeight %#",[imageHeader objectForKey:#"PixelHeight"]);
Swift 4.x
Xcode 12.x
func sizeOfImageAt(url: URL) -> CGSize? {
// with CGImageSource we avoid loading the whole image into memory
guard let source = CGImageSourceCreateWithURL(url as CFURL, nil) else {
return nil
}
let propertiesOptions = [kCGImageSourceShouldCache: false] as CFDictionary
guard let properties = CGImageSourceCopyPropertiesAtIndex(source, 0, propertiesOptions) as? [CFString: Any] else {
return nil
}
if let width = properties[kCGImagePropertyPixelWidth] as? CGFloat,
let height = properties[kCGImagePropertyPixelHeight] as? CGFloat {
return CGSize(width: width, height: height)
} else {
return nil
}
}
Use Asynchronous mechanism called GCD in iOS to dowload image without affecting your main thread.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Download IMAGE using URL
NSData *data = [[NSData alloc]initWithContentsOfURL:URL];
// COMPOSE IMAGE FROM NSData
UIImage *image = [[UIImage alloc]initWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
// UI UPDATION ON MAIN THREAD
// Calcualte height & width of image
CGFloat height = image.size.height;
CGFloat width = image.size.width;
});
});
For Swift 4 use this:
let imageURL = URL(string: post.imageBigPath)!
let source = CGImageSourceCreateWithURL(imageURL as CFURL,
let imageHeader = CGImageSourceCopyPropertiesAtIndex(source!, 0, nil)! as NSDictionary;
print("Image header: \(imageHeader)")
The header would looks like:
Image header: {
ColorModel = RGB;
Depth = 8;
PixelHeight = 640;
PixelWidth = 640;
"{Exif}" = {
PixelXDimension = 360;
PixelYDimension = 360;
};
"{JFIF}" = {
DensityUnit = 0;
JFIFVersion = (
1,
0,
1
);
XDensity = 72;
YDensity = 72;
};
"{TIFF}" = {
Orientation = 0;
}; }
So u can get from it the Width, Height.
you can try like this:
NSData *data = [[NSData alloc]initWithContentsOfURL:URL];
UIImage *image = [[UIImage alloc]initWithData:data];
CGFloat height = image.size.height;
CGFloat width = image.size.width;

How to take a screenshot with low quality

Is there a way to a take a screenshot (low level quality) on osx programmatically?
I developed a function like below:
CGImageRef resizeImage(CGImageRef imageRef) {
CGRect thumRect;
CGPoint point;
point.x = 0;
point.y = 0;
thumRect.origin = point;
thumRect.size.height = 225;
thumRect.size.width = 360;
CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageRef);
if (aplhaInfo == kCGImageAlphaNone)
alphaInfo = kCGImageAlphaNoneSkipLast;
CGContextRef bitmap = CGBitmapContextCreate(NULL, thumRect.size.width, thumRect.size.height, CGImageGetBitsPerComponent(imageRef), 4 * thumRect.size.width, CGImageGetColorSpace(imageRef), alphaInfo);
CGContextDrawImage(bitmap, thumRect, imageRef);
imageRef = CGBitmapContextCreateImage(bitmap);
CGContextRelease(bitmap);
return imageRef;
}
When I runned this function, I took an between 150KB and 600KB image. If I decrease thumRect size, I cant read any characters in the image. But, I want to decrease these images as low as possible. Is there any suggestion or another possible solution?
Thanks.
I found a solution like below:
First af all, resize your image with code in my question.
Then Compress it :)
//imageRef is CGImageRef
NSImage * image = [[NSImage alloc] initWithCGImage:imageRef size:NSZeroSize];
NSBitmapImageRep *bmpImageRep = [NSBitmapImageRep imageRepWithData [image TIFFRepresentation]];
CGFloat compressionFactor = 1.0 //Read it : (1)
NSDictionary *jpgProperties = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithDouble:compressionFactor], NSImageCompressionFactor, [NSNumber numberWithBool:NO], NSImageProgressive, nil];
NSData *jpgData = [bmpImageRep representationUsingType:NSJPEGFileType properties:jpgProperties];
(1):https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSBitmapImageRep_Class/index.html#//apple_ref/doc/constant_group/Bitmap_image_properties

First frame of a video using AVFoundation

I'm trying to get the first frame of a video using the classes in AVFoundation. But it appears to not be getting an image at all.
My code currently looks like this
AVURLAsset* asset = [AVURLAsset URLAssetWithURL:[NSURL URLWithString:videoPath] options:nil];
AVAssetImageGenerator* imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:asset];
UIImage* image = [UIImage imageWithCGImage:[imageGenerator copyCGImageAtTime:CMTimeMake(0, 1) actualTime:nil error:nil]];
[videoFrame setImage:image];
The value of video path is /var/mobile/Applications/02F42CBF-D8BD-4155-85F2-8CF1E55B5023/Documents/videos/1334300431637030.mp4 which is definitely a video, since I can play it with MPMoviePlayerViewController. I'm not sure what I'm doing wrong but any suggestions would be helpful.
Thanks.
I solved it. Apparently using [NSURL fileURLWithPath:videoPath] instead of [NSURL URLWithString:videoPath] makes all the difference.
I used null0pointer solution but in some videos I recieved the first frame rotated. To resolve this issue I set to TRUE the appliesPreferredTrackTransform property of AVAssetImageGenerator. And this code looks like this:
AVURLAsset* asset = [AVURLAsset URLAssetWithURL:fileURL options:nil];
AVAssetImageGenerator* imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:asset];
[imageGenerator setAppliesPreferredTrackTransform:TRUE];
UIImage* image = [UIImage imageWithCGImage:[imageGenerator copyCGImageAtTime:CMTimeMake(0, 1) actualTime:nil error:nil]];
[self.imageView setImage:image];
Doing this in Swift 4.0:
// Assumes you have a local `fileURL`
var avAsset = AVURLAsset(url: fileURL, options: nil)
var imageGenerator = AVAssetImageGenerator(asset: avAsset)
imageGenerator.appliesPreferredTrackTransform = true
var thumbnail: UIImage?
do {
thumbnail = try UIImage(cgImage: imageGenerator.copyCGImage(at: CMTime(seconds: 0, preferredTimescale: 1), actualTime: nil))
} catch let e as NSError {
print("Error: \(e.localizedDescription)")
}

CGImage create thumbnail image with desired size

I want to create the thumbnail using the CG. It creates the thumbnails.
Here i want to have the thumbnail with the size 1024 (with aspect ratio.) Is it possible to get the desired size thumbnail directly from the CG?
In the options dictionary i can pass the max size of the thumnail can be created, but is there any way to have min size for the same..?
NSURL * url = [NSURL fileURLWithPath:inPath];
CGImageSourceRef source = CGImageSourceCreateWithURL((CFURLRef)url, NULL);
CGImageRef image=nil;
if (source)
{
NSDictionary* thumbOpts = [NSDictionary dictionaryWithObjectsAndKeys:
(id) kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailWithTransform,
(id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailFromImageIfAbsent,
[NSNumber numberWithInt:2048], kCGImageSourceThumbnailMaxPixelSize,
nil];
image = CGImageSourceCreateThumbnailAtIndex(source, 0, (CFDictionaryRef)thumbOpts);
NSLog(#"image width = %d %d", CGImageGetWidth(image), CGImageGetHeight(image));
CFRelease(source);
}
If you want a thumbnail with size 1024 (maximum dimension), you should be passing 1024, not 2048. Also, if you want to make sure the thumbnail is created to your specifications, you should be asking for kCGImageSourceCreateThumbnailFromImageAlways, not kCGImageSourceCreateThumbnailFromImageIfAbsent, since the latter might cause an existing thumbnail to be used, and it could be smaller than you want.
So, here's code that does what you ask:
NSURL* url = // whatever;
NSDictionary* d = [NSDictionary dictionaryWithObjectsAndKeys:
(id)kCFBooleanTrue, kCGImageSourceShouldAllowFloat,
(id)kCFBooleanTrue, kCGImageSourceCreateThumbnailWithTransform,
(id)kCFBooleanTrue, kCGImageSourceCreateThumbnailFromImageAlways,
[NSNumber numberWithInt:1024], kCGImageSourceThumbnailMaxPixelSize,
nil];
CGImageSourceRef src = CGImageSourceCreateWithURL((CFURLRef)url, NULL);
CGImageRef imref = CGImageSourceCreateThumbnailAtIndex(src, 0, (CFDictionaryRef)d);
// memory management omitted
Swift 3 version of the answer:
func loadImage(at url: URL, maxDimension max: Int) -> UIImage? {
guard let imageSource = CGImageSourceCreateWithURL(url as CFURL, nil)
else {
return nil
}
let options: [CFString: Any] = [
kCGImageSourceShouldAllowFloat: true,
kCGImageSourceCreateThumbnailWithTransform: true,
kCGImageSourceCreateThumbnailFromImageAlways: true,
kCGImageSourceThumbnailMaxPixelSize: max
]
guard let thumbnail = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary)
else {
return nil
}
return UIImage(cgImage: thumbnail)
}