【问题标题】:iOS 7 Core Image QR Code generation too bluriOS 7 Core Image QR Code 生成太模糊
【发布时间】:2014-04-17 23:19:20
【问题描述】:

这是我生成二维码图片的代码

+ (UIImage *)generateQRCodeWithString:(NSString *)string {
    NSData *stringData = [string dataUsingEncoding:NSUTF8StringEncoding];
    CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
    [filter setValue:stringData forKey:@"inputMessage"];
    [filter setValue:@"M" forKey:@"inputCorrectionLevel"];
    return [UIImage imageWithCIImage:filter.outputImage];
}

结果太模糊了。是否可以设置生成的二维码的大小?

【问题讨论】:

  • 你的uiimageview的contentmode是什么?
  • 按比例填充。但不确定它是否相关。 uiimage 本身是模糊的
  • 不要使用比例填充 - 尝试宽高比或宽高比填充
  • @Roecrew 不工作。我认为问题在于 uiimage 本身的大小

标签: ios uikit core-image


【解决方案1】:

我正要开始悬赏这个问题,但我找到了答案。

您需要的是一个比例过滤器。要使用 CoreImage 实现这一点,您需要执行以下操作:

CIImage *input = [CIImage imageWithCGImage: ImageView.Image.CGImage]; // input image is 100 X 100
CGAffineTransform transform = CGAffineTransformMakeScale(5.0f, 5.0f); // Scale by 5 times along both dimensions
CIImage *output = [input imageByApplyingTransform: transform];
// output image is now 500 X 500

来自这个答案: https://stackoverflow.com/a/16316701/2859764

【讨论】:

  • 很奇怪。它在模拟器上工作,但在设备上仍然模糊
  • @OMGPOP,您的图像必须具有大分辨率。 (超过 500x500)。
  • 只是对某些人的警告,这可能会产生一个好看的二维码,但对某些人来说,它也可能无法扫描。
  • 这应该取决于图像的原始分辨率。正确的? @kevinl
【解决方案2】:

此方法将使用 CoreImage 将 QR 码生成为 CIImage。不幸的是,没有简单的方法来禁用插值,因此缩放图像会产生模糊的代码。解决方法是使用位创建临时 CGImageRef 并将其绘制到灰度位图 CGContextRef 中。

在 OSX 上测试,但应该可以在 iOS 上运行。

- (CGImageRef)createQRImageForString:(NSString *)string size:(CGSize)size {
  // Setup the QR filter with our string
  CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
  [filter setDefaults];

  NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
  [filter setValue:data forKey:@"inputMessage"];
  CIImage *image = [filter valueForKey:@"outputImage"];

  // Calculate the size of the generated image and the scale for the desired image size
  CGRect extent = CGRectIntegral(image.extent);
  CGFloat scale = MIN(size.width / CGRectGetWidth(extent), size.height / CGRectGetHeight(extent));

  // Since CoreImage nicely interpolates, we need to create a bitmap image that we'll draw into
  // a bitmap context at the desired size;
  size_t width = CGRectGetWidth(extent) * scale;
  size_t height = CGRectGetHeight(extent) * scale;
  CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray();
  CGContextRef bitmapRef = CGBitmapContextCreate(nil, width, height, 8, 0, cs, (CGBitmapInfo)kCGImageAlphaNone);

#if TARGET_OS_IPHONE
  CIContext *context = [CIContext contextWithOptions:nil];
#else
  CIContext *context = [CIContext contextWithCGContext:bitmapRef options:nil];
#endif

  CGImageRef bitmapImage = [context createCGImage:image fromRect:extent];

  CGContextSetInterpolationQuality(bitmapRef, kCGInterpolationNone);
  CGContextScaleCTM(bitmapRef, scale, scale);
  CGContextDrawImage(bitmapRef, extent, bitmapImage);

  // Create an image with the contents of our bitmap
  CGImageRef scaledImage = CGBitmapContextCreateImage(bitmapRef);

  // Cleanup
  CGContextRelease(bitmapRef);
  CGImageRelease(bitmapImage);

  return scaledImage;
}

【讨论】:

  • 有一篇很棒的帖子描述了一种更紧凑、更灵活的方法:avanderlee.com/swift/qr-code-generation-swift
  • @DanWaylonis 这样,我们应该释放'cs'和'scaledImage'吗?正如 Xcode 分析并显示“存储到 'scaledImage' 中的对象的潜在泄漏”
【解决方案3】:

我遇到了同样的问题,基于这个tutorial这是我解决它的方法:

-(UIImage *) generateQRCodeWithString:(NSString *)string scale:(CGFloat) scale{
NSData *stringData = [string dataUsingEncoding:NSUTF8StringEncoding ];

CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
[filter setValue:stringData forKey:@"inputMessage"];
[filter setValue:@"M" forKey:@"inputCorrectionLevel"];

// Render the image into a CoreGraphics image
CGImageRef cgImage = [[CIContext contextWithOptions:nil] createCGImage:[filter outputImage] fromRect:[[filter outputImage] extent]];

//Scale the image usign CoreGraphics
UIGraphicsBeginImageContext(CGSizeMake([[filter outputImage] extent].size.width * scale, [filter outputImage].extent.size.width * scale));
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetInterpolationQuality(context, kCGInterpolationNone);
CGContextDrawImage(context, CGContextGetClipBoundingBox(context), cgImage);
UIImage *preImage = UIGraphicsGetImageFromCurrentImageContext();

//Cleaning up .
UIGraphicsEndImageContext();
CGImageRelease(cgImage);

// Rotate the image
UIImage *qrImage = [UIImage imageWithCGImage:[preImage CGImage]
                                            scale:[preImage scale]
                                      orientation:UIImageOrientationDownMirrored];
return qrImage;
}

【讨论】:

    【解决方案4】:

    我必须改编@cromanelli 的答案才能达到完美的清晰度:

    func convertTextToQRCode(text: String, withSize size: CGSize) -> UIImage {
    
        let data = text.dataUsingEncoding(NSISOLatin1StringEncoding, allowLossyConversion: false)
    
        let filter = CIFilter(name: "CIQRCodeGenerator")!
    
        filter.setValue(data, forKey: "inputMessage")
        filter.setValue("L", forKey: "inputCorrectionLevel")
    
        var qrcodeCIImage = filter.outputImage!
    
        let cgImage = CIContext(options:nil).createCGImage(qrcodeCIImage, fromRect: qrcodeCIImage.extent)
        UIGraphicsBeginImageContext(CGSizeMake(size.width * UIScreen.mainScreen().scale, size.height * UIScreen.mainScreen().scale))
        let context = UIGraphicsGetCurrentContext()
        CGContextSetInterpolationQuality(context, .None)
        CGContextDrawImage(context, CGContextGetClipBoundingBox(context), cgImage)
        let preImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
    
        let qrCodeImage = UIImage(CGImage: preImage.CGImage!, scale: 1.0/UIScreen.mainScreen().scale, orientation: .DownMirrored)
    
        return qrCodeImage
    }
    

    【讨论】:

      【解决方案5】:

      也许你应该试试这个。 Here 是一个快速教程。

      + (UIImage *)generateQRCodeImageBySize:(CGFloat)size andString:(NSString *)string {
      
          CIImage *qrCodeImage = [[CIImage alloc] init];
      
          NSData *stringData = [string dataUsingEncoding:NSISOLatin1StringEncoding allowLossyConversion:NO];
      
          CIFilter *ciFilter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
      
          [ciFilter setValue:stringData forKey:@"inputMessage"];
          [ciFilter setValue:@"Q" forKey:@"inputCorrectionLevel"];
      
          qrCodeImage = ciFilter.outputImage;
      
          CGFloat scaleX = size / qrCodeImage.extent.size.width;
          CGFloat scaleY = size / qrCodeImage.extent.size.height;
          CIImage *transformedQRImage = [qrCodeImage imageByApplyingTransform:CGAffineTransformMakeScale(scaleX, scaleY)];
      
          return [UIImage imageWithCIImage:transformedQRImage];
      }
      

      【讨论】:

        【解决方案6】:

        在 Swift 3.1 中重写 @Benoît Caron 的答案:

        func convertTextToQRCode(text: String, withSize size: CGSize) -> UIImage {
        
            let data = text.data(using: String.Encoding.isoLatin1, allowLossyConversion: false)
        
            let filter = CIFilter(name: "CIQRCodeGenerator")!
        
            filter.setValue(data, forKey: "inputMessage")
            filter.setValue("L", forKey: "inputCorrectionLevel")
        
            let qrcodeCIImage = filter.outputImage!
        
            let cgImage = CIContext(options:nil).createCGImage(qrcodeCIImage, from: qrcodeCIImage.extent)
            UIGraphicsBeginImageContext(CGSize(width: size.width * UIScreen.main.scale, height:size.height * UIScreen.main.scale))
            let context = UIGraphicsGetCurrentContext()
            context!.interpolationQuality = .none
        
            context?.draw(cgImage!, in: CGRect(x: 0.0,y: 0.0,width: context!.boundingBoxOfClipPath.width,height: context!.boundingBoxOfClipPath.height))
        
            let preImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
        
            let qrCodeImage = UIImage(cgImage: (preImage?.cgImage!)!, scale: 1.0/UIScreen.main.scale, orientation: .downMirrored)
        
            return qrCodeImage
        }
        

        【讨论】:

        • 不错的答案,但添加一些安全展开语法会更好,谢谢
        【解决方案7】:

        修复使用 CIFilter 生成的 QR 码中的模糊外观: 放大 QR 码图像而不使其模糊的基本思想是更改其变换属性。但是,由于放大图像并同时将其添加到图像视图中是不可行的,因此我们将创建另一个将被放大的 CIImage,然后将其分配给图像视图。

        目标 C:

        - (void)createQRForData:(id)qrData forImageView:(UIImageView *)imageView {
        
            NSData *data = [NSJSONSerialization dataWithJSONObject:qrData options:NSJSONWritingPrettyPrinted error:nil];
        
            CIFilter *qrFilter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
            [qrFilter setValue:data forKey:@"inputMessage"];
            [qrFilter setValue:@"Q" forKey: @"inputCorrectionLevel"];
        
            //Scaling the CIFilter image as per the UIImageView frame. 
            CGFloat scaleX = imageView.frame.size.width / qrFilter.outputImage.extent.size.width;
            CGFloat scaleY = imageView.frame.size.height / qrFilter.outputImage.extent.size.height;
            CIImage *transformedImage = [qrFilter.outputImage imageByApplyingTransform:CGAffineTransformMakeScale(scaleX, scaleY)];
        
            UIImage *QRImage = [UIImage imageWithCIImage:transformedImage];
        
            imageView.image = QRImage;
        }
        

        这帮助我解决了 QR 码中的模糊外观。

        【讨论】:

          【解决方案8】:

          最简单的解决方案是将以下内容添加到您的图像视图中:

          imgViewQR.layer.magnificationFilter = kCAFilterNearest
          

          这将使用nearest 自动将您生成的二维码图像放大到 imageview 的大小,从而生成清晰的像素化图像。这通常不是您在调整图标/照片大小时想要的,但对于 QR 码来说是完美

          (它似乎在模拟器上不起作用,但在真实设备上效果很好

          【讨论】:

            【解决方案9】:

            这是一个 SwiftUI 版本。

            import SwiftUI
            import CoreImage.CIFilterBuiltins
            
            struct QRCodeView: View {
                let message: Data
            
                var body: some View {
                    GeometryReader { reader in
                        generate(size: reader.size)
                    }
                }
            
                func generate(size: CGSize) -> Image {
                    let filter = CIFilter.qrCodeGenerator()
                    filter.message = message
                    filter.correctionLevel = "Q"
            
                    if let output = filter.outputImage {
                        let x = size.width / output.extent.size.width
                        let y = size.height / output.extent.size.height
            
                        let scaled = output.transformed(by: CGAffineTransform(scaleX: x, y: y))
                        if let cg = CIContext().createCGImage(scaled, from: scaled.extent) {
                            return Image(uiImage: UIImage(cgImage: cg))
                        }
                    }
            
                    return Image(systemName: "xmark.circle")
                }
            }
            
            struct QRCodeView_Previews: PreviewProvider {
                static var previews: some View {
                    QRCodeView(message: Data("Hi mom".utf8))
                        .frame(width: 200, height: 200)
                }
            }
            

            【讨论】:

              【解决方案10】:

              Swift 5.5

              // 在 5.5 中更改

              imgViewQR.layer.magnificationFilter = CALayerContentsFilter.nearest
              

              【讨论】:

              • 你好 Ronald,这看起来更像是对 this answer 的评论,而不是新的答案?
              猜你喜欢
              • 2019-01-24
              • 1970-01-01
              • 1970-01-01
              • 2022-12-18
              • 1970-01-01
              • 2012-09-15
              • 1970-01-01
              • 2015-09-23
              • 2013-06-06
              相关资源
              最近更新 更多