Skip to content

Commit

Permalink
Merge pull request #629 from dfinity/ulan/qrcode-transparent
Browse files Browse the repository at this point in the history
QR code example: add a feature to make the result transparent
  • Loading branch information
ulan authored Dec 8, 2023
2 parents eb1507c + fed5cbc commit c62de1a
Show file tree
Hide file tree
Showing 10 changed files with 45 additions and 20 deletions.
25 changes: 8 additions & 17 deletions rust/qrcode/Makefile
Original file line number Diff line number Diff line change
@@ -1,37 +1,28 @@
.PHONY: all
all: build
all: deploy

.PHONY: node_modules
.SILENT: node_modules
node_modules:
npm install

.PHONY: build
.SILENT: build
build: node_modules
dfx canister create --all
dfx build

.PHONY: install
.SILENT: install
install: build
dfx canister install --all

.PHONY: upgrade
.SILENT: upgrade
upgrade: build
dfx canister install --all --mode=upgrade
.PHONY: deploy
.SILENT: deploy
deploy: node_modules
dfx deploy

.PHONY: test
.SILENT: test
test: install
test: deploy
# Wait at least 2 seconds.
sleep 2
# Validate the image is generated as a query.
dfx canister call qrcode_backend qrcode_query '("test", record {add_gradient=false; add_logo=false})' | fgrep -q 'Image = blob' && echo PASS
dfx canister call qrcode_backend qrcode_query '("test", record {add_gradient=false; add_logo=true})' | fgrep -q 'Image = blob' && echo PASS
dfx canister call qrcode_backend qrcode_query '("test", record {add_gradient=true; add_logo=false})' | fgrep -q 'Image = blob' && echo PASS
dfx canister call qrcode_backend qrcode_query '("test", record {add_gradient=true; add_logo=true})' | fgrep -q 'Image = blob' && echo PASS
dfx canister call qrcode_backend qrcode_query '("test", record {add_gradient=true; add_logo=true; add_trasparency=opt true})' | fgrep -q 'Image = blob' && echo PASS
dfx canister call qrcode_backend qrcode_query '("test", record {add_gradient=true; add_logo=true; add_trasparency=opt false})' | fgrep -q 'Image = blob' && echo PASS
# Validate the image is generated as an update call.
dfx canister call qrcode_backend qrcode '("test", record {add_gradient=true; add_logo=true})' | fgrep -q 'Image = blob' && echo PASS

Expand Down
1 change: 1 addition & 0 deletions rust/qrcode/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ This example requires an installation of:
- [x] Make sure your rust version is up-to-date (e.g., run `rustup update`).
- [x] Add the `wasm32` target to your rust installation (by running `rustup target add wasm32-unknown-unknown`).
- [x] Clone this project to a local directory.
- [x] Install `node.js` dependencies by running `npm install`.

## Running locally

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions rust/qrcode/src/qrcode_backend/qrcode_backend.did
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
type Options = record {
add_logo: bool;
add_gradient: bool;
add_transparency: opt bool;
};

type QrError = record {
Expand Down
16 changes: 15 additions & 1 deletion rust/qrcode/src/qrcode_backend/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ pub(super) fn generate(
)?)
.into_rgba8();

if options.add_transparency == Some(true) {
make_transparent(&mut qr);
}

if options.add_logo {
add_logo(&mut qr, logo);
}
Expand All @@ -33,6 +37,16 @@ pub(super) fn generate(
Ok(result)
}

/// Replaces white pixels in the image with transparent pixels.
fn make_transparent(qr: &mut ImageBuffer<Rgba<u8>, Vec<u8>>) {
for (_x, _y, pixel) in qr.enumerate_pixels_mut() {
if pixel.0 == [255, 255, 255, 255] {
*pixel = image::Rgba([255, 255, 255, 0]);
}
}
}


/// Adds the given logo at the center of QR code image.
/// It ensures that the logo does not cover more than 10% of the image, which is
/// below the QR error threshold.
Expand Down Expand Up @@ -89,7 +103,7 @@ fn add_gradient(qr: &mut ImageBuffer<Rgba<u8>, Vec<u8>>) {
// The gradient goes from the center of the image to its sides.
let center = (image_size / 2) as u32;
for (x, y, pixel) in qr.enumerate_pixels_mut() {
if pixel.0[0] == 0 {
if pixel.0 == [0, 0, 0, 255] {
// Use a simple Manhattan distance as an estimate of how far the
// pixel is from the center of the image.
let distance = x.abs_diff(center) + y.abs_diff(center);
Expand Down
11 changes: 9 additions & 2 deletions rust/qrcode/src/qrcode_backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ use std::include_bytes;
mod core;

const IMAGE_SIZE_IN_PIXELS: usize = 1024;
const LOGO: &[u8] = include_bytes!("../assets/logo.png");
const LOGO_TRANSPARENT: &[u8] = include_bytes!("../assets/logo_transparent.png");
const LOGO_WHITE: &[u8] = include_bytes!("../assets/logo_white.png");

#[derive(CandidType, Deserialize)]
struct Options {
add_logo: bool,
add_gradient: bool,
add_transparency: Option<bool>,
}

#[derive(CandidType, Deserialize)]
Expand All @@ -24,7 +26,12 @@ enum QrResult {
}

fn qrcode_impl(input: String, options: Options) -> QrResult {
let result = match core::generate(input, options, LOGO, IMAGE_SIZE_IN_PIXELS) {
let logo = if options.add_transparency == Some(true) {
LOGO_TRANSPARENT
} else {
LOGO_WHITE
};
let result = match core::generate(input, options, logo, IMAGE_SIZE_IN_PIXELS) {
Ok(blob) => QrResult::Image(blob),
Err(err) => QrResult::Err(QrError {
message: err.to_string(),
Expand Down
1 change: 1 addition & 0 deletions rust/qrcode/src/qrcode_frontend/assets/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ div {
img {
max-width: 80vw;
border: 1px solid #555;
background-color: #ddd;
}

.qrcode {
Expand Down
9 changes: 9 additions & 0 deletions rust/qrcode/src/qrcode_frontend/src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ <h1>QR code generator</h1>
&nbsp; add gradient
</label>
</div>
<div class="option">
<label>
<div class="toggle-switch">
<input type="checkbox" id="transparent">
<span class="slider"></span>
</div>
&nbsp; make transparent
</label>
</div>
<div class="option">
<label>
<div class="toggle-switch">
Expand Down
1 change: 1 addition & 0 deletions rust/qrcode/src/qrcode_frontend/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ async function onGenerateButtonClick(event) {
const options = {
add_logo: document.getElementById("logo").checked,
add_gradient: document.getElementById("gradient").checked,
add_transparency: [document.getElementById("transparent").checked],
}

// Call the backend and wait for the result.
Expand Down

0 comments on commit c62de1a

Please sign in to comment.