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

QR code example: add a feature to make the result transparent #629

Merged
merged 5 commits into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from 4 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
23 changes: 6 additions & 17 deletions rust/qrcode/Makefile
Original file line number Diff line number Diff line change
@@ -1,37 +1,26 @@
.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
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