iOS 7 Core Image QR-код слишком размытие

вот мой код для генерации изображения QRCode

+ (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];
}

результат слишком размыто. Можно ли установить размер сгенерированного QR-кода?

8 ответов


Я собирался начать баунти на этот вопрос, но я нашел ответ.

вам нужен масштабный фильтр. Чтобы достичь этого с помощью 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


этот метод будет использовать 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;
}

я столкнулся с той же проблемой, основываясь на этом учебник вот как я это исправил :

-(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;
}

мне пришлось адаптировать ответ @ 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
}

самое простое решение-добавить следующее к вашему представлению изображения:

imgViewQR.layer.magnificationFilter = kCAFilterNearest

это автоматически повысит ваш сгенерированный QR-код изображения до размера imageview с помощью nearest что приводит к резкому, неровному изображению. Обычно это не то, что вы хотите при изменении размера значков/фотографий, но это идеальный для QR-кодов

enter image description here

(похоже, он не работает на симуляторе, но отлично работает на реальном устройстве


перепишите ответ @ Benoît Caron в Swift 3.1:

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
}

Возможно, вам стоит попробовать это. здесь - быстрый tutotial.

+ (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];
}

чтобы исправить размытие выглядит в QR-коде, сгенерированном с помощью CIFilter: основная идея для масштабирования изображения 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-код.