Merge pull request #1 from Namophice/dev

Dev
This commit is contained in:
南陌怀尘
2021-08-07 12:56:18 +08:00
committed by GitHub
24 changed files with 1208 additions and 64 deletions

5
.gitignore vendored
View File

@@ -12,3 +12,8 @@ gradle-app.setting
# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
# gradle/wrapper/gradle-wrapper.properties
.idea/
cache
error.log
gradle/

View File

@@ -1,36 +0,0 @@
# ink-photo-album
#### Description
用Java编写的基于树莓派的电子墨水屏相册
#### Software Architecture
Software architecture description
#### Installation
1. xxxx
2. xxxx
3. xxxx
#### Instructions
1. xxxx
2. xxxx
3. xxxx
#### Contribution
1. Fork the repository
2. Create Feat_xxx branch
3. Commit your code
4. Create Pull Request
#### Gitee Feature
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
4. The most valuable open source project [GVP](https://gitee.com/gvp)
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

View File

@@ -3,35 +3,17 @@
#### 介绍
用Java编写的基于树莓派的电子墨水屏相册
#### 软件架构
软件架构说明
#### 效果图
![效果图1](https://images.gitee.com/uploads/images/2021/0807/125215_b6d4fd2e_7404037.jpeg "微信图片_20210807125140.jpg")
![效果图2](https://images.gitee.com/uploads/images/2021/0807/125242_cfcada7d_7404037.jpeg "微信图片_20210807125134.jpg")
#### 安装教程
![效果图3](https://images.gitee.com/uploads/images/2021/0807/125303_bedcd72e_7404037.jpeg "微信图片_20210807125148.jpg")
1. xxxx
2. xxxx
3. xxxx
#### 相关链接
https://gitee.com/namophice/ink-photo-album
https://github.com/Namophice/ink-photo-album
https://zhuanlan.zhihu.com/p/397288660
#### 使用说明
1. xxxx
2. xxxx
3. xxxx
#### 参与贡献
1. Fork 本仓库
2. 新建 Feat_xxx 分支
3. 提交代码
4. 新建 Pull Request
#### 特技
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
#### PS
此仓库仅包含源码、图片等资源感兴趣者可拉取代码到本地编译运行如有疑问或建议可提issues或通过邮箱namophice@foxmail.com与QQ1763453138联系我有时间会在后续版本解决与优化或许

33
build.gradle Normal file
View File

@@ -0,0 +1,33 @@
plugins {
id 'java-library'
id 'com.github.johnrengelman.shadow' version '6.1.0'
}
group 'icu.namophice'
version '1.0-SNAPSHOT'
description = 'slow'
sourceCompatibility = JavaVersion.VERSION_11
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
implementation group: 'com.alibaba', name: 'fastjson', version: '1.2.76'
// RaspbarryPi驱动接口核心包
implementation group: 'com.pi4j', name: 'pi4j-core', version: '1.4'
}
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
jar {
manifest {
attributes(
'Main-Class': 'icu.namophice.inkphotoalbum.Main'
)
}
}

4
conf.json Normal file
View File

@@ -0,0 +1,4 @@
{
"enable_image_fill": true, // 是否开启图片填充
"local_images_mode": false // 本地图片库模式
}

BIN
images/self_1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

BIN
images/self_10.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 KiB

BIN
images/self_13.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

BIN
images/self_15.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 KiB

BIN
images/self_16.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

BIN
images/self_17.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1012 KiB

BIN
images/self_2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

BIN
images/self_22.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 KiB

BIN
images/self_6.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

2
settings.gradle Normal file
View File

@@ -0,0 +1,2 @@
rootProject.name = 'ink-photo-album'

View File

@@ -0,0 +1,39 @@
package icu.namophice.inkphotoalbum;
import icu.namophice.inkphotoalbum.business.MasterService;
import icu.namophice.inkphotoalbum.config.DefaultConfig;
import icu.namophice.inkphotoalbum.utils.CommonUtil;
/**
* @author Namophice
* @createTime 2021-07-29 16:42
*/
public class Main {
public static void main(String [] args) {
try {
CommonUtil.printLogToConsole("Application Started ...");
// 初始化配置
DefaultConfig.initConfig();
// 从cache文件获取imageIndex
DefaultConfig.initImageIndexWithCache();
// 进入主流程
MasterService.master();
} catch (Exception e) {
CommonUtil.printErrorToLogFile(e);
} finally {
try {
// 打印下次获取的图片下标位置到cache文件
CommonUtil.printImageIndexToCache(DefaultConfig.imageIndex);
} catch (Exception e) {
CommonUtil.printErrorToLogFile(e);
}
CommonUtil.printLogToConsole("Application Exit !");
}
}
}

View File

@@ -0,0 +1,154 @@
package icu.namophice.inkphotoalbum.business;
import icu.namophice.inkphotoalbum.config.DefaultConfig;
import icu.namophice.inkphotoalbum.driver.EPaper;
import icu.namophice.inkphotoalbum.utils.CommonUtil;
import icu.namophice.inkphotoalbum.utils.ImageUtil;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Namophice
* @createTime 2021-08-05 10:27
*/
public class MasterService {
public static void master() throws IOException, InterruptedException {
CommonUtil.printLogToConsole("The master program is running ...");
if (DefaultConfig.imageIndex < 0) {
DefaultConfig.imageIndex = 0;
}
EPaper ePaper = EPaper.getInstance();
ePaper.init();
if (DefaultConfig.imageIndex == 0) {
BufferedImage defaultImage = ImageUtil.getImageToScreen();
CommonUtil.printLogToConsole("Print images to screen ...");
ePaper.drawImage(defaultImage);
}
DefaultConfig.defaultImageIsLoaded = true;
if (DefaultConfig.local_images_mode()) { // local
CommonUtil.printLogToConsole("Enabled local images mode ...");
CommonUtil.printLogToConsole("Find images directory ...");
File imagesDir = new File(CommonUtil.rootPath + "/" + DefaultConfig.imagePath);
if (imagesDir.exists()) {
if (imagesDir.isDirectory()) {
CommonUtil.printLogToConsole("Images directory is exists ...");
CommonUtil.printLogToConsole("Find images files ...");
File[] imageList = imagesDir.listFiles();
imagesDir = null;
if (imageList == null || imageList.length < 1) {
DefaultConfig.imageIndex = 0;
return;
}
imageList = Arrays.stream(imageList).filter(imageFile -> !imageFile.isDirectory()).toArray(File[]::new);
if (imageList.length < 1) {
DefaultConfig.imageIndex = 0;
return;
}
if (DefaultConfig.imageIndex < imageList.length) {
BufferedImage targetImage = ImageUtil.getImageToScreen(imageList[DefaultConfig.imageIndex]);
CommonUtil.printLogToConsole("Print images to screen ...");
ePaper.drawImage(targetImage);
DefaultConfig.imageIndex++;
} else {
DefaultConfig.imageIndex = 0;
}
}
}
} else { // remote
CommonUtil.printLogToConsole("Enabled remote images mode ...");
if (!(DefaultConfig.imageIndex < 20)) {
DefaultConfig.imageIndex = 0;
}
StringBuffer htmlStr = new StringBuffer();
InputStream inputStream = null;
InputStreamReader inputStreamReader = null;
BufferedReader bufferedReader = null;
try {
URL url = new URL("https://wall.alphacoders.com/popular.php?page=" + (DefaultConfig.imageIndex + 1));
inputStream = url.openStream();
inputStreamReader = new InputStreamReader(inputStream, "utf-8");
bufferedReader = new BufferedReader(inputStreamReader);
String line;
while ((line = bufferedReader.readLine()) != null) {
htmlStr.append(line).append("\n");
}
bufferedReader.close();
} catch (IOException e) {
DefaultConfig.imageIndex = 0;
throw e;
}finally {
try {
if(bufferedReader!=null){
bufferedReader.close();
bufferedReader=null;
}
if(inputStreamReader!=null){
inputStreamReader.close();
inputStreamReader=null;
}
if(inputStream!=null){
inputStream.close();
inputStream=null;
}
} catch (IOException e) {
throw e;
}
}
if (htmlStr.length() > 0) {
final List<String> imageUrlList = new ArrayList<>();
final String IMGURL_REG = "(https://images(.*)thumbbig-(\\d*).jpg)";
Matcher matcher = Pattern.compile(IMGURL_REG).matcher(htmlStr);
while (matcher.find()){
imageUrlList.add(matcher.group());
}
if (imageUrlList.size() < 1) {
DefaultConfig.imageIndex = 0;
return;
}
String imageUrl = imageUrlList.get(new Random().nextInt(imageUrlList.size()));
imageUrl = imageUrl.replace("/thumbbig-", "/");
BufferedImage targetImage = ImageUtil.getImageToScreen(imageUrl, true);
CommonUtil.printLogToConsole("Print images to screen ...");
ePaper.drawImage(targetImage);
DefaultConfig.imageIndex++;
}
}
}
}

View File

@@ -0,0 +1,135 @@
package icu.namophice.inkphotoalbum.config;
import com.alibaba.fastjson.JSONObject;
import icu.namophice.inkphotoalbum.utils.CommonUtil;
import java.io.*;
/**
* @author Namophice
* @createTime 2021-08-04 11:46
*/
public class DefaultConfig {
public static final String configFileName = "conf.json";
public static final String cacheFileName = "cache";
public static final String imagePath = "images";
public static int imageIndex;
/**
* 默认图片是否被加载过
*/
public static boolean defaultImageIsLoaded = false;
/**
* 是否开启图片填充
*/
private static boolean enable_image_fill = false;
public static final boolean enable_image_fill() {
return enable_image_fill;
}
/**
* 本地图片库模式
*/
private static boolean local_images_mode = true;
public static boolean local_images_mode() {
return local_images_mode;
}
/**
* 初始化配置文件
*/
public static void initConfig() {
CommonUtil.printLogToConsole("Init config ...");
File configFile = new File(CommonUtil.rootPath + "/" + configFileName);
if (configFile.exists()) {
BufferedReader bufferedReader = null;
final StringBuilder confJsonStrBuilder = new StringBuilder();
try {
bufferedReader = new BufferedReader(new FileReader(configFile));
String lineStr;
while ((lineStr = bufferedReader.readLine()) != null) {
confJsonStrBuilder.append(lineStr).append("\n");
}
bufferedReader.close();
} catch (Exception e) {
CommonUtil.printErrorToLogFile(e);
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (Exception e) {
CommonUtil.printErrorToLogFile(e);
}
}
}
final String confJsonStr = confJsonStrBuilder.toString();
if (confJsonStr.length() > 2 && confJsonStr.contains("{") && confJsonStr.contains("}")) {
JSONObject conJsonMap = JSONObject.parseObject(confJsonStr);
if (conJsonMap.size() > 0) {
if (conJsonMap.get("enable_image_fill") != null) {
final Boolean cst_enable_image_fill = conJsonMap.getBoolean("enable_image_fill");
if (cst_enable_image_fill != null) {
enable_image_fill = cst_enable_image_fill;
}
}
if (conJsonMap.get("local_images_mode") != null) {
final Boolean cst_local_images_mode = conJsonMap.getBoolean("local_images_mode");
if (cst_local_images_mode != null) {
local_images_mode = cst_local_images_mode;
}
}
}
}
}
}
/**
* 从cache文件获取imageIndex
* @throws IOException
*/
public static void initImageIndexWithCache() throws IOException {
CommonUtil.printLogToConsole("Init image index with cache ...");
DefaultConfig.imageIndex = 0;
File cacheFile = new File(CommonUtil.rootPath + "/" + cacheFileName);
if (cacheFile.exists() && !cacheFile.isDirectory()) {
BufferedReader bufferedReader = null;
String lineStr = null;
try {
bufferedReader = new BufferedReader(new FileReader(cacheFile));
lineStr = bufferedReader.readLine().trim();
bufferedReader.close();
} catch (Exception e) {
CommonUtil.printErrorToLogFile(e);
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (Exception e) {
CommonUtil.printErrorToLogFile(e);
}
}
}
if (lineStr.length() > 0) {
DefaultConfig.imageIndex = Integer.parseInt(lineStr);
}
}
}
}

View File

@@ -0,0 +1,342 @@
package icu.namophice.inkphotoalbum.driver;
import com.pi4j.io.gpio.*;
import com.pi4j.io.spi.SpiChannel;
import com.pi4j.io.spi.SpiDevice;
import com.pi4j.io.spi.SpiFactory;
import icu.namophice.inkphotoalbum.utils.CommonUtil;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.IOException;
/**
* @author Namophice
* @createTime 2021-07-29 17:00
*/
public class EPaper {
public static final int width = 800;
public static final int height = 480;
public static final long resolution = width * height;
private EPaper() {}
private static EPaper ePaper;
public static EPaper getInstance() {
return ePaper = new EPaper();
}
private static GpioPinDigitalOutput CS;
private static GpioPinDigitalOutput DC;
private static GpioPinDigitalOutput RST;
private static GpioPinDigitalInput BUSY;
public static SpiDevice spiDevice;
static {
RaspiGpioProvider raspiGpioProvider = new RaspiGpioProvider(RaspiPinNumberingScheme.BROADCOM_PIN_NUMBERING);
final GpioController gpio = GpioFactory.getInstance();
CS = gpio.provisionDigitalOutputPin(raspiGpioProvider, RaspiBcmPin.GPIO_08, "CS", PinState.HIGH);
DC = gpio.provisionDigitalOutputPin(raspiGpioProvider, RaspiBcmPin.GPIO_25, "DC", PinState.HIGH);
RST = gpio.provisionDigitalOutputPin(raspiGpioProvider, RaspiBcmPin.GPIO_17, "RST", PinState.HIGH);
BUSY = gpio.provisionDigitalInputPin(raspiGpioProvider, RaspiBcmPin.GPIO_24, "BUSY");
try {
spiDevice = SpiFactory.getInstance(SpiChannel.CS1, SpiDevice.DEFAULT_SPI_SPEED, SpiDevice.DEFAULT_SPI_MODE);
} catch (Exception e) {
CommonUtil.printErrorToLogFile(e);
}
}
/**
* 绘制图片到屏幕
* @param image
* @throws IOException
* @throws InterruptedException
*/
public void drawImage(BufferedImage image) throws IOException, InterruptedException {
this.initLut();
this.clear();
this.display(image);
}
/**
* 重置屏幕
* @throws InterruptedException
*/
public void reset() throws InterruptedException {
CommonUtil.printLogToConsole("Reset the screen ...");
RST.high();
Thread.sleep(200);
RST.low();
Thread.sleep(10);
RST.high();
Thread.sleep(200);
}
/**
* 写入指令
* @param data
* @throws IOException
*/
public void sendCommand(int data) throws IOException {
DC.low();
CS.low();
spiDevice.write((byte) data);
CS.high();
}
/**
* 写入数据
* @param data
* @throws IOException
*/
public void sendData(int data) throws IOException {
DC.high();
CS.low();
spiDevice.write((byte) data);
CS.high();
}
/**
* 检查屏幕是否Busy
* @throws IOException
* @throws InterruptedException
*/
public void checkBusy() throws IOException, InterruptedException {
CommonUtil.printLogToConsole("Check whether the screen is busy ...");
this.sendCommand((byte) 0x71);
while (BUSY.isLow()) {
this.sendCommand((byte) 0x71);
Thread.sleep(200);
}
}
public void init() throws IOException, InterruptedException {
CommonUtil.printLogToConsole("Init the driver ...");
reset();
this.sendCommand(0x01); // power setting
this.sendData(0x17); // 1-0=11: internal power
this.sendData(Voltage_Frame_7IN5_V2[6]); // VGH&VGL
this.sendData(Voltage_Frame_7IN5_V2[1]); // VSH
this.sendData(Voltage_Frame_7IN5_V2[2]); // VSL
this.sendData(Voltage_Frame_7IN5_V2[3]); // VSHR
this.sendCommand(0x82); // # VCOM DC Setting
this.sendData(Voltage_Frame_7IN5_V2[4]); // VCOM
this.sendCommand(0x06); // Booster Setting
this.sendData(0x27);
this.sendData(0x27);
this.sendData(0x2F);
this.sendData(0x17);
this.sendCommand(0x30); // OSC Setting
this.sendData(Voltage_Frame_7IN5_V2[0]); // 2-0=100: N=4 5-3=111: M=7 3C=50Hz 3A=100HZ
this.sendCommand(0x04); // power on
this.checkBusy();
this.sendCommand(0X00); // PANNEL SETTING
this.sendData(0x3F); // #KW-3f KWR-2F BWROTP 0f BWOTP 1f
this.sendCommand(0x61); // tres
this.sendData(0x03); // source 800
this.sendData(0x20);
this.sendData(0x01); // gate 480
this.sendData(0xE0);
this.sendCommand(0X15);
this.sendData(0x00);
this.sendCommand(0X50); // VCOM AND DATA INTERVAL SETTING
this.sendData(0x10);
this.sendData(0x07);
this.sendCommand(0X60); // TCON SETTING
this.sendData(0x22);
this.sendCommand(0x65); // Resolution setting
this.sendData(0x00);
this.sendData(0x00); // 800*480
this.sendData(0x00);
this.sendData(0x00);
}
/**
* 初始化LUT
* @throws IOException
*/
public void initLut() throws IOException {
CommonUtil.printLogToConsole("Set LUT ...");
this.sendCommand(0x20);
for (int data : LUT_VCOM_7IN5_V2) {
this.sendData(data);
}
this.sendCommand(0x21);
for (int data : LUT_WW_7IN5_V2) {
this.sendData(data);
}
this.sendCommand(0x22);
for (int data : LUT_BW_7IN5_V2) {
this.sendData(data);
}
this.sendCommand(0x23);
for (int data : LUT_WB_7IN5_V2) {
this.sendData(data);
}
this.sendCommand(0x24);
for (int data : LUT_BB_7IN5_V2) {
this.sendData(data);
}
}
/**
* 清屏
* @throws IOException
* @throws InterruptedException
*/
public void clear() throws IOException, InterruptedException {
CommonUtil.printLogToConsole("Clear screen ...");
this.initLut();
this.sendCommand(0x10);
for (int i = 0; i < resolution; i++) {
this.sendData(0xFF);
}
this.sendCommand(0x13);
for (int i = 0; i < resolution; i++) {
this.sendData(0xFF);
}
this.sendCommand(0x12);
this.checkBusy();
}
/**
* 绘制屏幕画面
* @param image
* @throws IOException
* @throws InterruptedException
*/
public void display(BufferedImage image) throws IOException, InterruptedException {
final byte[] pixels = ((DataBufferByte)(image.getRaster().getDataBuffer())).getData();
this.display(pixels);
}
/**
* 绘制屏幕画面
* @param pixels
* @throws IOException
* @throws InterruptedException
*/
public void display(byte[] pixels) throws IOException, InterruptedException {
CommonUtil.printLogToConsole("Print image to screen ...");
this.initLut();
this.sendCommand(0x13);
int step = 0;
int temp = 0;
for (int i = 0; i < 800 * 480; i++) {
int grayNum = pixels[i] & 0xFF;
if (grayNum < GRAY_SCALE_OF_4[0]) {
temp |= 1;
} else if(grayNum < GRAY_SCALE_OF_4[1]){
temp |= 0;
}else if (grayNum < GRAY_SCALE_OF_4[2]) {
temp |= 1;
} else if(grayNum <= GRAY_SCALE_OF_4[3]){
temp |= 0;
}
step++;
if (step != 8) {
temp = temp << 1;
} else {
step = 0;
this.sendData(temp);
temp = 0;
}
}
this.sendCommand(0x12);
this.checkBusy();
}
private final static int[] Voltage_Frame_7IN5_V2 = { 0x6, 0x3F, 0x3F, 0x11, 0x24, 0x7, 0x17 };
private static final int[] GRAY_SCALE_OF_4 = {0xff / 4, 0xff / 4 * 2, 0xff / 4 * 3, 0xff};
private final static int[] LUT_VCOM_7IN5_V2 = {
0x0, 0xF, 0xF, 0x0, 0x0, 0x1,
0x0, 0xF, 0x1, 0xF, 0x1, 0x2,
0x0, 0xF, 0xF, 0x0, 0x0, 0x1,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0
};
private final static int[] LUT_WW_7IN5_V2 = {
0x10, 0xF, 0xF, 0x0, 0x0, 0x1,
0x84, 0xF, 0x1, 0xF, 0x1, 0x2,
0x20, 0xF, 0xF, 0x0, 0x0, 0x1,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0
};
private final static int[] LUT_BW_7IN5_V2 = {
0x10, 0xF, 0xF, 0x0, 0x0, 0x1,
0x84, 0xF, 0x1, 0xF, 0x1, 0x2,
0x20, 0xF, 0xF, 0x0, 0x0, 0x1,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0
};
private final static int[] LUT_WB_7IN5_V2 = {
0x80, 0xF, 0xF, 0x0, 0x0, 0x1,
0x84, 0xF, 0x1, 0xF, 0x1, 0x2,
0x40, 0xF, 0xF, 0x0, 0x0, 0x1,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0
};
private final static int[] LUT_BB_7IN5_V2 = {
0x80, 0xF, 0xF, 0x0, 0x0, 0x1,
0x84, 0xF, 0x1, 0xF, 0x1, 0x2,
0x40, 0xF, 0xF, 0x0, 0x0, 0x1,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0
};
}

View File

@@ -0,0 +1,97 @@
package icu.namophice.inkphotoalbum.utils;
import icu.namophice.inkphotoalbum.config.DefaultConfig;
import java.io.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* @author Namophice
* @createTime 2021-08-01 17:44
*/
public class CommonUtil {
/**
* 获取程序运行根目录
* @return
*/
public static String rootPath = System.getProperty("user.dir");
/**
* 打印异常信息至error.log
* @param exception
*/
public static void printErrorToLogFile(Exception exception) {
printErrorToLogFile(exception, true);
}
/**
* 打印异常信息至error.log
* @param exception
* @param clearLogFile
*/
public static void printErrorToLogFile(Exception exception, boolean clearLogFile) {
if (exception != null) {
try {
exception.printStackTrace();
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
exception.printStackTrace(pw);
final String errorDetail = "Error [" + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:ms").format(LocalDateTime.now()) + "] " + sw;
sw.close();
pw.close();
File logFile = new File(rootPath + "/error.log");
if ((!logFile.exists()) || logFile.isDirectory()) {
logFile.createNewFile();
}
FileWriter fileWriter = new FileWriter(logFile, clearLogFile);
fileWriter.write(errorDetail);
fileWriter.flush();
fileWriter.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 获取日志时间头
* @return
*/
public static String getLogTime() {
return "[" + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:ms").format(LocalDateTime.now()) + "] ";
}
/**
* 打印日志到控制台
* @param log
*/
public static void printLogToConsole(final String log) {
System.out.println("Info " + getLogTime() + log);
}
/**
* 打印图片下标位置到cache文件
* @param imageIndex
* @throws IOException
*/
public static void printImageIndexToCache(int imageIndex) throws IOException {
CommonUtil.printLogToConsole("Print image index to cache file ...");
File cacheFile = new File(CommonUtil.rootPath + "/" + DefaultConfig.cacheFileName);
if ((!cacheFile.exists()) || cacheFile.isDirectory()) {
cacheFile.createNewFile();
}
FileWriter fileWriter = new FileWriter(cacheFile, false);
fileWriter.write(String.valueOf(imageIndex));
fileWriter.flush();
fileWriter.close();
}
}

View File

@@ -0,0 +1,344 @@
package icu.namophice.inkphotoalbum.utils;
import icu.namophice.inkphotoalbum.config.DefaultConfig;
import icu.namophice.inkphotoalbum.driver.EPaper;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URL;
import java.util.Random;
/**
* @author Namophice
* @createTime 2021-08-04 16:28
*/
public class ImageUtil {
/**
* 获取可直接打印至屏幕的Image流
* @param imagePath
* @param isRemoteUrl
* @return
* @throws IOException
*/
public static BufferedImage getImageToScreen(final String imagePath, final boolean isRemoteUrl) throws IOException {
BufferedImage targetImage = getImage(imagePath, isRemoteUrl);
targetImage = tailoringImage(targetImage, EPaper.width, EPaper.height, DefaultConfig.enable_image_fill());
targetImage = getGaryImg(targetImage);
return targetImage;
}
/**
* 获取可直接打印至屏幕的Image流
* @param imageFile
* @return
* @throws IOException
*/
public static BufferedImage getImageToScreen(File imageFile) throws IOException {
BufferedImage targetImage = getImage(imageFile);
targetImage = tailoringImage(targetImage, EPaper.width, EPaper.height, DefaultConfig.enable_image_fill());
targetImage = getGaryImg(targetImage);
return targetImage;
}
/**
* 获取可直接打印至屏幕的Image流
* @return
* @throws IOException
*/
public static BufferedImage getImageToScreen() throws IOException {
return getImageToScreen(null);
}
/**
* 获取图片流
* @param imageUrl
* @param isRemoteUrl
* @return
* @throws IOException
*/
public static BufferedImage getImage(final String imageUrl, final boolean isRemoteUrl) throws IOException {
CommonUtil.printLogToConsole("Input image to BufferedImage ...");
if (imageUrl == null || imageUrl.length() < 1) {
return getDefaultImage();
} else {
InputStream imageStream;
if (isRemoteUrl) {
CommonUtil.printLogToConsole("Image path: " + imageUrl + " ...");
URL url = new URL(imageUrl);
imageStream = url.openStream();
} else {
File imgFile = new File(imageUrl);
if (imgFile.exists()) {
CommonUtil.printLogToConsole("Image path: " + imgFile.getAbsolutePath() + " ...");
imageStream = new FileInputStream(imgFile);
} else {
return getDefaultImage();
}
}
BufferedImage originImage = ImageIO.read(imageStream);
imageStream.close();
imageStream = null;
BufferedImage targetImage = new BufferedImage(originImage.getWidth(), originImage.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
for (int i = 0; i < originImage.getWidth(); i++) {
for (int j = 0; j < originImage.getHeight(); j++) {
targetImage.setRGB(i, j, originImage.getRGB(i, j));
}
}
return targetImage;
}
}
/**
* 获取图片流
* @param imageFile
* @return
* @throws IOException
*/
public static BufferedImage getImage(File imageFile) throws IOException {
CommonUtil.printLogToConsole("Input image to BufferedImage ...");
if (imageFile == null || !imageFile.exists() || imageFile.isDirectory()) {
return getDefaultImage();
} else {
CommonUtil.printLogToConsole("Image path: " + imageFile.getAbsolutePath() + " ...");
InputStream imageStream = new FileInputStream(imageFile);
BufferedImage originImage = ImageIO.read(imageStream);
imageStream.close();
BufferedImage targetImage = new BufferedImage(originImage.getWidth(), originImage.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
for (int i = 0; i < originImage.getWidth(); i++) {
for (int j = 0; j < originImage.getHeight(); j++) {
targetImage.setRGB(i, j, originImage.getRGB(i, j));
}
}
return targetImage;
}
}
/**
* 获取默认图片流
* @return
* @throws IOException
*/
public static BufferedImage getDefaultImage() throws IOException {
CommonUtil.printLogToConsole("Input default image to BufferedImage ...");
InputStream defaultImageStream = CommonUtil.class.getClassLoader().getResourceAsStream("images/default.bmp");
BufferedImage originImage = ImageIO.read(defaultImageStream);
defaultImageStream.close();
defaultImageStream = null;
BufferedImage targetImage = new BufferedImage(originImage.getWidth(), originImage.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
for (int i = 0; i < originImage.getWidth(); i++) {
for (int j = 0; j < originImage.getHeight(); j++) {
targetImage.setRGB(i, j, originImage.getRGB(i, j));
}
}
return targetImage;
}
/**
* 对图片做自适应or填充处理默认自适应
* @param originImage
* @param screenWidth
* @param screenHeight
* @param enable_image_fill
* @return
*/
public static BufferedImage tailoringImage(BufferedImage originImage, final int screenWidth, final int screenHeight, final boolean enable_image_fill) {
CommonUtil.printLogToConsole("Tailoring image with screen ...");
// 获取原始图片宽高
final BigDecimal originWidth = new BigDecimal(originImage.getWidth());
final BigDecimal originHeight = new BigDecimal(originImage.getHeight());
BufferedImage targetImage;
if (originWidth.intValue() == screenWidth && originHeight.intValue() == screenHeight) { // 图片宽高 == 屏幕宽高
return originImage;
} else if (originWidth.intValue() < screenWidth && originHeight.intValue() < screenHeight) { // 图片宽高 皆小于 屏幕宽高
targetImage = new BufferedImage(screenWidth, screenHeight, BufferedImage.TYPE_INT_RGB);
// 将原图居中,计算原图在输出图片中的位置
final int xStart = (screenWidth - originWidth.intValue()) / 2;
final int xEnd = originWidth.intValue() + xStart;
final int yStart = (screenHeight - originHeight.intValue()) / 2;
final int yEnd = originHeight.intValue() + yStart;
for (int x = 0; x < screenWidth; x++) {
for (int y = 0; y < screenHeight; y++) {
// 在输出图片中未被原始图片覆盖的位置直接做涂黑处理
if (x < xStart || x >= xEnd) {
targetImage.setRGB(x, y, 0);
} else {
if (y < yStart || y >= yEnd) {
targetImage.setRGB(x, y, 0);
} else {
targetImage.setRGB(x, y, originImage.getRGB(x - xStart, y - yStart));
}
}
}
}
return targetImage;
} else { // 图片宽 > 屏幕宽 or 图片高 > 屏幕高
// 屏幕宽高比例
final BigDecimal screenPercentage = new BigDecimal(screenWidth).divide(new BigDecimal(screenHeight), 5, RoundingMode.HALF_DOWN);
// 原图宽高比例
final BigDecimal imagePercentage = originWidth.divide(originHeight, 5, RoundingMode.HALF_UP);
int percentageCompareRes = screenPercentage.compareTo(imagePercentage);
if (percentageCompareRes == 0) { // 图片宽高比例 == 屏幕宽高比例
return originImage;
} else {
// 等比例放大,相同高度下,屏幕宽度小于原图宽度
boolean check = originHeight.multiply(new BigDecimal(screenWidth)).compareTo(originWidth.multiply(new BigDecimal(screenHeight))) < 1;
if (!DefaultConfig.defaultImageIsLoaded || !enable_image_fill) { // 自适应模式
CommonUtil.printLogToConsole("Enabled image adaptive mode ...");
if (check) {
final int targetWight = originWidth.intValue();
final int targetHeight = originWidth.divide(screenPercentage, 0, RoundingMode.HALF_DOWN).intValue();
targetImage = new BufferedImage(targetWight, targetHeight, BufferedImage.TYPE_INT_RGB);
final int yStart = (targetHeight - originHeight.intValue()) / 2;
final int yEnd = originHeight.intValue() + yStart;
for (int x = 0; x < targetWight; x++) {
for (int y = 0; y < targetHeight; y++) {
if (yStart <= y && y < yEnd) {
targetImage.setRGB(x, y, originImage.getRGB(x, y - yStart));
} else {
targetImage.setRGB(x, y, 0);
}
}
}
} else {
final int targetWight = originHeight.multiply(screenPercentage).intValue();
final int targetHeight = originHeight.intValue();
targetImage = new BufferedImage(targetWight, targetHeight, BufferedImage.TYPE_INT_RGB);
final int xStart = (targetWight - originWidth.intValue()) / 2;
final int xEnd = originWidth.intValue() + xStart;
for (int x = 0; x < targetWight; x++) {
for (int y = 0; y < targetHeight; y++) {
if (xStart <= x && x < xEnd) {
targetImage.setRGB(x, y, originImage.getRGB(x - xStart, y));
} else {
targetImage.setRGB(x, y, 0);
}
}
}
}
} else { // 填充模式
CommonUtil.printLogToConsole("Enabled image fill mode ...");
if (check) {
final int targetWight = originHeight.multiply(screenPercentage).intValue();
final int targetHeight = originHeight.intValue();
targetImage = new BufferedImage(targetWight, targetHeight, BufferedImage.TYPE_INT_RGB);
final int xStart = originWidth.subtract(new BigDecimal(targetWight)).divide(new BigDecimal(2), 0, RoundingMode.HALF_UP).intValue();
final int xEnd = originWidth.intValue() - xStart;
for (int x = 0; x < originWidth.intValue(); x++) {
for (int y = 0; y < originHeight.intValue(); y++) {
if (xStart <= x && x < xEnd) {
targetImage.setRGB(x - xStart, y, originImage.getRGB(x, y));
}
}
}
} else {
final int targetWight = originWidth.intValue();
final int targetHeight = originWidth.divide(screenPercentage, 0, RoundingMode.HALF_UP).intValue();
targetImage = new BufferedImage(targetWight, targetHeight, BufferedImage.TYPE_INT_RGB);
final int yStart = originHeight.subtract(new BigDecimal(targetHeight)).divide(new BigDecimal(2), 0, RoundingMode.HALF_UP).intValue();
final int yEnd = originHeight.intValue() - yStart;
for (int x = 0; x < originWidth.intValue(); x++) {
for (int y = 0; y < originHeight.intValue(); y++) {
if (yStart <= y && y < yEnd) {
targetImage.setRGB(x, y - yStart, originImage.getRGB(x, y));
}
}
}
}
}
// 根据屏幕做等比例缩放
CommonUtil.printLogToConsole("Scale image to the screen ...");
BufferedImage finallyImage = new BufferedImage(EPaper.width, EPaper.height, BufferedImage.TYPE_BYTE_GRAY);
Graphics graphics = finallyImage.getGraphics();
graphics.drawImage(targetImage, 0, 0, EPaper.width, EPaper.height, null);
return finallyImage;
}
}
}
/**
* 获取灰度图
* @param originImage
* @return
*/
public static BufferedImage getGaryImg(BufferedImage originImage) {
CommonUtil.printLogToConsole("Convert RGB to GRAY ...");
// 获取原始图片宽高
final int width = originImage.getWidth();
final int height = originImage.getHeight();
BufferedImage targetImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
int rgb = originImage.getRGB(i, j);
int oneGate = rgb & 0xffffff;
int randomNum = new Random().nextInt(0xffffff);
int binValue;
//0是黑 1是白 ,或者说数值小就靠近黑色,数值大就靠近白色
if(oneGate > 0xec82e0) { // 大于一定数值,直接用白点
binValue = 0xffffff;
} else if(oneGate < 0x6ea050) { // 小于一定数值直接用黑点
binValue = 0;
} else if(oneGate > randomNum) { // 模拟灰阶使用随机数画白点
binValue = 0xffffff;
} else {
binValue = 0;
}
targetImage.setRGB(i, j, binValue);
}
}
return targetImage;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

View File

@@ -0,0 +1,33 @@
package icu.namophice.inkphotoalbum;
import icu.namophice.inkphotoalbum.config.DefaultConfig;
import icu.namophice.inkphotoalbum.utils.CommonUtil;
import icu.namophice.inkphotoalbum.utils.ImageUtil;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
/**
* @author Namophice
* @createTime 2021-07-29 16:43
*/
public class Test {
public static void main(String[] args) {
try {
BufferedImage targetImage = ImageUtil.getImageToScreen(CommonUtil.rootPath + "/" + DefaultConfig.imagePath + "/" + "self_22.jpg", false);
printImage(targetImage, CommonUtil.rootPath + "/test.jpg");
} catch (Exception e) {
e.printStackTrace();
CommonUtil.printErrorToLogFile(e);
}
}
private static void printImage(BufferedImage image, String path) throws IOException {
File file = new File(path);
ImageIO.write(image, "JPG", file);
}
}

10
start.sh Normal file
View File

@@ -0,0 +1,10 @@
#!/bin/sh
/usr/bin/rm /opt/software/ink-photo-album/cache
while true
do
cd /opt/software/ink-photo-album
/usr/bin/sudo /usr/bin/java -jar /opt/software/ink-photo-album/ink-photo-album-1.0-SNAPSHOT-all.jar
sleep 5m
done