Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds the ability to generate a QR with a custom image instead of boxes #8

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions QRCode.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
31693FC71F0939F8000F9231 /* redButton.png in Resources */ = {isa = PBXBuildFile; fileRef = 31693FC61F0939F8000F9231 /* redButton.png */; };
52DC9B6E188D65A300272042 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52DC9B6D188D65A300272042 /* Foundation.framework */; };
52DC9B70188D65A300272042 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52DC9B6F188D65A300272042 /* CoreGraphics.framework */; };
52DC9B72188D65A300272042 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52DC9B71188D65A300272042 /* UIKit.framework */; };
Expand Down Expand Up @@ -43,6 +44,7 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
31693FC61F0939F8000F9231 /* redButton.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = redButton.png; sourceTree = "<group>"; };
52DC9B6A188D65A300272042 /* QRCode.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = QRCode.app; sourceTree = BUILT_PRODUCTS_DIR; };
52DC9B6D188D65A300272042 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
52DC9B6F188D65A300272042 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
Expand Down Expand Up @@ -180,6 +182,7 @@
isa = PBXGroup;
children = (
52DC9B9D188D660C00272042 /* [email protected] */,
31693FC61F0939F8000F9231 /* redButton.png */,
52DC9B9E188D660C00272042 /* [email protected] */,
52DC9B9F188D660C00272042 /* Icon.png */,
);
Expand Down Expand Up @@ -298,6 +301,7 @@
52DC9BA2188D660C00272042 /* Icon.png in Resources */,
52DC9B80188D65A300272042 /* Images.xcassets in Resources */,
52DC9BA0188D660C00272042 /* [email protected] in Resources */,
31693FC71F0939F8000F9231 /* redButton.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -522,6 +526,7 @@
52DC9B98188D65A300272042 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
52DC9B99188D65A300272042 /* Build configuration list for PBXNativeTarget "QRCodeTests" */ = {
isa = XCConfigurationList;
Expand All @@ -530,6 +535,7 @@
52DC9B9B188D65A300272042 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
Expand Down
4 changes: 3 additions & 1 deletion QRCode/MDAppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
CGFloat imageSize = ceilf(viewController.view.bounds.size.width * 0.6f);
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(floorf(viewController.view.bounds.size.width * 0.5f - imageSize * 0.5f), floorf(viewController.view.bounds.size.height * 0.5f - imageSize * 0.5f), imageSize, imageSize)];
[viewController.view addSubview:imageView];
imageView.image = [UIImage mdQRCodeForString:@"Hello, world!" size:imageView.bounds.size.width fillColor:[UIColor darkGrayColor]];
// imageView.image = [UIImage mdQRCodeForString:@"Hello, world!" size:imageView.bounds.size.width fillColor:[UIColor darkGrayColor]];
imageView.image = [UIImage mdQRCodeForString:@"Hello, world!" size:imageView.bounds.size.width fillImage:[UIImage imageNamed:@"redButton"]];

self.window.rootViewController = viewController;
return YES;
}
Expand Down
1 change: 1 addition & 0 deletions QRCode/QR/UIImage+MDQRCode.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
*/
+ (UIImage *)mdQRCodeForString:(NSString *)qrString size:(CGFloat)size;
+ (UIImage *)mdQRCodeForString:(NSString *)qrString size:(CGFloat)size fillColor:(UIColor *)fillColor;
+ (UIImage *)mdQRCodeForString:(NSString *)qrString size:(CGFloat)size fillImage:(UIImage *)fillImage;


@end
160 changes: 92 additions & 68 deletions QRCode/QR/UIImage+MDQRCode.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,82 +28,106 @@ @implementation UIImage (MDQRCode)

#pragma mark - private

+ (void)mdDrawQRCode:(QRcode *)code context:(CGContextRef)ctx size:(CGFloat)size fillColor:(UIColor *)fillColor {
int margin = 0;
unsigned char *data = code->data;
int width = code->width;
int totalWidth = width + margin * 2;
int imageSize = (int)floorf(size);

// @todo - review float->int stuff
int pixelSize = imageSize / totalWidth;
if (imageSize % totalWidth) {
pixelSize = imageSize / width;
margin = (imageSize - width * pixelSize) / 2;
}

CGRect rectDraw = CGRectMake(0.0f, 0.0f, pixelSize, pixelSize);
// draw
CGContextSetFillColorWithColor(ctx, fillColor.CGColor);
for(int i = 0; i < width; ++i) {
for(int j = 0; j < width; ++j) {
if(*data & 1) {
rectDraw.origin = CGPointMake(margin + j * pixelSize, margin + i * pixelSize);
CGContextAddRect(ctx, rectDraw);
}
++data;
}
}
CGContextFillPath(ctx);
+ (void)mdDrawQRCode:(QRcode *)code context:(CGContextRef)ctx size:(CGFloat)size fillImage:(UIImage *)fillImage orFillColor:(UIColor *)fillColor {
int margin = 0;
unsigned char *data = code->data;
int width = code->width;
int totalWidth = width + margin * 2;
int imageSize = (int)floorf(size);

// @todo - review float->int stuff
int pixelSize = imageSize / totalWidth;
if (imageSize % totalWidth) {
pixelSize = imageSize / width;
margin = (imageSize - width * pixelSize) / 2;
}

CGRect rectDraw = CGRectMake(0.0f, 0.0f, pixelSize, pixelSize);
// draw
if (fillColor) {
CGContextSetFillColorWithColor(ctx, fillColor.CGColor);
}

for(int i = 0; i < width; ++i) {
for(int j = 0; j < width; ++j) {
if(*data & 1) {
rectDraw.origin = CGPointMake(margin + j * pixelSize, margin + i * pixelSize);
if (fillColor) {
CGContextAddRect(ctx, rectDraw);
}else if (fillImage) {
UIGraphicsPushContext(ctx);
[fillImage drawInRect:rectDraw];
UIGraphicsPopContext();
}
}
++data;
}
}
CGContextFillPath(ctx);
}

+ (UIImage *)mdQRCodeForString:(NSString *)qrString size:(CGFloat)imageSize boxImage:(UIImage *)fillImage orFillColor:(UIColor *)fillColor{


if (0 == [qrString length]) {
return nil;
}

// generate QR
QRcode *code = QRcode_encodeString([qrString UTF8String], 0, QR_ECLEVEL_L, QR_MODE_8, 1);
if (!code) {
return nil;
}

CGFloat size = imageSize * [[UIScreen mainScreen] scale];
if (code->width > size) {
printf("Image size is less than qr code size (%d)\n", code->width);
return nil;
}

// create context
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

// The constants for specifying the alpha channel information are declared with the CGImageAlphaInfo type but can be passed to this parameter safely.

CGContextRef ctx = CGBitmapContextCreate(0, size, size, 8, size * 4, colorSpace, (CGBitmapInfo)kCGImageAlphaPremultipliedLast);

CGAffineTransform translateTransform = CGAffineTransformMakeTranslation(0, -size);
CGAffineTransform scaleTransform = CGAffineTransformMakeScale(1, -1);
CGContextConcatCTM(ctx, CGAffineTransformConcat(translateTransform, scaleTransform));

// draw QR on this context

[self mdDrawQRCode:code context:ctx size:size fillImage:fillImage orFillColor:fillColor];


// get image
CGImageRef qrCGImage = CGBitmapContextCreateImage(ctx);
UIImage * qrImage = [UIImage imageWithCGImage:qrCGImage];

// free memory
CGContextRelease(ctx);
CGImageRelease(qrCGImage);
CGColorSpaceRelease(colorSpace);
QRcode_free(code);
return qrImage;

}

#pragma mark - public


+ (UIImage *)mdQRCodeForString:(NSString *)qrString size:(CGFloat)size {
return [self mdQRCodeForString:qrString size:size fillColor:[UIColor blackColor]];
return [self mdQRCodeForString:qrString size:size fillColor:[UIColor blackColor]];
}

+ (UIImage *)mdQRCodeForString:(NSString *)qrString size:(CGFloat)imageSize fillColor:(UIColor *)fillColor {
if (0 == [qrString length]) {
return nil;
}

// generate QR
QRcode *code = QRcode_encodeString([qrString UTF8String], 0, QR_ECLEVEL_L, QR_MODE_8, 1);
if (!code) {
return nil;
}

CGFloat size = imageSize * [[UIScreen mainScreen] scale];
if (code->width > size) {
printf("Image size is less than qr code size (%d)\n", code->width);
return nil;
}

// create context
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

// The constants for specifying the alpha channel information are declared with the CGImageAlphaInfo type but can be passed to this parameter safely.

CGContextRef ctx = CGBitmapContextCreate(0, size, size, 8, size * 4, colorSpace, (CGBitmapInfo)kCGImageAlphaPremultipliedLast);

CGAffineTransform translateTransform = CGAffineTransformMakeTranslation(0, -size);
CGAffineTransform scaleTransform = CGAffineTransformMakeScale(1, -1);
CGContextConcatCTM(ctx, CGAffineTransformConcat(translateTransform, scaleTransform));

// draw QR on this context
[self mdDrawQRCode:code context:ctx size:size fillColor:fillColor];

// get image
CGImageRef qrCGImage = CGBitmapContextCreateImage(ctx);
UIImage * qrImage = [UIImage imageWithCGImage:qrCGImage];

// free memory
CGContextRelease(ctx);
CGImageRelease(qrCGImage);
CGColorSpaceRelease(colorSpace);
QRcode_free(code);
return qrImage;
return [self mdQRCodeForString:qrString size:imageSize boxImage:nil orFillColor:fillColor];

}
+ (UIImage *)mdQRCodeForString:(NSString *)qrString size:(CGFloat)imageSize fillImage:(UIImage *)fillImage{
return [self mdQRCodeForString:qrString size:imageSize boxImage:fillImage orFillColor:nil];
}


@end
Binary file added Resources/redButton.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.