0

What do I simply do?

let pasteboard = UIPasteboard.general
let base64EncodedImageString = "here_base_64_string_image"
let data = Data(base64Encoded: base64EncodedImageString)
let url = data?.write(withName: "image.jpeg")
pasteboard.image = UIImage(url: url) //and now when I try to paste somewhere that image for example in imessage, it is rotated... why?

What may be important:

  1. It happens only for images created by camera.
  2. However, if use exactly the same process (!) to create activityItems for UIActivityViewController and try to use iMessage app, then it works... why? What makes the difference?

I use above two simple extensions for UIImage and Data:

extension Data {
    func write(withName name: String) -> URL {
        let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(name)
        do {
            try write(to: url, options: NSData.WritingOptions.atomic)
            return url
        } catch {
            return url
        }
    }
}

extension UIImage {
    convenience init?(url: URL?) {
        guard let url = url else {
            return nil
        }
        do {
            self.init(data: try Data(contentsOf: url))
        } catch {
            return nil
        }
    }
}

Before server returns base64EncodedString I upload an image from camera like this:

func imagePickerController(
    _ picker: UIImagePickerController,
    didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]
) {
    let image = info[.originalImage] as? UIImage
    let encodedBase64 = image?.jpegData(compressionQuality: 0.9)?.base64EncodedString() ?? ""
    //upload encodedBase64 to the server... that is all
}
Bartłomiej Semańczyk
  • 59,234
  • 49
  • 233
  • 358
  • Apparently you are losing the image orientation information between getting it from camera and converting to Data. Could you please post the full code from the point of getting the image from camera through the saving it to a Data object. – Vadim Dagman Feb 12 '22 at 16:02
  • I dont have that code, I receive base64encoded from server. But I was just informed that these images are from camera. However, please consider that it IS NOT rotated when I try to share that image via UIActivityController… – Bartłomiej Semańczyk Feb 12 '22 at 16:19
  • @BartłomiejSemańczyk As already mentioned you are probably losing the orientation somewhere in the process. If you are using JPEG data representation this shouldn't be a problem but if you get the PNG data representation your orientation will be discarded. You have a few options. You can redraw your image with a new image context before getting the PNG data or use jpeg during the whole process – Leo Dabus Feb 12 '22 at 16:38
  • possible duplicate of https://stackoverflow.com/a/42098812/2303865 – Leo Dabus Feb 12 '22 at 16:39
  • @LeoDabus The image got from camera and uploaded to server is used with jpegData(compressionQuality: 0.9)?.base64EncodedString() – Bartłomiej Semańczyk Feb 12 '22 at 16:43
  • This doesn't make any sense. Anyway you can simply do what I suggested in the link above and your image won't depend on the orientation anymore. If you edit your question and post your image picker code I might be able to spot where the issue occurs. I need the whole process. – Leo Dabus Feb 12 '22 at 16:47
  • @LeoDabus Should it also be wrong for UIActivityController? – Bartłomiej Semańczyk Feb 12 '22 at 16:51
  • It is just a guess but it seems that your issue is when using the pasteboard – Leo Dabus Feb 12 '22 at 16:52
  • Regardless of where you are losing the orientation redrawing the image before getting its data representation would solve it. – Leo Dabus Feb 12 '22 at 16:54
  • Not related to your question but you should use UIImage(contentsOfFile:) when loading a local resource image – Leo Dabus Feb 12 '22 at 17:03
  • I actually doing this. Look at UIImage extension – Bartłomiej Semańczyk Feb 12 '22 at 17:08
  • @BartłomiejSemańczyk not the same [contentsOfFile](https://developer.apple.com/documentation/uikit/uiimage/1624112-init) loads the image data into memory and marks it as purgeable. data initializer doesn't. – Leo Dabus Feb 12 '22 at 17:20

1 Answers1

1

I am not sure but I think UIPasteBoard converts your image to PNG and discards its orientation. You can explicitly tell the kind of data you are adding to the pasteboard but I am not sure if this would work for your scenery.

extension Data {
    var image: UIImage? { UIImage(data: self) }
}

setting your pasteboard data

UIPasteboard.general.setData(jpegData, forPasteboardType: "public.jpeg")

loading the data from pasteboard

if let pbImage = UIPasteboard.general.data(forPasteboardType: "public.jpeg")?.image {

}

Or Redrawing your image before setting your pasteboard image property

extension UIImage {
    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()
    }
}

UIPasteboard.general.image = image.flattened()
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
  • In you case I would simply flatten the image before sending the jpeg data representation to the server. This would solve the rest. – Leo Dabus Feb 12 '22 at 17:25
  • 1
    `setData(:forPasteboardType` did work. I dont know why, but propably UIPasteboard discards orientation as you mentioned. Thank you. – Bartłomiej Semańczyk Feb 12 '22 at 18:10