Browse Source

Rotate RGB565 image rather than convert

pull/94/head
Andrea Ciliberti 2 years ago
parent
commit
4ecb1e4077
  1. 66
      ctru-rs/examples/camera-image.rs

66
ctru-rs/examples/camera-image.rs

@ -1,16 +1,15 @@ @@ -1,16 +1,15 @@
use ctru::console::Console;
use ctru::gfx::{Gfx, Screen};
use ctru::gfx::Screen;
use ctru::prelude::*;
use ctru::services::cam::{Cam, CamOutputFormat, CamShutterSoundType, CamSize, Camera};
use ctru::services::hid::KeyPad;
use ctru::services::{Apt, Hid};
use ctru::services::gspgpu::FramebufferFormat;
use std::time::Duration;
const WIDTH: usize = 400;
const HEIGHT: usize = 240;
// The screen size is the width and height multiplied by 2 and
// then multiplied by 2 again for 3D images
const BUF_SIZE: usize = WIDTH * HEIGHT * 2 * 2;
// The screen size is the width and height multiplied by 2 (RGB565 store pixels in 2 bytes)
const BUF_SIZE: usize = WIDTH * HEIGHT * 2;
const WAIT_TIMEOUT: Duration = Duration::from_micros(300);
@ -22,8 +21,10 @@ fn main() { @@ -22,8 +21,10 @@ fn main() {
let gfx = Gfx::init().expect("Failed to initialize GFX service.");
gfx.top_screen.borrow_mut().set_double_buffering(true);
gfx.top_screen
.borrow_mut()
.set_framebuffer_format(FramebufferFormat::Rgb565);
gfx.bottom_screen.borrow_mut().set_double_buffering(false);
let _console = Console::init(gfx.bottom_screen.borrow_mut());
let mut keys_down;
@ -54,7 +55,9 @@ fn main() { @@ -54,7 +55,9 @@ fn main() {
.set_trimming(false)
.expect("Failed to disable trimming");
}
let mut buf = vec![0u8; BUF_SIZE];
let mut buf = vec![128u8; BUF_SIZE / 2];
let mut lol = vec![255u8; BUF_SIZE / 2];
buf.append(&mut lol);
println!("\nPress R to take a new picture");
println!("Press Start to exit to Homebrew Launcher");
@ -83,7 +86,7 @@ fn main() { @@ -83,7 +86,7 @@ fn main() {
.expect("Failed to take picture");
}
let img = convert_image_to_rgb8(&buf, 0, 0, WIDTH, HEIGHT);
let img = rotate_image(&buf, WIDTH, HEIGHT);
unsafe {
gfx.top_screen
@ -99,39 +102,28 @@ fn main() { @@ -99,39 +102,28 @@ fn main() {
}
}
// The available camera output formats are both using u16 values.
// To write to the frame buffer with the default RGB8 format,
// the values must be converted.
//
// Alternatively, the frame buffer format could be set to RGB565 as well
// but the image would need to be rotated 90 degrees.
fn convert_image_to_rgb8(img: &[u8], x: usize, y: usize, width: usize, height: usize) -> Vec<u8> {
let mut rgb8 = vec![0u8; img.len()];
// The 3DS' screens are 2 vertical LCD panels rotated by 90 degrees.
// As such, we'll need to write a "vertical" image to the framebuffer to have it displayed properly.
// This functions handles the rotation of an horizontal image to a vertical one.
fn rotate_image(img: &[u8], width: usize, height: usize) -> Vec<u8> {
let mut res = vec![0u8; img.len()];
for j in 0..height {
for i in 0..width {
// Y-coordinate of where to draw in the frame buffer
let draw_y = y + height - j;
// Height must be esclusive of the upper end (otherwise, we'd be writing to the pixel one column to the right when having j=0)
let draw_y = (height - 1) - j;
// X-coordinate of where to draw in the frame buffer
let draw_x = x + i;
// Initial index of where to draw in the frame buffer based on y and x coordinates
let draw_index = (draw_y + draw_x * height) * 3;
let draw_x = i;
// Index of the pixel to draw within the image buffer
let index = (j * width + i) * 2;
// Pixels in the image are 2 bytes because of the RGB565 format.
let pixel = u16::from_ne_bytes(img[index..index + 2].try_into().unwrap());
// b value from the pixel
let b = (((pixel >> 11) & 0x1F) << 3) as u8;
// g value from the pixel
let g = (((pixel >> 5) & 0x3F) << 2) as u8;
// r value from the pixel
let r = ((pixel & 0x1F) << 3) as u8;
// set the r, g, and b values to the calculated index within the frame buffer
rgb8[draw_index] = r;
rgb8[draw_index + 1] = g;
rgb8[draw_index + 2] = b;
let read_index = (j * width + i) * 2;
// Initial index of where to draw in the frame buffer based on y and x coordinates
let draw_index = (draw_x * height + draw_y) * 2; // This 2 stands for the number of bytes per pixel (16 bits)
res[draw_index] = img[read_index];
res[draw_index + 1] = img[read_index + 1];
}
}
rgb8
res
}

Loading…
Cancel
Save