local g = playdate.graphics local geom = playdate.geometry -- XXX: the compiler only knows to link the imported file in if the import statement is at the start of the line local qrencode = import("CoreLibs/3rdparty/qrencode_panic_mod.lua") -- was tempted to make this sync function local… but maybe somebody out there needs it for something. still, it's not mentioned in the docs. function playdate.graphics.generateQRCodeSync( stringToEncode, desiredEdgeDimension ) -- calculate QR code local ok, qrCodeData = qrencode.qrcode( stringToEncode ) -- error handling if not ok then local errorMessage = qrCodeData print( errorMessage ) return end return generateQRCodeImage( qrCodeData, desiredEdgeDimension ) end local function generateQRCodeImage( qrCodeData, desiredEdgeDimension ) local MIN_BLOCK_SIZE = 2 local OPTIMAL_WIDTH = 100 local PADDING_WIDTH = 1 local desiredEdgeDimension = desiredEdgeDimension or OPTIMAL_WIDTH local qrCodeDataWidth = #qrCodeData + PADDING_WIDTH * 2 local blockSize = desiredEdgeDimension // qrCodeDataWidth if blockSize < MIN_BLOCK_SIZE then blockSize = MIN_BLOCK_SIZE end -- create image to hold qrcode local qrCodeImage = g.image.new( qrCodeDataWidth * blockSize, qrCodeDataWidth * blockSize ) g.pushContext( qrCodeImage ) -- draw the padding g.setColor(g.kColorWhite) g.fillRect( 0, 0, qrCodeImage.width, qrCodeImage.height ) -- draw the data g.setColor(g.kColorBlack) for x = 1, #qrCodeData do for y = 1, #qrCodeData[ x ] do local value = qrCodeData[ x ][ y ] local q_x = x - 1 + PADDING_WIDTH local q_y = y - 1 + PADDING_WIDTH if value > 0 then g.fillRect( q_x * blockSize, q_y * blockSize, blockSize, blockSize ) end end end g.popContext() return qrCodeImage end local qrCodeTimer = nil function playdate.graphics.generateQRCode( stringToEncode, desiredEdgeDimension, callback ) assert( callback, "Need to pass a callback as the third argument to generateQRCode()" ) local wrapped = coroutine.wrap( function() return qrencode.qrcode( stringToEncode ) end ) local MS_PER_FRAME = 1000 // playdate.display.getRefreshRate() qrCodeTimer = playdate.timer.new( MS_PER_FRAME, function( thisTimer ) local wrappedDone, qrCodeData = wrapped() if wrappedDone == true then -- stop the timer thisTimer:remove() -- generate and return image local qrCodeImage = generateQRCodeImage( qrCodeData, desiredEdgeDimension ) callback( qrCodeImage ) elseif wrappedDone == false then -- stop the timer thisTimer:remove() -- error callback( nil, qrCodeData ) -- this is the error message end end ) qrCodeTimer.repeats = true qrCodeTimer.timerEndedArgs = { qrCodeTimer } return qrCodeTimer end