kindle7插件开发笔记[2]-使用Rust重写插件
前言
上一篇笔记:kindle7插件开发笔记[1]-在折腾中入门
代码地址:https://gitee.com/qsbye/kindle-plugin-touch
摘要
用Rust语言重写在Kindle上显示图片的插件,初步实现了图片完整显示及自动刷新屏幕的功能.
说明
Kindle7的屏幕信息
eips -i
结果:
Fixed framebuffer info
id: mxc_epdc_fb smem_start: 0x80C00000
smem_len: 3268608 type: PACKED_PIXELS
type_aux: 0 visual: STATIC_PSEUDOCOLOR
xpanstep: 1 ypanstep: 1
ywrapstep: 0 line_length: 608
mmio_start: 0x00000000 mmio_len: 0
accel: 0
Variable framebuffer info
xres: 600 yres: 800
xres_virtual: 608 yres_virtual: 5376
xoffset: 0 yoffset: 0
bits_per_pixel: 8 grayscale: 1
red.offset: 0 green.offset: 0
red.length: 8 green.length: 8
red.msb_right: 0 green.msb_right: 0
blue.offset: 0 transp.offset: 0
blue.length: 8 transp.length: 0
blue.msb_right: 0 transp.msb_right: 0
nonstd: 0 activate: 128
width: 91 height: 122
accel_flags: 0 pixclock: 27027027
left_margin: 8 right_margin: 100
upper_margin: 4 lower_margin: 8
hsync_len: 4 vsync_len: 1
sync: 0 vmode: 0
rotate: 3
DPI: 167.472527 166.557377 167
waveform type = 2
material type = 0
temperature = 28 (C)
Musl C库
几种C库比较(musl uClibc dietlibc glibc)
[https://www.bytenote.net/article/163117942798548993]
musl libc和glibc是两个不同的C标准库,用于提供C语言程序运行所需的基础功能。它们在实现上存在一些重要的差异:
实现方式:musl libc是一个简单,轻量级的C标准库,它的设计目标是实现纯粹的C标准,没有任何额外的功能。相反,glibc是一个功能非常强大的标准库,提供了大量的扩展功能,以及与操作系统内核进行交互的特殊接口。
兼容性:由于glibc提供了大量的额外功能,因此它与各种操作系统,硬件平台以及第三方库之间的兼容性更好。然而,这也使得glibc的代码实现更加复杂,可维护性更加困难。
性能:由于musl libc的设计目标是简单和轻量级,因此它的运行速度通常比glibc更快。同时,由于musl libc代码实现更简单,它的内存使用量也通常更少。
png图片的颜色空间
RGB和Grey是两种不同的色彩空间。RGB是一种彩色空间,由红色、绿色和蓝色三个基本颜色组成,可以产生各种颜色。而Grey是一种灰度空间,只有黑白两种颜色,没有彩色。
在Kindle等电子墨水屏幕上,只有Grey空间的图片能够按照原来的比例正确显示。这是因为电子墨水屏幕只能显示黑白两种颜色,无法显示彩色。因此,如果一个彩色图片在电子墨水屏幕上显示,必须将其转换为灰度图像。在这种情况下,只有Grey空间的图片能够按照原来的比例正确显示,因为它们只有一个颜色通道,而RGB空间的图片有三个颜色通道,转换为灰度图像时需要进行颜色通道的合并和平均,会导致比例失真。
Bing每日一图
[https://cn.bing.com]
[https://tool.liumingye.cn/bingimg/]
PHP 获取每日BING图 并且缓存URL链接到本地JSON
bing官网每天都会更新一张精美图片,用作图片源很合适.
请求地址: [http://tool.liumingye.cn/bingimg/img.php]
请求地址(HTTPS): [https://tool.liumingye.cn/bingimg/img.php]
请求方法: GET
<img src="http://tool.liumingye.cn/bingimg/img.php" />
<div style="background-image: url(http://tool.liumingye.cn/bingimg/img.php);"></div>
实现
目录结构:
hello_weather_three
├── Cargo.lock
├── Cargo.toml
├── server
│ ├── DailyImg1.php
│ ├── SmileySans-Oblique.ttf
│ └── board.json
├── src
│ └── main.rs
├── target
│ ├── CACHEDIR.TAG
│ ├── armv7-unknown-linux-musleabihf
│ │ ├── CACHEDIR.TAG
│ │ └── release
│ │ ├── examples
│ │ ├── hello_weather_three
│ │ ├── hello_weather_three.d
│ │
└── touch
├── 1.txt
├── 2.txt
├── config.xml
├── error.png
├── hello
├── hello_weather_three
├── img1.png
├── img1_old.png
├── kterm
│ ├── bin
│ │ ├── kterm
│ │ ├── kterm.conf
│ │ └── kterm.sh
│ ├── config.xml
│ │ ├── keyboard-200dpi.xml
│ │ ├── keyboard-300dpi.xml
│ │ └── keyboard.xml
│ ├── menu.json
│ └── vte
│ ├── termcap-0.0
│ │ └── xterm
│ └── terminfo
├── menu.json
├── nohup.out
└── touch.sh
Rust
主要作用:从网络下载图片,将图片转为Grey颜色空间的png图片并调用eips
命令显示,定时执行前述任务.
main.rs
use std::process::Command;
use image::{GenericImageView, ImageFormat, GrayImage, RgbImage};
use std::fs::{File, OpenOptions, copy};
use std::io::Write;
use chrono::prelude::*;
use std::thread::sleep;
use std::time::Duration;
fn main() {
// Create or open the runtime.log file
let mut file = OpenOptions::new()
.create(true)
.append(true)
.open("/mnt/us/runtime.log")
.unwrap();
loop {
// Download the image from the URL using wget command
let url = "https://www.qsbye.cn/infoimg/daily.png";
let output = Command::new("wget")
.arg("-O")
.arg("/mnt/us/extensions/touch/img1_old.png")
.arg(url)
.output();
match output {
Ok(output) => {
let output_str = String::from_utf8_lossy(&output.stdout);
println!("{}", output_str);
writeln!(file, "{} Download image from URL: {}", Local::now(), url).unwrap();
writeln!(file, "{} {}", Local::now(), output_str).unwrap();
},
Err(e) => {
println!("Error: {:?}", e);
copy("/mnt/us/extensions/touch/error.png", "/mnt/us/extensions/touch/img1.png").unwrap();
writeln!(file, "{} Error: {:?}", Local::now(), e).unwrap();
continue;
}
}
// Convert the image to bitmap format and save as png color space
let img = image::open("/mnt/us/extensions/touch/img1_old.png").unwrap().into_luma8();
let png = img.save_with_format("/mnt/us/extensions/touch/img1.png", ImageFormat::Png);
match png {
Ok(_) => {
writeln!(file, "{} Convert the image to png format", Local::now()).unwrap();
},
Err(e) => {
println!("Error: {:?}", e);
copy("/mnt/us/extensions/touch/error.png", "/mnt/us/extensions/touch/img1.png").unwrap();
writeln!(file, "{} Error: {:?}", Local::now(), e).unwrap();
continue;
}
}
// Display the bitmap on the Kindle device
let output = Command::new("eips")
.arg("-f")
.arg("-g")
.arg("/mnt/us/extensions/touch/img1.png")
.output();
match output {
Ok(output) => {
let output_str = String::from_utf8_lossy(&output.stdout);
println!("{}", output_str);
writeln!(file, "{} Display the bitmap on the Kindle device", Local::now()).unwrap();
writeln!(file, "{} {}", Local::now(), output_str).unwrap();
},
Err(e) => {
println!("Error: {:?}", e);
copy("/mnt/us/extensions/touch/error.png", "/mnt/us/extensions/touch/img1.png").unwrap();
writeln!(file, "{} Error: {:?}", Local::now(), e).unwrap();
continue;
}
}
// Wait for 5 mins before running again
sleep(Duration::from_secs(300));
}
}
Cargo.toml
[package]
name = "hello_weather_three"
version = "0.1.0"
edition = "2021"
[dependencies]
chrono = "0.4.24"
image = "0.24.6"
libc = "0.2.144"
reqwest = "0.11.18"
.cargo/config
[target.arm-unknown-linux-musleabihf]
linker = "arm-linux-musleabihf-ld"
[target.armv7-unknown-linux-musleabihf]
linker = "arm-linux-musleabihf-ld"
[target.arm-unknown-linux-gnueabihf]
linker = "arm-linux-gnueabihf-gcc"
[target.armv7-unknown-linux-gnueabihf]
linker = "arm-linux-gnueabihf-gcc"
编译:
#添加依赖库
cargo add chrono
cargo add image
#配置编译环境
brew install FiloSottile/musl-cross/musl-cross --without-x86_64 --with-arm-hf
rustup target add armv7-unknown-linux-musleabihf # armv7,mac
#编译
cargo build --target armv7-unknown-linux-musleabihf --release # armv7, mac
Shell脚本
touch.sh
#!/bin/sh
# 变量
export COUNT=1
export PATH=$PATH:/mnt/us/extensions/touch
# 清除txt临时文件
rm /mnt/us/extensions/touch/*.txt
#log
touch /mnt/us/extensions/touch/$COUNT.txt && COUNT=$((COUNT+1))
# 超级权限
su
# 检查/mnt/us/extensions是否有kterm目录,否则复制/mnt/us/extensions/touch/kterm目录过去
if [ ! -d "/mnt/us/extensions/kterm" ]; then cp -r /mnt/us/extensions/touch/kterm /mnt/us/extensions/; fi
#禁止休眠
lipc-set-prop -i com.lab126.powerd preventScreenSaver 1
#log
touch /mnt/us/extensions/touch/$COUNT.txt && COUNT=$((COUNT+1))
# 复制并重命名
cp /mnt/us/extensions/touch/hello_weather_three /mnt/us/extensions/touch/hello
# 添加可执行权限
chmod 666 hello
#开启wifi
lipc-set-prop com.lab126.cmd wirelessEnable 1
#显示图片
eips -c
/mnt/us/extensions/kterm/bin/kterm -e "/bin/bash -c 'hello'"
#程序加了死循环,下面应该都不会运行了
#log
touch /mnt/us/extensions/touch/$COUNT.txt && COUNT=$((COUNT+1))
#延时5s
sleep 5
#延时1小时
sleep 1h
#循环获取图片
nohup /mnt/us/extensions/touch/touch.sh &
#log
touch /mnt/us/extensions/touch/$COUNT.txt && COUNT=$((COUNT+1))
Php脚本
DailyImg1.php
<?php
//php7.4
// 更新图片函数
function updateImage() {
// HTML代码字符串
$html = '<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=600,height=800,initial-scale=1,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
<link rel="stylesheet" type="text/css" href="https://npm.elemecdn.com/amazeui@2.7.2/dist/css/amazeui.flat.min.css">
<meta http-equiv="Cache-Control" content="no-siteapp">
<!--[if IE]><script>window.location.href="http://tool.liumingye.cn/support/?referrer=" encodeURIComponent(location.href);</script><![endif]-->
<title>每日Bing图</title>
<meta name="keywords" content="每日Bing图,Bing图,Bing每日背景,必应图片">
<meta name="description" content="获取Bing每日背景图片接口,用于获取并返回必应今日美图">
<style>
@font-face {
font-family: "SmileySans-Oblique";
src: url("SmileySans-Oblique.ttf") format("truetype");
}
html, body {
height: 100%;
margin: 0;
}
.div_top {
position: absolute;
top: 0;
left: 0;
right: 0;
margin-top: 20px;
width: 100%;
text-align: center;
overflow: hidden;
box-shadow: 0px 3px 20px -3px rgba(0, 0, 0, 0.4);
font-family: "SmileySans-Oblique", sans-serif;
}
.div_bottom img {
width: 80%;
border-radius: 6px;
}
.div_bottom {
position: absolute;
bottom: 0;
left: 0;
right: 0;
margin-bottom: 47px;
width: 100%;
text-align: center;
font-size: 50px;
font-family: "SmileySans-Oblique", sans-serif;
}
.div_middle {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
height: 55%;
font-family: "SmileySans-Oblique", sans-serif;
}
</style>
</head>
<body>';
// 获取Bing每日背景图片
$bingImage = file_get_contents('https://api.dujin.org/bing/1920.php');
// 创建画布
$width = 600;
$height = 800;
$image = imagecreatetruecolor($width, $height);
// 创建颜色
$white = imagecolorallocate($image, 255, 255, 255);
$black = imagecolorallocate($image, 0, 0, 0);
$gray = imagecolorallocate($image, 128, 128, 128);
// 填充背景
imagefill($image, 0, 0, $white);
// 添加顶部信息
$text = "♪(^∇^*) 一言加载中...";
$font = 'SmileySans-Oblique.ttf';
$fontSize = 20;
$textWidth = imagettfbbox($fontSize, 0, $font, $text)[2] - imagettfbbox($fontSize, 0, $font, $text)[0];
$textX = ($width - $textWidth) / 2;
$textY = 50;
imagettftext($image, $fontSize, 0, $textX, $textY, $black, $font, $text);
// 添加日期
$date = date('Y年m月d日');
$fontSize = 16;
$textWidth = imagettfbbox($fontSize, 0, $font, $date)[2] - imagettfbbox($fontSize, 0, $font, $date)[0];
$textX = ($width - $textWidth) / 2;
$textY = 80;
imagettftext($image, $fontSize, 0, $textX, $textY, $gray, $font, $date);
// 添加一言
$hitokoto = json_decode(file_get_contents('https://v1.hitokoto.cn'), true)['hitokoto'];
$fontSize = 20;
$textWidth = imagettfbbox($fontSize, 0, $font, $hitokoto)[2] - imagettfbbox($fontSize, 0, $font, $hitokoto)[0];
$textX = ($width - $textWidth) / 2;
$textY = 120;
imagettftext($image, $fontSize, 0, $textX, $textY, $black, $font, $hitokoto);
// 添加中间留空信息区
$text = "";
$fontSize = 20;
$textWidth = imagettfbbox($fontSize, 0, $font, $text)[2] - imagettfbbox($fontSize, 0, $font, $text)[0];
$textHeight = imagettfbbox($fontSize, 0, $font, $text)[3] - imagettfbbox($fontSize, 0, $font, $text)[1];
$textX = ($width - $textWidth) / 2;
$textY = ($height - $textHeight) / 2;
imagettftext($image, $fontSize, 0, $textX, $textY, $black, $font, $text);
// 添加底部Bing每日背景图片
$bingImage = imagecreatefromstring($bingImage);
$bingImageWidth = imagesx($bingImage);
$bingImageHeight = imagesy($bingImage);
$bingImageX = ($width - $bingImageWidth) / 2;
$bingImageY = $height - $bingImageHeight - 100;
imagecopyresampled($image, $bingImage, $bingImageX, $bingImageY, 0, 0, $bingImageWidth, $bingImageHeight, $bingImageWidth, $bingImageHeight);
// 添加底部信息
$text = "每日Bing图";
$fontSize = 50;
$textWidth = imagettfbbox($fontSize, 0, $font, $text)[2] - imagettfbbox($fontSize, 0, $font, $text)[0];
$textX = ($width - $textWidth) / 2;
$textY = $height - 50;
imagettftext($image, $fontSize, 0, $textX, $textY, $black, $font, $text);
// 将图像颜色空间转换为灰度
imagefilter($image, IMG_FILTER_GRAYSCALE);
// 保存图像为PNG文件
imagepng($image, 'daily.png');
// 释放内存
imagedestroy($image);
}
// 更新一次图像
updateImage();
// 显示图片
echo "<html><body><img src='./daily.png' alt='生成的图片'></body></html>";
// 设置定时器,每15分钟更新一次图像
set_time_limit(0);
while (true) {
sleep(15 * 60);
updateImage();
}
?>
说明:使用的SmileySans-Oblique字体是开源字体,地址为:[https://github.com/atelier-anchor/smiley-sans]
安装
复制touch
目录至Kindle盘的extensions
目录(实际地址/mnt/us/extensions
),然后在插件菜单中点击touch
按钮.