macOS Objective-C中二维码矢量NSImage导出及CGPDFContextCreate使用问题
Hey there! Let's work through how to get a vector-format QR code instead of a bitmap in your project. The core issue is that CGBitmapContextCreateImage only works with bitmap contexts—since you're switching to a CGPDFContext (a vector context), we need to adjust how we capture the final output.
Key Changes to Your Code
Instead of generating a CGImage from the context, we'll leverage the PDF data produced by CGPDFContext, which retains vector information. Here's the revised full function, with explanations of critical adjustments:
+ (NSImage *)vectorQRImageForString:(NSString *)string imageSize:(CGFloat)size { if (![string length]) { return nil; } int str1; QRcode *code = QRcode_encodeString([string UTF8String], 0, str1, QR_MODE_8, 1); if (!code) { return nil; } // Prepare a data container to hold the PDF output NSMutableData* outputData = [[NSMutableData alloc] init]; CGDataConsumerRef dataConsumer = CGDataConsumerCreateWithCFData((CFMutableDataRef)outputData); if (!dataConsumer) { QRcode_free(code); return nil; } // Create a vector-based PDF context instead of a bitmap context CGRect rect = CGRectMake(0.0, 0.0, size, size); CGContextRef ctx = CGPDFContextCreate(dataConsumer, &rect, NULL); if (!ctx) { CGDataConsumerRelease(dataConsumer); QRcode_free(code); return nil; } // Start a new PDF page CGPDFContextBeginPage(ctx, NULL); // Adjust coordinate system to match your original bitmap context (top-left origin) // PDF contexts default to bottom-left origin, so we flip and translate to align CGAffineTransform flipTransform = CGAffineTransformMakeScale(1, -1); CGAffineTransform translateTransform = CGAffineTransformMakeTranslation(0, -size); CGContextConcatCTM(ctx, CGAffineTransformConcat(flipTransform, translateTransform)); // Draw the QR code as vector shapes (critical: ensure your drawQRCode method uses vector drawing!) [MainClass drawQRCode:code context:ctx size:size]; // Finalize the PDF page and clean up context resources CGPDFContextEndPage(ctx); CGContextRelease(ctx); CGDataConsumerRelease(dataConsumer); // Create an NSImage from the PDF data (this retains vector properties) NSImage *qrImage = [[NSImage alloc] initWithData:outputData]; qrImage.size = NSMakeSize(size, size); QRcode_free(code); return qrImage; }
Critical Notes for Success
Ensure
drawQRCode:uses vector drawing
Your existingdrawQRCodemethod must draw vector shapes (like rectangles) instead of manipulating bitmap pixels. If it's currently writing directly to bitmap data, rewrite it to useCGContextFillRectfor each QR cell. For example:+ (void)drawQRCode:(QRcode *)code context:(CGContextRef)ctx size:(CGFloat)size { if (!code || !ctx) return; CGFloat cellSize = size / code->width; CGContextSetFillColorWithColor(ctx, [NSColor blackColor].CGColor); for (int y = 0; y < code->width; y++) { for (int x = 0; x < code->width; x++) { unsigned char cell = code->data[y * code->width + x]; if (cell & 0x01) { CGRect cellRect = CGRectMake(x * cellSize, y * cellSize, cellSize, cellSize); CGContextFillRect(ctx, cellRect); } } } }Direct PDF export (optional)
If you don't need anNSImageand just want to save the vector QR code as a PDF file, skip creating theNSImageand write theoutputDatadirectly:[outputData writeToFile:@"/your/path/qrcode.pdf" atomically:YES];Coordinate system alignment
The flip/translate transform ensures your QR code isn't drawn upside-down, matching the output of your original bitmap context.
内容的提问来源于stack exchange,提问作者GeraldTheGerm

