Thursday, November 23, 2017

#1 2017-11-09 06:33:07 am

ProGrammer
Member
Registered: 2016-12-16
Posts: 16

Generate QR code (offline)

I know that it is possible to create a QR code using AppleScript and a curl command to download, then open a QR code generated with chart.apis.google.com for example.

This required an active internet connection... but the following equivalent written in OBJ-C is able to carry out the same task using essentially the same UI components found in Xcode's AppleScript ObjC interface designer.

Applescript:

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

NSString *info = @"http://codeafterhours.wordpress.com";

// Generation of QR code image
NSData *qrCodeData = [info dataUsingEncoding:NSISOLatin1StringEncoding]; // recommended encoding
CIFilter *qrCodeFilter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
[qrCodeFilter setValue:qrCodeData forKey:@"inputMessage"];
[qrCodeFilter setValue:@"M" forKey:@"inputCorrectionLevel"]; //default of L,M,Q & H modes

CIImage *qrCodeImage = qrCodeFilter.outputImage;

CGRect imageSize = CGRectIntegral(qrCodeImage.extent); // generated image size
CGSize outputSize = CGSizeMake(240.0, 240.0); // required image size
CIImage *imageByTransform = [qrCodeImage imageByApplyingTransform:CGAffineTransformMakeScale(outputSize.width/CGRectGetWidth(imageSize), outputSize.height/CGRectGetHeight(imageSize))];

UIImage *qrCodeImageByTransform = [UIImage imageWithCIImage:imageByTransform];
self.imgViewQRCode.image = qrCodeImageByTransform;

// Generation of bar code image
CIFilter *barCodeFilter = [CIFilter filterWithName:@"CICode128BarcodeGenerator"];
NSData *barCodeData = [info dataUsingEncoding:NSASCIIStringEncoding]; // recommended encoding
[barCodeFilter setValue:barCodeData forKey:@"inputMessage"];
[barCodeFilter setValue:[NSNumber numberWithFloat:7.0] forKey:@"inputQuietSpace"]; //default whitespace on sides of barcode

CIImage *barCodeImage = barCodeFilter.outputImage;
self.imgViewBarCode.image = [UIImage imageWithCIImage:barCodeImage];
}

Source: https://codeafterhours.wordpress.com/20 … es-in-ios/

I would like to be able to carry out the same function just with the AppleScriptObjC framework instead of the purely ObjC above.
The key emphasis is offline and without additional terminal tools that need to be installed first (i.e. link text gets converted to QR code and displayed in the NSImageView or similar).
As Google was not very helpful in pointing me in the right direction, I have my fingers crossed that the translation between the code above and its AppleScriptObjC equivalent is straightforward and something I can get a hand with (especially since ObjC is in the name of the target framework).

Thank you in advance.


Filed under: applescript, xcode, QR code

Offline

 

#2 2017-11-09 06:42:56 am

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 5179

Re: Generate QR code (offline)

Here's some code I've used. However, the scaling involves using CGAffineTransformMakeScale(), which I believe is not working from ASObjC in 10.13. You can use an alternative method of scaling instead.

Applescript:

use framework "Foundation"
use framework "AppKit"
use framework "CoreImage"
use scripting additions

set destPath to (POSIX path of (path to desktop folder)) & "Test QR Code.jpg"

my makeQRForString:"https://www.macosxautomation.com/applescript/apps/" ofWidth:360 savingTo:destPath

on makeQRForString:theString ofWidth:theWidth savingTo:posixPath
   set anImageFilter to current application's CIFilter's filterWithName:"CIQRCodeGenerator"
   anImageFilter's setDefaults()
   set thisURLString to current application's NSString's stringWithString:theString
   set thisData to thisURLString's dataUsingEncoding:(current application's NSUTF8StringEncoding)
   anImageFilter's setValue:thisData forKey:"inputMessage"
   anImageFilter's setValue:"L" forKey:"inputCorrectionLevel"
   
   set baseImage to anImageFilter's outputImage()
   set baseImageWidth to baseImage's extent()'s |size|()'s width()
   set theScale to theWidth / baseImageWidth
   
   set thisTransform to current application's CGAffineTransform's CGAffineTransformMakeScale(theScale, theScale)
   set thisOutputImage to baseImage's imageByApplyingTransform:thisTransform
   set tiffData to thisOutputImage's TIFFRepresentation()
   tiffData's writeToFile:posixPath atomically:true
end makeQRForString:ofWidth:savingTo:


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/

Offline

 

#3 2017-11-09 07:29:25 pm

ProGrammer
Member
Registered: 2016-12-16
Posts: 16

Re: Generate QR code (offline)

I have just found out that the CGAffineTransformMakeScale does indeed throw an error, so I found a rather basic method of scaling (which I call at the bottom of the makeQRForString function) that resizes but greatly blurs the output - that is where CGAffineTransformMakeScale would come in handy due to it's scaling operation before saving, not after.

Applescript:

on scaleImage(myPath)
   tell application "Image Events"
       set thisImage to open myPath
       scale thisImage to size 300
       save thisImage in myPath
       close thisImage
   end tell
end scaleImage

You can use an alternative method of scaling instead.

Could you give an example of an alternative method?

Whenever I try to set the NSImageView on the interface builder (imgView) using the following syntax, the error message NSImageCell's object value must be an NSImage. (error -10000) is thrown. Note: I am pulling from the tiffData variable, not the path to the saved QR code as I have omitted the saving part for now.

Applescript:

imgView's setImage_(tiffData)

Offline

 

#4 2017-11-09 10:45:47 pm

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 5179

Re: Generate QR code (offline)

ProGrammer wrote:

Could you give an example of an alternative method?



This version uses bitmap image reps to do the job. Doing it this way also results in a greyscale file, rather than RGB:

Applescript:

use framework "Foundation"
use framework "AppKit"
use framework "CoreImage"
use scripting additions

set destPath to (POSIX path of (path to desktop folder)) & "Test QR Code.jpg"

my makeQRForString:"https://www.macosxautomation.com/applescript/apps/" ofWidth:360 savingTo:destPath

on makeQRForString:theString ofWidth:theWidth savingTo:posixPath
   set anImageFilter to current application's CIFilter's filterWithName:"CIQRCodeGenerator"
   anImageFilter's setDefaults()
   set thisURLString to current application's NSString's stringWithString:theString
   set thisData to thisURLString's dataUsingEncoding:(current application's NSUTF8StringEncoding)
   anImageFilter's setValue:thisData forKey:"inputMessage"
   anImageFilter's setValue:"L" forKey:"inputCorrectionLevel"
   set baseImage to anImageFilter's outputImage()
   
   -- make image rep
   set imageRep to current application's NSBitmapImageRep's alloc()'s initWithCIImage:baseImage
   set actualWidth to imageRep's |size|()'s width()
   set actualHeight to imageRep's |size|()'s height()
   set theScale to theWidth / actualWidth
   
   -- make greyscale image rep
   set newRep to current application's NSBitmapImageRep's alloc()'s initWithBitmapDataPlanes:(missing value) pixelsWide:theWidth pixelsHigh:actualHeight * theScale bitsPerSample:8 samplesPerPixel:1 hasAlpha:false isPlanar:false colorSpaceName:(current application's NSCalibratedWhiteColorSpace) bytesPerRow:0 bitsPerPixel:0
   
   -- store graphics state and set new values
   current application's NSGraphicsContext's saveGraphicsState()
   set theContext to current application's NSGraphicsContext's graphicsContextWithBitmapImageRep:newRep
   current application's NSGraphicsContext's setCurrentContext:theContext
   theContext's setShouldAntialias:false
   theContext's setImageInterpolation:(current application's NSImageInterpolationNone)
   
   -- draw from original to new rep
   imageRep's drawInRect:(current application's NSMakeRect(0, 0, theWidth, actualHeight * theScale)) fromRect:(current application's NSZeroRect) operation:(current application's NSCompositeCopy) fraction:(1.0) respectFlipped:false hints:(missing value)
   
   -- restore state and save from new rep
   current application's NSGraphicsContext's restoreGraphicsState()
   set theProps to current application's NSDictionary's dictionaryWithObject:1.0 forKey:(current application's NSImageCompressionFactor)
   set imageData to (newRep's representationUsingType:(current application's NSTIFFFileType) |properties|:theProps)
   (imageData's writeToFile:posixPath atomically:true)
end makeQRForString:ofWidth:savingTo:


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/

Offline

 

#5 2017-11-10 02:26:16 am

ProGrammer
Member
Registered: 2016-12-16
Posts: 16

Re: Generate QR code (offline)

This version uses bitmap image reps to do the job. Doing it this way also results in a greyscale file, rather than RGB

You are so right! This is the way to go as the result is sharp and of very high quality.
The final part is drawing this image to into the image view instead of saving it to the file, I have just tried:

Applescript:

imgView's setImage:(imageData)

Which returns: NSImageCell's object value must be an NSImage. (error -10000) but isn't it already an NSImage? Is there a special way of translating / drawing this data into the NSImageView instead of the file? Cheers.

Offline

 

#6 2017-11-10 02:32:39 am

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 5179

Re: Generate QR code (offline)

You'll need to do something like:

Applescript:

set theImage to current application's NSImage's alloc()'s initWithData:imageData
imgView's setImage:theImage


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)