1

I've been trying to figure out how to export my QR codes on my little project as a vector.

I start from qrImageForString function which generates the image initially, and does so as a bitmap.

The main two lines in question are:

CGContextRef ctx = CGBitmapContextCreate(0, size, size, 8, size * 4, colorSpace,kCGImageAlphaPremultipliedLast);
CGImageRef qrCGImage = CGBitmapContextCreateImage(ctx);

For the first one I think this may be a replacement:

NSRect rect = CGRectMake(0.0, 0.0, 750.0, 750.0);
CGContextRef ctx = CGPDFContextCreate(dataConsumer, &rect, NULL);

However I'm not sure how to replace the second line to make it a vector.

Full function is:

+ (NSImage *)qrImageForString:(NSString *)string imageSize:(CGFloat)size {
    if (![string length]) {
        return nil;
    }
    
    int str1;
      
    QRcode *code = QRcode_encodeString([string UTF8String], 0, str1, QR_MODE_8, 1);
    
    
    // create context
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef ctx = CGBitmapContextCreate(0, size, size, 8, size * 4, colorSpace, kCGImageAlphaPremultipliedLast);
    
    NSRect rect = CGRectMake(0.0, 0.0, 750.0, 750.0);

    
    NSMutableData* outputData = [[NSMutableData alloc] init];
    CGDataConsumerRef dataConsumer = CGDataConsumerCreateWithCFData((CFMutableDataRef)outputData);
      
    CGAffineTransform translateTransform = CGAffineTransformMakeTranslation(0, -size);
    CGAffineTransform scaleTransform = CGAffineTransformMakeScale(1, -1);
    CGContextConcatCTM(ctx, CGAffineTransformConcat(translateTransform, scaleTransform));
    
    // draw QR on this context
    [MainClass drawQRCode:code context:ctx size:size];
    
    // get image
    CGImageRef qrCGImage = CGBitmapContextCreateImage(ctx);

    
    
    NSImage *qrImage = [[NSImage alloc] initWithCGImage:qrCGImage size:NSZeroSize];
  
    
    // some releases
    CGContextRelease(ctx);
    CGImageRelease(qrCGImage);
    CGColorSpaceRelease(colorSpace);
    QRcode_free(code);
    
    return qrImage;
}
Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
  • See [How to make dataWithEPSInsideRect vector rather than bitmap in vector format?](https://stackoverflow.com/questions/69743622/how-to-make-datawithepsinsiderect-vector-rather-than-bitmap-in-vector-format). – Willeke Nov 09 '21 at 14:44
  • I don't think this answers my question, the example here shows drawing with core graphics and then drawing it to the view and then writing the file the data from that drawing to EPS. I'm trying to figure out how I can convert my drawing from bitmap to vector I think i'm half way but i'm not sure how i convert this line to a vector equivalent CGImageRef qrCGImage = CGBitmapContextCreateImage(ctx); Then I can drae to view and then to file - but right now i'm struggling to get the output of the QR in vector format. – GeraldTheGerm Nov 09 '21 at 15:55
  • Do you want to draw a bitmap and convert the bitmap to vector? Why don't you want to draw a vector? What are you trying to accomplish? The linked accepted answer converts drawing code to EPS, why can't you use it? – Willeke Nov 09 '21 at 17:34
  • I am using the QR Library which at present draws bitmap - i'm trying to draw a vector not convert a bitmap to vector - it's just it currently draws as bitmap so i'm trying to replace this line which clearly makes a bitmap into something that will make a vector: CGImageRef qrCGImage = CGBitmapContextCreateImage(ctx); It's just at present it's drawing in bitmap so I can't draw it to EPS as it's not vector I need to figure out how to convert the drawing code to draw as PDF rather than bitmap so I can draw to EPS. – GeraldTheGerm Nov 09 '21 at 17:44
  • This is what i'm using https://github.com/moqod/ios-qr-code-encoder/blob/master/QRCode/QR/UIImage%2BMDQRCode.m except i've modified it slightly for macOS and NSImage. – GeraldTheGerm Nov 09 '21 at 17:45
  • Take the code from [How to make dataWithEPSInsideRect vector rather than bitmap in vector format?](https://stackoverflow.com/a/69744176) and replace the drawing code by the QR drawing code. – Willeke Nov 09 '21 at 23:08
  • Maybe this helps: [Create QR Barcodes on Mac](https://stackoverflow.com/questions/16002314/create-qr-barcodes-on-mac) – Willeke Nov 10 '21 at 00:16
  • Drawing happens on this fuction `+ (void)drawQRCode:(QRcode *)code context:(CGContextRef)ctx size:(CGFloat)size {` I need to export it on this function: `- (void)exportSheetDidEnd: (NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)dummy` How can I get the draw function to draw to a view that is also accessible to the export function? I've created a view outside of the instance: `NSView * viewtoday;` In the draw function i've added this: – GeraldTheGerm Nov 10 '21 at 13:45
  • ` CGContextFillPath(ctx); viewtoday = [[self alloc] initWithFrame: NSRectFromCGRect(CGRectMake(0, 0, 800, 800))];` And in the export function i've added this: `NSData *data = [viewtoday dataWithPDFInsideRect: viewtoday.bounds]; [data writeToURL: [NSURL fileURLWithPath:path] atomically: YES];` But it's exporting blank files rather than the drawing? – GeraldTheGerm Nov 10 '21 at 13:46

1 Answers1

2

Copied from How to make dataWithEPSInsideRect vector rather than bitmap in vector format?: Create an offscreen view, set up the draw method of the view to include your graphic and then use NSView's dataWithEPSInsideRect: method.

I made mdDrawQRCode:context:size:fillColor: an instance method of the view but it can be a method of different class. The view:

@interface MyView : NSView

@property (strong) NSString *qrString;

@end


@implementation MyView

- (void)drawRect:(NSRect)dirtyRect {
    [super drawRect:dirtyRect];

    if (!self.qrString)
        return;

    CGContextRef cgContext = [[NSGraphicsContext currentContext] CGContext];
    CGContextSaveGState(cgContext);

    QRcode *code = QRcode_encodeString([self.qrString UTF8String], 0, QR_ECLEVEL_L, QR_MODE_8, 1);
    [self mdDrawQRCode:code context:cgContext size:self.bounds.size.width fillColor:[NSColor blackColor]];
    QRcode_free(code);

    CGContextRestoreGState(cgContext);
}

@end

Use the view like:

MyView *myView = [[MyView alloc] initWithFrame:NSMakeRect(0, 0, 100.0, 100.0)];
myView.qrString = @"Hello World!";
NSData *data = [myView dataWithEPSInsideRect:myView.bounds];
Willeke
  • 14,578
  • 4
  • 19
  • 47
  • Thank you for your patience, I think I was just trying to overthink things too much! Appreciate your help and patience with me! – GeraldTheGerm Nov 10 '21 at 17:43