I want to show image from gallery.
i am loading the image using imagePicker.
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
guard let image = info[.originalImage] as? UIImage else { return }
if let imgUrl = info[UIImagePickerController.InfoKey.imageURL] as? URL{
self.photoEntity = createPhotoEntity(fileUrl: imgUrl, fileName: imgName)
}
dismiss(animated: true)
}
and then i have created a modelEntity like this.
private func createPhotoEntity(fileUrl: URL, fileName: String) -> ModelEntity? {
// Create a TextureResource by loading the contents of the file URL.
do {
let texture = try TextureResource.load(contentsOf: fileUrl)
let planeMesh = MeshResource.generatePlane(width: 0.5, depth: 0.5)
var material = UnlitMaterial()
material.color = .init(tint: .red.withAlphaComponent(0.999), texture: .init(texture))
let entity = ModelEntity(mesh: planeMesh, materials: [material])
entity.generateCollisionShapes(recursive: true)
ARView.installGestures([.scale, .translation], for: entity)
return entity
} catch(let error) {
print("error loading. \(error.localizedDescription)")
}
return nil
}
But the fact is, image is being shown with a color and this is legit.
But
Is there any way to show only image without any color?
Try this. Take into consideration, a tint color is multiplied by an image – so, if tint's RGBA = [1,1,1,1], a result of multiplication will be an image itself (without tinting)...
import ARKit
import RealityKit
class ViewController: UIViewController {
#IBOutlet var arView: ARView!
var anchor: AnchorEntity!
override func viewDidLoad() {
super.viewDidLoad()
self.anchor = AnchorEntity(world: [0,0,-1])
let ball: MeshResource = .generateSphere(radius: 0.25)
var material = UnlitMaterial()
if #available(iOS 15.0, *) {
material.color = try! .init(tint: .white,
texture: .init(.load(named: "img",
in: nil)))
}
let ballEntity = ModelEntity(mesh: ball, materials: [material])
self.anchor.addChild(ballEntity)
self.arView.scene.anchors.append(self.anchor)
}
}
Tested on Xcode 13.4, macOS 12.4
import Foundation
import RealityKit
import UIKit
import SwiftUI
#available(macOS 11.0, iOS 15.0, *)
public extension UnlitMaterial {
static func imageWith(imageName: String, bundle: Bundle? = nil, uiTint: UIColor) throws -> UnlitMaterial {
var material = UnlitMaterial()
do {
let texture = try TextureResource.load(named: imageName, in: bundle)
let materialParameter = MaterialParameters.Texture(texture)
let materialBaseColor = UnlitMaterial.BaseColor(tint: uiTint, texture: materialParameter)
material.color = materialBaseColor
return material
} catch let error {
throw error
}
}
static func imageWith(imageName: String, bundle: Bundle? = nil, tint: Color) throws -> UnlitMaterial {
var material = UnlitMaterial()
do {
let texture = try TextureResource.load(named: imageName, in: bundle)
let materialParameter = MaterialParameters.Texture(texture)
let materialBaseColor = UnlitMaterial.BaseColor(tint: UIColor(tint), texture: materialParameter)
material.color = materialBaseColor
return material
} catch let error {
throw error
}
}
}
Usage:
if #available(iOS 15.0, *) {
do {
var imageMaterial = try UnlitMaterial.imageWith(imageName: "1", uiTint: .white)
let bluePlane = ModelEntity(mesh: bluePlaneMeshResource, materials: [imageMaterial])
bluePlane.transform.rotation *= simd_quatf(angle: 90, axis: SIMD3<Float>(1,0,0))
box1AnchorEntity.addChild(bluePlane)
view.scene.addAnchor(box1AnchorEntity)
} catch let error {
print("Error: \(error)")
}
} else {
// Fallback on earlier versions
}
Related
Below is my main view controller. The user selects images of clothing which are then categorized using CoreML and given a filename. Then, data is saved to Realm. When I call the function loadClothing(), the array is empty even though items were added during func detect. Any help is much appreciated!
import UIKit
import PhotosUI
import RealmSwift
import CoreML
import Vision
class ViewController: UIViewController, PHPickerViewControllerDelegate {
#IBOutlet weak var shoesImageView: UIImageView!
#IBOutlet weak var shirtImageView: UIImageView!
#IBOutlet weak var pantsImageView: UIImageView!
var documentsUrl: URL {
return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
}
let realm = try! Realm()
var clothing: Results<Clothing>?
override func viewDidLoad() {
super.viewDidLoad()
loadClothing()
let clothingArray = Clothing()
print(clothingArray)
}
#IBAction func addClothesButton(_ sender: UIBarButtonItem) {
pickPhotos()
}
#IBAction func randomizeButton(_ sender: UIBarButtonItem) {
loadClothing()
let clothingArray = Clothing()
print(clothingArray)
shirtImageView.image = load(fileName: clothingArray.shirtImages.randomElement()!)
pantsImageView.image = load(fileName: clothingArray.pantsImages.randomElement()!)
shoesImageView.image = load(fileName: clothingArray.shoesImages.randomElement()!)
}
//MARK: - PHPickerViewController
#objc func pickPhotos() {
var config = PHPickerConfiguration()
config.selectionLimit = 25
config.filter = PHPickerFilter.images
let pickerViewController = PHPickerViewController(configuration: config)
pickerViewController.delegate = self
self.present(pickerViewController, animated: true, completion: nil)
}
// MARK: - PHPickerViewControllerDelegate
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true, completion: nil)
for result in results {
result.itemProvider.loadObject(ofClass: UIImage.self) {(object, error) in
if let image = object as? UIImage {
DispatchQueue.main.async {
guard let fileName = result.itemProvider.suggestedName else {
fatalError("Could not retrieve file name.")
}
print(fileName)
guard let ciImage = CIImage(image: image) else {
fatalError("Could not convert to CI Image.")
}
self.detect(image: ciImage, fileName: fileName)
}
}
}
}
}
// MARK: - Core ML
func detect(image: CIImage, fileName: String) {
guard let model = try? VNCoreMLModel(for: ClothingClassifier(configuration: MLModelConfiguration()).model) else {
fatalError("Loading CoreML Model failed.")
}
let request = VNCoreMLRequest(model: model) { (request, error) in
guard let results = request.results as? [VNClassificationObservation] else {
fatalError("Model failed to process image.")
}
let newClothing = Clothing()
if let firstResult = results.first {
let uiImage = UIImage(ciImage: image)
if firstResult.identifier.contains("shirts") {
newClothing.shirtImages.append(fileName)
} else if firstResult.identifier.contains("pants"){
newClothing.pantsImages.append(fileName)
} else if firstResult.identifier.contains("shoes") {
newClothing.shoesImages.append(fileName)
}
self.save(clothing: newClothing)
print(newClothing)
}
}
let handler = VNImageRequestHandler(ciImage: image)
do {
try handler.perform([request])
}
catch {
print(error)
}
}
// MARK: - Data Manipulation Methods
func save(clothing: Clothing) {
do {
try realm.write {
realm.add(clothing)
}
} catch {
print("Error saving uploaded clothing. \(error)")
}
}
func loadClothing() {
clothing = realm.objects(Clothing.self)
print("loaded")
}
private func load(fileName: String) -> UIImage? {
let fileURL = documentsUrl.appendingPathComponent(fileName)
do {
let imageData = try Data(contentsOf: fileURL)
return UIImage(data: imageData)
} catch {
print("Error loading image : \(error)")
}
return nil
}
}
Clothing Class
import Foundation
import RealmSwift
class Clothing: Object {
let shirtImages = List<String>()
let pantsImages = List<String>()
let shoesImages = List<String>()
}
Hi I am fairly new to coding and I ran into this error with AVCapturePhotoOutput. I am using Swift 5 and Xcode 12.5.1. I'm running it on my actual device and I have been stuck on it for awhile. The error only occurs when I try to capture a photo. Any help would be greatly appreciated thank you :)
private let output = AVCapturePhotoOutput()
private var captureSession: AVCaptureSession?
private let previewLayer = AVCaptureVideoPreviewLayer()
private let cameraView = UIView()
t
private func setUpCamera() {
let captureSession = AVCaptureSession()
if let device = AVCaptureDevice.default(for: .video) {
do {
let input = try AVCaptureDeviceInput(device: device)
if captureSession.canAddInput(input) {
captureSession.addInput(input)
}
if captureSession.canAddOutput(output) {
captureSession.addOutput(output)
}
// Layer
previewLayer.session = captureSession
previewLayer.videoGravity = .resizeAspectFill
cameraView.layer.addSublayer(previewLayer)
captureSession.startRunning()
captureSession.sessionPreset = AVCaptureSession.Preset.high
self.captureSession = captureSession
}
catch {
print(error)
}
}
}
t
Extension CameraViewController: AVCapturePhotoCaptureDelegate {
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
guard let data = photo.fileDataRepresentation(),
let image = UIImage(data: data) else {
return
}
captureSession?.stopRunning()
showEditPhoto(image: image)
}
private func showEditPhoto(image: UIImage) {
guard let resizedImage = image.sd_resizedImage(
with: CGSize(width: 640, height: 640),
scaleMode: .aspectFill
) else {
return
}
let vc = PostEditViewController(image: resizedImage)
if #available(iOS 14.0, *) {
vc.navigationItem.backButtonDisplayMode = .minimal
}
navigationController?.pushViewController(vc, animated: false)
}
Try using ‘ cgImageRepresentation()’ instead of ‘ fileDataRepresentation()’. And init a UIImage from the given cgImage
If I use the image before it is saved it is normal. But if I save it and use it later is is 90 degrees turned. How can I make sure it doesn't save sideways?
func saveEvent(_ center1: CLLocation, title2: String, imagePicked1: UIImage)
{
let data = UIImagePNGRepresentation(imagePicked1);///
let url = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(NSUUID().uuidString+".dat")
do {
try data!.write(to: url!, options: [])
} catch let e as NSError {
print("Error! \(e)");
return
}
let image11 = CKAsset(fileURL: url!)
self.eventRecord.setObject(image11 as CKAsset, forKey: "Picture")
let publicData = CKContainer.default().publicCloudDatabase
publicData.save(self.eventRecord, completionHandler: { record, error in
if error == nil
{
print("Image saved")
}else{
print(error!)
}
})
}
If you need to save your PNG with correct rotation you will need to redraw your image if its orientation it is not .up. You can redraw it as follow:
extension UIImage {
func png(isOpaque: Bool = true) -> Data? { flattened(isOpaque: isOpaque)?.pngData() }
func flattened(isOpaque: Bool = true) -> UIImage? {
if imageOrientation == .up { return self }
UIGraphicsBeginImageContextWithOptions(size, isOpaque, scale)
defer { UIGraphicsEndImageContext() }
draw(in: CGRect(origin: .zero, size: size))
return UIGraphicsGetImageFromCurrentImageContext()
}
}
edit/update:
For iOS10+ tvOS10+ you can use UIGraphicsImageRenderer:
extension UIImage {
func png(isOpaque: Bool = true) -> Data? { flattened(isOpaque: isOpaque).pngData() }
func flattened(isOpaque: Bool = true) -> UIImage {
if imageOrientation == .up { return self }
let format = imageRendererFormat
format.opaque = isOpaque
return UIGraphicsImageRenderer(size: size, format: format).image { _ in draw(at: .zero) }
}
}
Playground testing:
Usage for images without transparency:
let image = UIImage(data: try! Data(contentsOf: URL(string: "https://i.stack.imgur.com/varL9.jpg")!))!
if let data = image.png() {
let imageFromPNGData = UIImage(data: data)
}
With transparency :
if let data = image.png(isOpaque: false) {
let imageFromPNGData = UIImage(data: data)
}
Just convert the image to JPEG data instead. No need to redraw your image:
let imageData = image.jpegData(compressionQuality: 1.0)
You can use this as well to prevent it from changing of orientation.
func rotateImage(image: UIImage) -> UIImage? {
if (image.imageOrientation == UIImage.Orientation.up ) {
return image
}
UIGraphicsBeginImageContext(image.size)
image.draw(in: CGRect(origin: CGPoint.zero, size: image.size))
let copy = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return copy
}
I want to create a thumbnail image for files (word, excel, video ....)
This what i did:
import QuickLook
class ThumbsCreator: NSObject {
private var file : File?
init(file: File?) {
super.init()
self.file = file
}
func createThumb() {
let url = URL(string: (self.file?.path()))
}
}
After a lot of search, I found this solution :
import PDFKit
import AVKit
import WebKit
func createThumb() {
let url = URL(string: (self.file?.path()))
switch file?.type {
case: FileType.image.rawValue:
let image = UIImage(contentsOfFile: (url?.path)!)
_finalImage = self.createScaledImage(image: image!)
break
case: FileType.office.rawValue:
//Loading.......
break
case FileType.Pdf.rawValue:
guard let doc = PDFDocument(url: url!) else {return}
guard let page = doc.page(at: 0) else {return}
_finalImage = page.thumbnail(of: CGSize(width: 768, height: 1024), for: .cropBox)
break
case: FileType.video.rawValue:
let asset = AVAsset(url: url!)
let imageGenerator = AVAssetImageGenerator(asset: asset)
imageGenerator.appliesPreferredTrackTransform = true
let time = CMTime(seconds: 2, preferredTimescale: 1)
do {
let imageRef = try imageGenerator.copyCGImage(at: time, actualTime: nil)
_finalImage = UIImage(cgImage: imageRef)
} catch let error{
print("Error: \(error)")
}
break
}
}
func createScaledImage(image: UIImage) {
let THUMB_WIDTH = 150.0 - 40.0
let THUMB_HEIGHT = THUMB_WIDTH - 23.0
var itemThumb = resizeImage(image: image, constraintSize: CGSize(width: THUMB_WIDTH, height: THUMB_HEIGHT))
let thumbRect = CGRect(x: 0, y: 0, width: 10, height: 10)
UIGraphicsBeginImageContextWithOptions(thumbRect.size, true, 0.0)
let context = UIGraphicsGetCurrentContext()
// Fill a white rect
context?.setFillColor(gray: 1.0, alpha: 1.0)
context?.fill(thumbRect)
// Stroke a gray rect
let comps : [CGFloat] = [0.8, 0.8, 0.8, 1]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let strokeColor = CGColor(colorSpace: colorSpace, components: comps)
context?.setStrokeColor(strokeColor!)
UIRectFrame(thumbRect)
//CGColorRelease(strokeColor!)
itemThumb.draw(in: thumbRect.insetBy(dx: 1, dy: 1))
itemThumb = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
self.finishThumCreation(image: image)
}
}
Starting from iOS 13 and macOS 10.15, there is the QuickLook Thumbnailing API. It supports any file format for which the OS can provide a preview: either because the OS knows this format or because the owner of the third-party format provided a QuickLook plugin.
Here is an example based on Apple's tutorial:
func thumbnail(for fileURL: URL, size: CGSize, scale: CGFloat) {
let request = QLThumbnailGenerator
.Request(fileAt: fileURL, size: size, scale: scale,
representationTypes: .lowQualityThumbnail)
QLThumbnailGenerator.shared.generateRepresentations(for: request)
{ (thumbnail, type, error) in
DispatchQueue.main.async {
if thumbnail == nil || error != nil {
// Handle the error case gracefully.
} else {
// Display the thumbnail that you created.
}
}
}
}
On macOS before 10.15, in my app I fallback to NSWorkspace.shared.icon(forFile:) which provides a document icon based on the file type (but not a thumbnail).
You can use https://developer.apple.com/documentation/uikit/uidocumentinteractioncontroller/1616801-icons
var icons: [UIImage] { get }
let controller = UIDocumentInteractionController(url:someUrl)
print(controller.icons.first)
Only for a video
extension UIViewController {
func thumbnail(_ sourceURL:URL) -> UIImage {
let asset = AVAsset(url: sourceURL)
let imageGenerator = AVAssetImageGenerator(asset: asset)
imageGenerator.appliesPreferredTrackTransform = true
let time = CMTime(seconds: 1, preferredTimescale: 1)
do {
let imageRef = try imageGenerator.copyCGImage(at: time, actualTime: nil)
return UIImage(cgImage: imageRef)
} catch {
print(error)
return UIImage(named: "NoVideos")!
}
}
}
There's no good API for this yet. There is NSURLThumbnailDictionaryKey, but YMMV. You can indeed get icons via UIDocumentInteractionController.
here is my code
import UIKit
import AVFoundation
class ViewController: UIViewController {
#IBOutlet weak var cameraView: UIView!
var image: UIImage!
var captureSession = AVCaptureSession()
var backCamera: AVCaptureDevice?
var frontCamera: AVCaptureDevice?
var currentCamera: AVCaptureDevice?
var photoOutput: AVCapturePhotoOutput?
var cameraPreviewLayer: AVCaptureVideoPreviewLayer?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func viewDidAppear(_ animated: Bool) {
setupCaptureSession()
setupDevice()
setupInputOutput()
setupPreviewLayer()
startRunningCaptureSession()
}
#IBAction func cameraButton_Tab(_ sender: Any) {
let settings = AVCapturePhotoSettings()
// performSegue(withIdentifier: "showPhoto_Segue", sender: nil)
photoOutput?.capturePhoto(with: settings, delegate: self)
}
func setupCaptureSession() {
captureSession.sessionPreset = AVCaptureSession.Preset.photo
}
func setupDevice() {
let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [AVCaptureDevice.DeviceType.builtInWideAngleCamera], mediaType: AVMediaType.video, position: AVCaptureDevice.Position.unspecified)
let devices = deviceDiscoverySession.devices
for device in devices {
if device.position == AVCaptureDevice.Position.back {
backCamera = device
}else if device.position == AVCaptureDevice.Position.front{
frontCamera = device
}
}
currentCamera = backCamera
}
func setupInputOutput() {
do{
let captureDeviceInput = try AVCaptureDeviceInput(device: currentCamera!)
captureSession.addInput(captureDeviceInput)
photoOutput = AVCapturePhotoOutput()
photoOutput?.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey : AVVideoCodecType.jpeg])], completionHandler: nil)
captureSession.addOutput(photoOutput!)
}catch {
print(error)
}
}
func setupPreviewLayer() {
cameraPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
cameraPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
cameraPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.portrait
cameraPreviewLayer!.frame = self.cameraView.bounds
self.cameraView.layer.insertSublayer(cameraPreviewLayer!, at: 0)
}
func startRunningCaptureSession() {
captureSession.startRunning()
}
}
extension ViewController: AVCapturePhotoCaptureDelegate {
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
if let imageData = photo.fileDataRepresentation(){
image = UIImage(data: imageData)
}
}
}
See the image,
I want save the image which background's color is yellow
I can see the camera through of that
But I save the image, it seems that save the whole view, not square.
I make the UIImageView same size of yellow UIView and save the output,
it takes the whole view capture and resize of that.
Like change rectangle to square with squeeze
How I cant catch just yellow background size and save?
This didFinishProcessingPhoto will return the complete image like what camera is seeing. You won't the image directly which is shown in your PreviewLayer. So, in order to get the UIImage of shown PreviewLayer, you can resize the captured image.
Well, resize can also be done in two ways: One keeping aspect ratio and other by passing the exact size. I would recommend to go with aspect ratio because it will ensure that your image won't be squeeze or streched from any size, while passing wrong size won't able to fulfil you requirement.
Resize UIImage passing new CGSize:
extension UIImage {
func scaleImage(toSize newSize: CGSize) -> UIImage? {
var newImage: UIImage?
let newRect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height).integral
UIGraphicsBeginImageContextWithOptions(newSize, false, 0)
if let context = UIGraphicsGetCurrentContext(), let cgImage = self.cgImage {
context.interpolationQuality = .high
let flipVertical = CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: newSize.height)
context.concatenate(flipVertical)
context.draw(cgImage, in: newRect)
if let img = context.makeImage() {
newImage = UIImage(cgImage: img)
}
UIGraphicsEndImageContext()
}
return newImage
}
}
Usage: capturedImage.scaleImage(toSize: CGSize(width: 300, height: 300))
Resize UIImage keeping aspect ratio:
extension UIImage {
func scaleImage(toWidth newWidth: CGFloat) -> UIImage {
let scale = newWidth / self.size.width
let newHeight = self.size.height * scale
let newSize = CGSize(width: newWidth, height: newHeight)
let renderer = UIGraphicsImageRenderer(size: newSize)
let image = renderer.image { (context) in
self.draw(in: CGRect(origin: CGPoint(x: 0, y: 0), size: newSize))
}
return image
}
}
Usage: capturedImage.scaleImage(toWidth: 300)
Reference: Resize UIImage to 200x200pt/px
Update:
Keep the below method as it is in your code:
#IBAction func cameraButton_Tab(_ sender: Any) {
let settings = AVCapturePhotoSettings()
photoOutput?.capturePhoto(with: settings, delegate: self)
}
extension ViewController: AVCapturePhotoCaptureDelegate {
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
if let imageData = photo.fileDataRepresentation(){
let capturedImage = UIImage(data: imageData)
let cropImage = capturedImage.scaleImage(toWidth: cameraPreviewLayer!.frame.size.width) //It will return the Image size of Camera Preview
}
}
}