I am creating a feature where a user can record a video of themselves, and superimposed on this video is a view that displays an image and some text. When they are done recording, I am using AVFoundation's composition classes to composite the video and the view (as an image) into one video file, and output this in the next scene in a custom video player. The problem is that while the view's resolution is crystal clear in the record scene, after the composition (and after the AVExportSession completes) the resulting video's overlayed view quality is not clsoe to the actual view quality. I am converting the view to an image, and then setting the contents of an overlay layer as this image's CGImage, which, as I have checked, still has the same quality as the original view. The problem occurs when I apply the composition, and the image becomes blurry. Does anyone have any idea why this might be happening?
If you need to see the code, please feel free to ask! I can also provide screenshots.
Thank you!
It could happen when initiating your UIImage, iOS automatically pick #2x or #3x image source for you corresponding to your device.
Let say you get image size using size property like image.size, it gives you #1x size, and you might reduce your image size from #2x or #3x to #1x, you get a bad quality image output, because JPEG or PNG resize algorithms.
Related
I am having difficulties with retina images.
The screenshot below shows the UICollectionView with a UIImageView contained within each UICollectionViewCell.
Within the app I have a large image 512x512 pixels called travel.png.
The green circle shows what is displayed on the app when I name this file: travel.png. The blue circle shows what I see when I update the image name to be travel#2x.png (i.e. retina naming).
I was hoping due to the large size of the image (512x512) that simply adding the #2x suffix would be enough to convert it to twice the definition (i.e. retina) but as you can see from the two screenshots, both version images show as non-retina.
How can I update the image so that it will display in retina?
travel.png:
travel#2x.png:
* Updated *
Following request in comments below:
I load this image by calling the following function:
// Note - when this method is called: contentMode is set to .scaleAspectFit & imageName is "travel"
public func setImageName(imageName: String, contentMode: ContentMode) {
self.contentMode = contentMode
if let image = UIImage(named: imageName) {
self.image = image
}
}
Here is how the image appears in Xcode before the app renders it (as you can see it is high enough definition):
The reason why you see the low quality image is anti-aliasing. When you provide images bigger then an actual frame of UIImageView (scaleAspectFit mode) the system will automatically downscale them. During scaling some anti-aliasing effects can be added at curve shapes. To avoid the effect you should provide the exact image size you want to display on the screen.
To detect if UIImageView autoscale the image you can switch on Debug->Color Misaligned Images at Simulator menu:
Now all scaled images will highlight at simulator with yellow color. Each highlighted image may have anti-aliasing artifacts and affect CPU usage for scaling algorithms:
To resolve the issue you should use exact sizes. So the system will use them directly without any additional calculations. For example, if your button have 80x80px size you should add three images to assert catalog with following sizes and dpi: 80x80px (72 dpi), 160x160px (144 dpi) and 240x240px (216 dpi):
Now the image will be drawn at the screen without downscaling with much better visual quality:
If your intention is to have just one image for all the sizes, I would suggest it having under Assets.xcassets. It is easy to create the folder structures and manage media assets here.
Steps
On clicking + icon, you will displayed a list of actions. Choose to create a New folder.
Choosing the new folder that is created, click on the + icon again and click on New Image Set.
Choose the imageset. And choose the attributes inspector.
Select Single Scale, under Scales.
Drag and drop the image.
Rename the image name and folder names as you wish.
Now you can use this image using the image name for all the screen sizes.
TL;DR;
Change the view layer's minificationFilter to .trilinear
imageView.layer.minificationFilter = .trilinear
as illustrated by the device screenshot below
As Anton's answer correctly pointed out, the aliasing effet you observe is caused by the large difference in dimensions between the source image and the image view it's displayed in. Adding the #2x suffix won't change anything if you do not change the dimensions of the source image itself.
That said there is an easy way to improve the situation without resizing the original image: CALayer offers some control over the method used by the graphics back-end to resize images : minificationFilter and magnificationFilter. The first one is relevant in your case since the image size is being reduced. The default value is CALayerContentsFilter.linear, just switch to .trilinear for a much better result (more info on those wikipedia pages). This will require more GPU power (thus battery), especially if you apply it on many images.
You should really consider resizing the images before displaying them, either statically or at run-time (and maybe cache the resized versions). In addition to the bad visual quality, using such large images in quantities in your UI will decrease performance and waste lots of memory, leading to potentially other issues.
I have fixed, #DarshanKunjadiya issue.
Make sure (if you are already using assets):
Make sure images are not un-assigned
Now use images in storyboard or code without extensions. (e.g. "image" NOT "image.png")
If you are not using images from assets, move them to assets.
Demo Projects
Hope it helps.
Let me know of your feedback.
I think images without the #2x and #3x are rendered for devices with low resolutions (like the iphone 4 an 3G).
The solution I think is to always use the .xcassets file or to add the #2x or #3X in the names of your images.
In iOS, content is placed on the screen based on the iOS coordinate system. for displaying an image on a standard resolution system having 1:1 pixel density we should supply image at #1x resolution. for higher resolution displays the pixel density will be a scale factor of 2.0, 3.0 which refers in the iOS system as #2x and #3x respectively. That is high-resolution displays demands images with higher density.
For example, if you want to display an image of size 128x128 in standard resolution. You have to supply the #2x and #3x size image of the same. ie., 256x256 at #2x version and 384x384 image at #3x version.
In the following screenshot, I have supplied an image of size 256x256 for 2x version to display a 128x128 pixel image in iPhone 6s. iPhone 6s render images at #2x size. Using the three version of images such as 1x, 2x and 3x with asset catalogue will resolve your issues. So the iPhone will automatically render the correct sized image automatically with the screen resolution.
I am displaying image thumbnails from urls(which are in json file) into custom cells of a tableview.
The images loaded from url are not showing up properly- they are of a resolution much higher than need and some are of much lower resolution.
How do I manipulate these images so that they are scaled properly as per each screen(retina as well as normal) in iphone?
How do I scale and resize the thumbnail images from url?
Unless you care about other issues like memory or disk usage (for some caching) for the images, you don't have to resize them.
You can use UIViewContentModeScaleAspectFit as contentMode for an UIImageView and just set an image for the image view. It would be sufficient for you.
I'm using Nimbus to display a photo album with scrubber and zoomable image view. I use network images, and display a thumbnail until the final image is loaded. NIPhotoAlbumScrollView provides the method didLoadPhoto:atIndex:photoSize: to accomplish exactly that.
From the source code comments, the NIPhotoScrollView should support that "image crisping effect" - showing thumbnail and when full-size image is loaded, sharpen the image without loosing the zoom state.
This feature seems broken though. When the thumbnail is loaded, it is displayed in its 1:1 pixel size, which is very small on screen. When the full-size image is loaded, it is also loaded in its 1:1 pixel size (if smaller than the available view size), which makes the image visually jump bigger.
Any idea on how to fix that issue?
Note that I tried both with a full sized image with dimensions bigger or smaller than the size of the NIToolbarPhotoViewController on screen.
you may already be doing this, but one thing to make certain:
where you implement photoAlbumScrollView:photoAtIndex:photoSize:isLoading:originalPhotoDimensions: for protocol NIPhotoAlbumScrollViewDataSource, you must do the following, as mentioned in these comments in the source:
* If you have a thumbnail in memory but not the full-size image yet, then you should return
* the thumbnail, set isLoading to YES, and set photoSize to NIPhotoScrollViewPhotoSizeThumbnail.
I was having a look at the RosyWriter Sample Code provided by Apple as a starting point and I'd like to find a way how to crop a video.
So i have the full resolution video from the iPhones Camera, but I just want to use a cropped part of it (and also rotate this subpart).
I figured that in captureOutput:didOutputSampleBuffer: fromConnection: i can modify each frame by modifying the CMSampleBufferRef that i get passed in.
So my questions now are:
Is this the right place to crop my video?
Where do I specify that the final video (that get's saved to disc) has a smaller resolution than the full video captured by AVCaptureSession? Setting the AVVideoWidthKey and AVVideoHeightKey has no effect.
How can I crop the video and still have good performance?
Any help is appreciated!
Thanks a lot!
EDIT:
Maybe I just need to know how I can make a video that was shot in portrait a landscape one by turning the images of the video by 90 degrees and then zoom in to fit the width again...?!?
In AVVideoSetttings.h there is the AVVideoScalingModeKey. This key combined with the defined values control how the video is scaled/cropped when encoding the images to the video container. For example if you specified a value of AVVideoScalingModeFit then cropping is used. Check out the header for how other values effect the video images.
I have to create a custom photolib like the default one, with animation etc. I had some doubts..
1. Doubt
Should I create 3 images (Thumbnail image, 320*480 image to display full image and original size image in case user share the image) (I am storing this all in app doc directory)
Or should I only store the original image and crop them wen required in 2 other images? In this case, if I use scroll view to display cropped images, how do I know what the user is seeing? And when do I crop next images to keep them ready to display?
(Can anything like reusable cells be created here like in tableview? If yes, can you give me some idea?)
Also, I am fetching images from doc directory. In this case should I load all images in Array or load in batches?
2. Problem Major:
Also need to compress original image and keep it of same size (I used uijpegrepresentation with compression ratio but with some jpegs after compression. It increases sizes even double the size).
You can use single image and for thumbnail you can Resize at run time else it increase size and performance issue. there is lots of open source library are there which do same what you needed. Please have a look below.
https://github.com/arturgrigor/AGImagePickerController
https://github.com/gdavis/FGallery-iPhone