在iOS中保留EXIF的同时调整JPEG图像的大小和设置质量

ipakzgxi  于 2022-11-26  发布在  iOS
关注(0)|答案(4)|浏览(209)

在iOS应用程序中,我有一个NSData对象,它是一个JPEG文件,需要将其大小调整为给定的分辨率(2048 x2048),需要将JPEG质量设置为75%。这些设置需要在文件中保留EXIF数据。照片不在相机胶卷中--它是通过网络从数码单反相机中提取的,只是临时存储在应用程序中。如果图像在UIIimage中移动,EXIF数据就会丢失。如何在不丢失EXIF的情况下调整大小和设置质量?或者有没有办法在转换前去除EXIF数据,并在转换完成后将其添加回来?

ux6nzvsh

ux6nzvsh1#

您可以尝试使用CGImageSourceCreateThumbnailAtIndex和CGImageSourceCopyPropertiesAtIndex来调整作为jpeg图像的NSData对象的大小,而不会丢失EXIF。
我的灵感来自Problem setting exif data for an image
下面是我为同样目的编写的代码。
干杯

+ (NSData *)JPEGRepresentationSavedMetadataWithImage:(NSData *)imageData compressionQuality:(CGFloat)compressionQuality maxSize:(CGFloat)maxSize
{
  CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL);

  CFDictionaryRef options = (__bridge CFDictionaryRef)@{(id)kCGImageSourceCreateThumbnailWithTransform: (id)kCFBooleanTrue,
                                                        (id)kCGImageSourceCreateThumbnailFromImageIfAbsent: (id)kCFBooleanTrue,
                                                        (id)kCGImageSourceThumbnailMaxPixelSize: [NSNumber numberWithDouble: maxSize], // The maximum width and height in pixels of a thumbnail
                                                        (id)kCGImageDestinationLossyCompressionQuality: [NSNumber numberWithDouble:compressionQuality]};
  CGImageRef thumbnail = CGImageSourceCreateThumbnailAtIndex(source, 0, options); // Create scaled image

  CFStringRef UTI = kUTTypeJPEG;
  NSMutableData *destData = [NSMutableData data];
  CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)destData, UTI, 1, NULL);
  if (!destination) {
    NSLog(@"Failed to create image destination");
  }
  CGImageDestinationAddImage(destination, thumbnail, CGImageSourceCopyPropertiesAtIndex(source, 0, NULL)); // copy all metadata in source to destination
  if (!CGImageDestinationFinalize(destination)) {
    NSLog(@"Failed to create data from image destination");
  }

  CFRelease(destination);
  CFRelease(source);
  CFRelease(thumbnail);

  return [destData copy];
}
vql8enpb

vql8enpb2#

我也遇到了同样的问题,现在我可以上传文件与EXIF数据,也可以压缩照片,如果需要它,这为我解决了问题:

// Get your image.
NSURL *url = @"http://somewebsite.com/path/to/some/image.jpg";
UIImage *loImgPhoto = [NSData dataWithContentsOfURL:url];

// Get your metadata (includes the EXIF data).
CGImageSourceRef loImageOriginalSource = CGImageSourceCreateWithData(( CFDataRef) loDataFotoOriginal, NULL);
NSDictionary *loDicMetadata = (__bridge NSDictionary *) CGImageSourceCopyPropertiesAtIndex(loImageOriginalSource, 0, NULL);

// Set your compression quality (0.0 to 1.0).
NSMutableDictionary *loDicMutableMetadata = [loDicMetadata mutableCopy];
[loDicMutableMetadata setObject:@(lfCompressionQualityValue) forKey:(__bridge NSString *)kCGImageDestinationLossyCompressionQuality];

// Create an image destination.
NSMutableData *loNewImageDataWithExif = [NSMutableData data];
CGImageDestinationRef loImgDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)loNewImageDataWithExif, CGImageSourceGetType(loImageOriginalSource), 1, NULL);

// Add your image to the destination.
CGImageDestinationAddImage(loImgDestination, loImgPhoto.CGImage, (__bridge CFDictionaryRef) loDicMutableMetadata);

// Finalize the destination.
if (CGImageDestinationFinalize(loImgDestination))
   {
       NSLog(@"Successful image creation.");                   
       // process the image rendering, adjustment data creation and finalize the asset edit.

       //Upload photo with EXIF metadata
       [self myUploadMethod:loNewImageDataWithExif];

    }
    else
    {
          NSLog(@"Error -> failed to finalize the image.");                         
    }

CFRelease(loImageOriginalSource);
CFRelease(loImgDestination);
9jyewag0

9jyewag03#

支持Greener Chen的答案,但这是我在Swift 3中实现它的方式。

  • 我的函数接受一个jpeg缓冲区并返回一个jpeg缓冲区。它还检查是否需要调整大小(检查源代码的最大尺寸),如果这里没有什么可做的,就返回输入缓冲区。您可能需要适应您的用例
  • 我不认为你可以设置一个目标属性,如kCGImageDestinationLossyCompressionQualityCGImageSourceCreateThumbnailAtIndex(),这是一个CGImageSource函数-但从来没有尝试过。
  • 请注意,通过将相关密钥(kCGImageDestinationLossyCompressionQuality)作为CGImageDestinationAddImage的一个选项添加到保留的源元数据集,可将压缩添加到目标映像
  • 最初让我感到困惑的是,尽管我们为调整大小后的目标映像提供了完整的源映像元数据,但CGImageDestinationAddImage()非常聪明,可以忽略任何维度数据(W+H),并自动替换为正确的,调整大小的图像,尺寸。所以PixelHeightPixelWidth(“根”元数据)& PixelXDimension & PixelYDimension(EXIF)不会从源中继承,并且会正确设置为调整大小后的图像尺寸。
class func resizeImage(imageData: Data, maxResolution: Int, compression: CGFloat) -> Data? {
        
    // create image source from jpeg data
    if let myImageSource = CGImageSourceCreateWithData(imageData as CFData, nil) {
            
      // get source properties so we retain metadata (EXIF) for the downsized image
      if var metaData = CGImageSourceCopyPropertiesAtIndex(myImageSource,0, nil) as? [String:Any],
          let width = metaData[kCGImagePropertyPixelWidth as String] as? Int, let height = metaData[kCGImagePropertyPixelHeight as String] as? Int {
                
              let srcMaxResolution = max(width, height)
                
              // if max resolution is exceeded, then scale image to new resolution
              if srcMaxResolution >= maxResolution {
                  let scaleOptions  = [ kCGImageSourceThumbnailMaxPixelSize as String : maxResolution,
                                          kCGImageSourceCreateThumbnailFromImageAlways as String : true] as [String : Any]
                    
                  if let scaledImage = CGImageSourceCreateThumbnailAtIndex(myImageSource, 0, scaleOptions as CFDictionary) {
                        
                        // add compression ratio to desitnation options
                        metaData[kCGImageDestinationLossyCompressionQuality as String] = compression
                        
                        //create new jpeg
                        let newImageData = NSMutableData()
                        if let cgImageDestination = CGImageDestinationCreateWithData(newImageData, "public.jpeg" as CFString, 1, nil) {
                            
                            CGImageDestinationAddImage(cgImageDestination, scaledImage, metaData as CFDictionary)
                            CGImageDestinationFinalize(cgImageDestination)
                            
                            return newImageData as Data
                        }
                        
                    }
                }
            }
        }
        
        return nil
    }
}
flmtquvp

flmtquvp4#

您可以使用ExifTool之类的公用程式来删除并还原EXIF。这是一个跨平台的指令行公用程式。以下是执行您想要的作业的适当指令。
要删除EXIF:
exiftool -exif=图像. jpg
若要在编辑图像后再次恢复EXIF:
exiftool -文件中的标签image.jpg_original -exifimage.jpg
在本例中,我利用了ExifTool自动生成的“_original”备份。

相关问题