Ich lade ein Bild von einer URL, die von einem Drittanbieter bereitgestellt wurde. Die URL enthält keine Dateierweiterung (oder keinen Dateinamen) (da es sich um eine verdeckte URL handelt). Ich kann die Daten daraus (in Form von NSData) nehmen und in ein UIImage laden und gut anzeigen.
Ich möchte diese Daten in einer Datei speichern. Ich weiß jedoch nicht, in welchem Format die Daten vorliegen (PNG, JPG, BMP). Ich nehme an, es ist JPG (da es sich um ein Bild aus dem Internet handelt), aber gibt es eine programmatische Möglichkeit, dies sicher herauszufinden? Ich habe mich in StackOverflow und in der Dokumentation umgesehen und konnte nichts finden.
TIA.
Bearbeiten: Brauche ich wirklich die Dateierweiterung? Ich speichere es auf einem externen Speicher (Amazon S3), aber wenn man bedenkt, dass es immer im Kontext von iOS oder einem Browser verwendet wird (beide scheinen bei der Interpretation der Daten ohne Erweiterung in Ordnung zu sein), ist dies möglicherweise kein Problem .
Antworten:
Wenn Sie NSData für die Bilddatei haben, können Sie den Inhaltstyp anhand des ersten Bytes erraten:
+ (NSString *)contentTypeForImageData:(NSData *)data { uint8_t c; [data getBytes:&c length:1]; switch (c) { case 0xFF: return @"image/jpeg"; case 0x89: return @"image/png"; case 0x47: return @"image/gif"; case 0x49: case 0x4D: return @"image/tiff"; } return nil; }
quelle
Um die Antwort von wl. Zu verbessern , finden Sie hier eine viel erweiterte und präzisere Möglichkeit, den MIME-Typ des Bildes anhand der Signatur vorherzusagen. Der Code wurde weitgehend von PHPs ext / standard / image.c inspiriert .
- (NSString *)mimeTypeByGuessingFromData:(NSData *)data { char bytes[12] = {0}; [data getBytes:&bytes length:12]; const char bmp[2] = {'B', 'M'}; const char gif[3] = {'G', 'I', 'F'}; const char swf[3] = {'F', 'W', 'S'}; const char swc[3] = {'C', 'W', 'S'}; const char jpg[3] = {0xff, 0xd8, 0xff}; const char psd[4] = {'8', 'B', 'P', 'S'}; const char iff[4] = {'F', 'O', 'R', 'M'}; const char webp[4] = {'R', 'I', 'F', 'F'}; const char ico[4] = {0x00, 0x00, 0x01, 0x00}; const char tif_ii[4] = {'I','I', 0x2A, 0x00}; const char tif_mm[4] = {'M','M', 0x00, 0x2A}; const char png[8] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a}; const char jp2[12] = {0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a}; if (!memcmp(bytes, bmp, 2)) { return @"image/x-ms-bmp"; } else if (!memcmp(bytes, gif, 3)) { return @"image/gif"; } else if (!memcmp(bytes, jpg, 3)) { return @"image/jpeg"; } else if (!memcmp(bytes, psd, 4)) { return @"image/psd"; } else if (!memcmp(bytes, iff, 4)) { return @"image/iff"; } else if (!memcmp(bytes, webp, 4)) { return @"image/webp"; } else if (!memcmp(bytes, ico, 4)) { return @"image/vnd.microsoft.icon"; } else if (!memcmp(bytes, tif_ii, 4) || !memcmp(bytes, tif_mm, 4)) { return @"image/tiff"; } else if (!memcmp(bytes, png, 8)) { return @"image/png"; } else if (!memcmp(bytes, jp2, 12)) { return @"image/jp2"; } return @"application/octet-stream"; // default type }
Die obige Methode erkennt die folgenden Bildtypen:
image/x-ms-bmp
(bmp)image/gif
(gif)image/jpeg
(jpg, jpeg)image/psd
(psd)image/iff
(iff)image/webp
(webp)image/vnd.microsoft.icon
(ico)image/tiff
(tif, tiff)image/png
(png)image/jp2
(jp2)Leider gibt es keine einfache Möglichkeit, diese Art von Informationen von einer
UIImage
Instanz abzurufen, da auf die gekapselten Bitmap-Daten nicht zugegriffen werden kann.quelle
Die Lösung von @Tai Le für Swift 3 besteht darin, ganze Daten einem Byte-Array zuzuweisen. Wenn ein Bild groß ist, kann es zum Absturz kommen. Diese Lösung weist nur ein einzelnes Byte zu:
import Foundation public extension Data { var fileExtension: String { var values = [UInt8](repeating:0, count:1) self.copyBytes(to: &values, count: 1) let ext: String switch (values[0]) { case 0xFF: ext = ".jpg" case 0x89: ext = ".png" case 0x47: ext = ".gif" case 0x49, 0x4D : ext = ".tiff" default: ext = ".png" } return ext } }
quelle
Wenn Sie das Bild von einer URL abrufen, können Sie vermutlich die HTTP-Antwortheader überprüfen. Enthält der
Content-Type
Header etwas Nützliches? (Ich würde mir das vorstellen, da ein Browser das Bild wahrscheinlich korrekt anzeigen könnte und dies nur tun könnte, wenn der Inhaltstyp entsprechend eingestellt wäre.)quelle
Swift3-Version:
let data: Data = UIImagePNGRepresentation(yourImage)! extension Data { var format: String { let array = [UInt8](self) let ext: String switch (array[0]) { case 0xFF: ext = "jpg" case 0x89: ext = "png" case 0x47: ext = "gif" case 0x49, 0x4D : ext = "tiff" default: ext = "unknown" } return ext } }
quelle
Data
es bereits eine Sammlung von Bytes, warum nicht einfachfirst
?Eine Alternative zur akzeptierten Antwort besteht darin, die UTI des Bildes mit zu überprüfen
image I/O frameWork
. Sie können den Bildtyp von UTI erreichen. Versuche dies:CGImageSourceRef imgSrc = CGImageSourceCreateWithData((CFDataRef)data, NULL); NSString *uti = (NSString*)CGImageSourceGetType(imgSrc); NSLog(@"%@",uti);
Die UTI eines GIF-Bildes lautet beispielsweise "com.compuserve.gif" und die UTI des PNG-Bildes lautet "public.png". ABER Sie können keine UTI aus einem
image I/O frameWork
nicht erkannten Bild erzielen .quelle
Um den Bildtyp von einem zu erhalten
UIImage
, können Sie die Typkennung (UTI) aus den zugrunde liegenden Quarzbilddaten abrufen:extension UIImage { var typeIdentifier: String? { cgImage?.utType as String? } }
Um die Bildtypkennung von einer URL zu erhalten, hängt es davon ab, ob die URL auf eine lokale Ressource verweist oder nicht:
extension URL { // for local resources (fileURLs) var typeIdentifier: String? { (try? resourceValues(forKeys: [.typeIdentifierKey]))?.typeIdentifier } // for non local resources (web) you can get it asyncronously func asyncTypeIdentifier(completion: @escaping ((String?, Error?) -> Void)) { var request = URLRequest(url: self) request.httpMethod = "HEAD" URLSession.shared.dataTask(with: request) { _ , response , error in completion((response as? HTTPURLResponse)?.mimeType, error) }.resume() } }
let imageURL = URL(string: "https://i.stack.imgur.com/varL9.jpg")! imageURL.asyncTypeIdentifier { typeIdentifier, error in guard let typeIdentifier = typeIdentifier, error == nil else { return } print("typeIdentifier:", typeIdentifier) }
quelle
Wenn es Ihnen wirklich wichtig ist, müssen Sie den Bytestream untersuchen. Ein JPEG beginnt mit den Bytes FF D8. Ein PNG beginnt mit 89 50 4E 47 0D 0A 1A 0A. Ich weiß nicht, ob BMP einen ähnlichen Header hat, aber ich glaube nicht, dass Sie 2010 zu wahrscheinlich auf solche im Web stoßen werden.
Aber ist es dir wirklich wichtig? Können Sie es nicht einfach als unbekanntes Bild behandeln und Cocoa Touch die Arbeit machen lassen?
quelle
Implementieren Sie eine Signaturprüfung für jedes bekannte Bildformat. Hier ist eine schnelle Objective-C-Funktion, die dies für PNG-Daten erledigt:
// Verify that NSData contains PNG data by checking the signature - (BOOL) isPNGData:(NSData*)data { // Verify that the PNG file signature matches static const unsigned char png_sign[8] = {137, 80, 78, 71, 13, 10, 26, 10}; unsigned char sig[8] = {0, 0, 0, 0, 0, 0, 0, 0}; if ([data length] <= 8) { return FALSE; } [data getBytes:&sig length:8]; BOOL same = (memcmp(sig, png_sign, 8) == 0); return same; }
quelle
Meine verbesserte Lösung basierend auf @ccoroom
// Data+ImageContentType.swift import Foundation extension Data { enum ImageContentType: String { case jpg, png, gif, tiff, unknown var fileExtension: String { return self.rawValue } } var imageContentType: ImageContentType { var values = [UInt8](repeating: 0, count: 1) self.copyBytes(to: &values, count: 1) switch (values[0]) { case 0xFF: return .jpg case 0x89: return .png case 0x47: return .gif case 0x49, 0x4D : return .tiff default: return .unknown } } }
Einige Anwendungsbeispiele:
//load some image do { let imageData = try Data(contentsOf: URL(string: "https://myServer/images/test.jpg")!) } catch { print("Unable to load image: \(error)") } //content type check guard [Data.ImageContentType.jpg, Data.ImageContentType.png].contains(imageData.imageContentType) else { print("unsupported image type") return } //set file extension let image = "myImage.\(imageData.imageContentType.fileExtension)" //myImage.jpg
quelle
Ich habe eine Bibliothek erstellt, um den Bildtyp von NSData zu überprüfen:
https://github.com/sweetmandm/ImageFormatInspector
quelle