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

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按钮.

效果

posted @ 2023-05-22 16:05  qsBye  阅读(163)  评论(0编辑  收藏  举报