Initial project

This commit is contained in:
Timi
2025-07-14 14:20:00 +08:00
parent 6266e06db1
commit 843eaef0cd
14 changed files with 795 additions and 94 deletions

128
.gitignore vendored
View File

@ -1,98 +1,38 @@
# ---> JetBrains
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
# ---> Maven
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
.mvn/wrapper/maven-wrapper.jar
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
# Eclipse m2e generated files
# Eclipse Core
.project
# JDT-specific (Eclipse Java Development Tools)
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

3
.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

7
.idea/encodings.xml generated Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>

14
.idea/misc.xml generated Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

124
.idea/uiDesigner.xml generated Normal file
View File

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

43
pom.xml Normal file
View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.imyeyu.fx.icon</groupId>
<artifactId>timi-fx-icon</artifactId>
<version>0.0.1</version>
<properties>
<fx.version>21.0.2</fx.version>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>${fx.version}</version>
</dependency>
<dependency>
<groupId>com.imyeyu.io</groupId>
<artifactId>timi-io</artifactId>
<version>0.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,384 @@
package com.imyeyu.fx.icon;
import javafx.scene.SnapshotParameters;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.Image;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import com.imyeyu.fx.icon.util.ImageConvertor;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.util.HashMap;
import java.util.Map;
/**
* JavaFX 像素风字体图标库,这些图标基于 16x 像素绘制,即图标在 16 32 64.. 等字号时渲染最清晰准确
*
* <p>图标名称可在 <a href="https://icon.imyeyu.net/">https://icon.imyeyu.net/</a> 查询</p>
*
* <pre>
* // 静态类,不需要实例化,直接调用静态方法
* TimiFXIcon.fromName("FILE");
* </pre>
*
* @author 夜雨
* @since 2022-07-28 09:57
*/
public class TimiFXIcon {
// ---------- 公开属性 ----------
/** 默认颜色 */
public static final Paint COLOR = Paint.valueOf("#333");
/** 字体文件资源路径 */
public static final String FONT_PATH = "font/timi-icon.ttf";
// ---------- 私有属性 ----------
/** 图标名称映射 Unicode 序列化文件路径 */
private static final String NAME_MAPPING_PATH = "font/timi-icon.mapping";
/** 组件样式类 */
private static final String STYLE_CLASS = "timi-icon";
/** 字体文件字节 */
private static byte[] bytes;
/** 用于转换渲染的画板 */
private static final Canvas CANVAS = new Canvas();
private static final GraphicsContext G2D = CANVAS.getGraphicsContext2D();
/** 图标字体缓存 Map&lt;字号, 字体&gt; */
private static final Map<Integer, Font> FONT_MAPPING = new HashMap<>();
/** 映射缓存 Map&lt;图标名, Unicode&gt; */
private static Map<String, Character> nameMapping;
/** 这个类不可实例化 */
private TimiFXIcon() {
}
/** 读取图标与 Unicode 的映射,由项目测试环境生成 */
@SuppressWarnings("unchecked")
private static synchronized void loadMapping() {
if (nameMapping == null) {
try {
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(NAME_MAPPING_PATH);
if (is == null) {
throw new NullPointerException("not found /font/timi-icon.ttf file");
}
ObjectInputStream ois = new ObjectInputStream(is);
nameMapping = (Map<String, Character>) ois.readObject();
ois.close();
is.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
/**
* 获取名称字符映射表
*
* @return 名称字符映射表
*/
public static Map<String, Character> getNameMapping() {
loadMapping();
return new HashMap<>(nameMapping); // 阻止修改
}
/**
* 获取字体文件数据流
*
* @return 字体文件数据流
*/
public static InputStream getInputStream() {
if (bytes == null) {
try {
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(FONT_PATH);
if (is == null) {
throw new NullPointerException("not found /font/timi-icon.ttf file");
}
bytes = is.readAllBytes();
is.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return new ByteArrayInputStream(bytes);
}
/**
* 获取字体
*
* @param size 字号
* @return 字体
*/
public static synchronized Font getFont(int size) {
if (FONT_MAPPING.containsKey(size)) {
return FONT_MAPPING.get(size);
}
Font font = Font.loadFont(getInputStream(), size);
FONT_MAPPING.put(size, font);
return font;
}
// ---------- 根据名称获取图标字符 ----------
/**
* 根据名称获取图标字符
*
* @param name 名称
* @return 字符
*/
public static char toChar(String name) {
if (nameMapping == null) {
loadMapping();
}
Character c = nameMapping.get(name.toLowerCase());
if (c == null) {
throw new NullPointerException("not found char from the name: " + name);
}
return c;
}
// ---------- 根据名称获取图标文本 ----------
/**
* 根据名称获取图标
*
* @param name 名称
* @return 图标文本
*/
public static Text fromName(String name) {
return fromName(name, 16, COLOR);
}
/**
* 根据名称获取图标
*
* @param name 名称
* @param size 字号
* @return 图标文本
*/
public static Text fromName(String name, int size) {
return fromName(name, size, COLOR);
}
/**
* 根据名称获取图标
*
* @param name 名称
* @param fill 填充色
* @return 图标文本
*/
public static Text fromName(String name, Paint fill) {
return fromName(name, 16, fill);
}
/**
* 根据名称获取图标
*
* @param name 名称
* @param size 字号
* @param fill 填充色
* @return 图标文本
*/
public static Text fromName(String name, int size, Paint fill) {
return fromChar(toChar(name), size, fill);
}
// ---------- 根据字符获取图标文本 ----------
/**
* 根据字符获取图标
*
* @param c 字符
* @return 图标文本
*/
public static Text fromChar(char c) {
return fromChar(c, 16, COLOR);
}
/**
* 根据字符获取图标
*
* @param c 字符
* @param size 字号
* @return 图标文本
*/
public static Text fromChar(char c, int size) {
return fromChar(c, size, COLOR);
}
/**
* 根据字符获取图标
*
* @param c 字符
* @param fill 填充色
* @return 图标文本
*/
public static Text fromChar(char c, Paint fill) {
return fromChar(c, 16, fill);
}
/**
* 根据字符获取图标
*
* @param c 字符
* @param size 字号
* @param fill 填充色
* @return 图标文本
*/
public static Text fromChar(char c, int size, Paint fill) {
Text text = new Text(String.valueOf(c));
text.getStyleClass().setAll(STYLE_CLASS);
text.setFont(getFont(size));
text.setFill(fill);
return text;
}
// ---------- 根据名称获取图像 ----------
/**
* 根据名称获取图像
*
* @param name 名称
* @return 图像
*/
public static Image imageFromName(String name) {
return imageFromName(name, 16, COLOR);
}
/**
* 根据名称获取图像
*
* @param name 名称
* @param fill 填充
* @return 图像
*/
public static Image imageFromName(String name, Paint fill) {
return imageFromName(name, 16, fill);
}
/**
* 根据名称获取图像
*
* @param name 名称
* @param size 尺寸
* @return 图像
*/
public static Image imageFromName(String name, int size) {
return imageFromName(name, size, COLOR);
}
/**
* 根据名称获取图像
*
* @param name 名称
* @param size 尺寸
* @param fill 填充
* @return 图像
*/
public static Image imageFromName(String name, int size, Paint fill) {
return imageFromChar(toChar(name), size, fill);
}
// ---------- 根据字符获取图像 ----------
/**
* 图标字符转图像
*
* @param c 字符
* @return 图像
*/
public static Image imageFromChar(char c) {
return imageFromChar(c, 16, COLOR);
}
/**
* 图标字符转图像
*
* @param c 字符
* @param size 尺寸
* @return 图像
*/
public static Image imageFromChar(char c, int size) {
return imageFromChar(c, size, COLOR);
}
/**
* 图标字符转图像
*
* @param c 字符
* @param fill 填充
* @return 图像
*/
public static Image imageFromChar(char c, Paint fill) {
return imageFromChar(c, 16, fill);
}
/**
* 图标字符转图像
*
* @param c 字符
* @param size 尺寸
* @param fill 填充
* @return 图像
*/
public static Image imageFromChar(char c, int size, Paint fill) {
CANVAS.setWidth(size);
CANVAS.setHeight(size);
G2D.clearRect(0, 0, CANVAS.getWidth(), CANVAS.getHeight());
G2D.setFont(getFont(size));
G2D.setFill(fill);
G2D.fillText(String.valueOf(c), 0, size - size / 16D);
SnapshotParameters sp = new SnapshotParameters();
sp.setFill(Color.TRANSPARENT);
return CANVAS.snapshot(sp, null);
}
// ---------- 根据名称获取重绘图像 ----------
/**
* 根据名称获取图标(产生重绘,可用在 Stage 图标)
*
* @param name 名称
* @return 图标
*/
public static Image iconFromName(String name) {
return iconFromName(name, COLOR);
}
/**
* 根据名称获取图标(产生重绘,可用在 Stage 图标)
*
* @param name 名称
* @param fill 填充
* @return 图标
*/
public static Image iconFromName(String name, Paint fill) {
try {
BufferedImage bImage = ImageConvertor.toAWTImage(imageFromName(name, fill));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(bImage, "PNG", baos);
bImage.flush();
baos.flush();
baos.close();
return new Image(new ByteArrayInputStream(baos.toByteArray()));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,2 @@
/** 主程序 */
package com.imyeyu.fx.icon;

View File

@ -0,0 +1,96 @@
package com.imyeyu.fx.icon.util;
import javafx.scene.image.Image;
import javafx.scene.image.PixelFormat;
import javafx.scene.image.PixelReader;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.image.WritablePixelFormat;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.awt.image.SampleModel;
import java.awt.image.SinglePixelPackedSampleModel;
import java.nio.IntBuffer;
/**
* JavaFX 和 AWT 图片转换
*
* @author 夜雨
* @since 2022-10-09 23:16
*/
public class ImageConvertor {
/**
* AWT 图像转 JavaFX 图像
*
* @param bimg AWT 图像
* @return JavaFX 图像
*/
public static WritableImage toFXImage(BufferedImage bimg) {
int bw = bimg.getWidth();
int bh = bimg.getHeight();
switch (bimg.getType()) {
case BufferedImage.TYPE_INT_ARGB:
case BufferedImage.TYPE_INT_ARGB_PRE:
break;
default:
BufferedImage converted = new BufferedImage(bw, bh, BufferedImage.TYPE_INT_ARGB_PRE);
Graphics2D g2d = converted.createGraphics();
g2d.drawImage(bimg, 0, 0, null);
g2d.dispose();
bimg = converted;
break;
}
WritableImage img = new WritableImage(bw, bh);
PixelWriter pw = img.getPixelWriter();
DataBufferInt db = (DataBufferInt) bimg.getRaster().getDataBuffer();
int[] data = db.getData();
int offset = bimg.getRaster().getDataBuffer().getOffset();
int scan = 0;
SampleModel sm = bimg.getRaster().getSampleModel();
if (sm instanceof SinglePixelPackedSampleModel) {
scan = ((SinglePixelPackedSampleModel) sm).getScanlineStride();
}
PixelFormat<IntBuffer> pf = (bimg.isAlphaPremultiplied() ? PixelFormat.getIntArgbPreInstance() : PixelFormat.getIntArgbInstance());
pw.setPixels(0, 0, bw, bh, pf, data, offset, scan);
return img;
}
/**
* JavaFX 图像转 AWT 图像
*
* @param img JavaFX 图像
* @return AWT 图像
*/
public static BufferedImage toAWTImage(Image img) {
PixelReader pr = img.getPixelReader();
int iw = (int) img.getWidth();
int ih = (int) img.getHeight();
PixelFormat<?> fxFormat = pr.getPixelFormat();
int prefImgType = switch (fxFormat.getType()) {
case BYTE_BGRA_PRE, INT_ARGB_PRE -> BufferedImage.TYPE_INT_ARGB_PRE;
case BYTE_BGRA, INT_ARGB -> BufferedImage.TYPE_INT_ARGB;
case BYTE_RGB -> BufferedImage.TYPE_INT_RGB;
case BYTE_INDEXED -> (fxFormat.isPremultiplied() ? BufferedImage.TYPE_INT_ARGB_PRE : BufferedImage.TYPE_INT_ARGB);
};
BufferedImage bImg = new BufferedImage(iw, ih, prefImgType);
DataBufferInt db = (DataBufferInt) bImg.getRaster().getDataBuffer();
int[] data = db.getData();
int offset = bImg.getRaster().getDataBuffer().getOffset();
int scan = 0;
SampleModel sm = bImg.getRaster().getSampleModel();
if (sm instanceof SinglePixelPackedSampleModel) {
scan = ((SinglePixelPackedSampleModel) sm).getScanlineStride();
}
WritablePixelFormat<IntBuffer> pf = switch (bImg.getType()) {
case BufferedImage.TYPE_INT_RGB, BufferedImage.TYPE_INT_ARGB_PRE -> PixelFormat.getIntArgbPreInstance();
case BufferedImage.TYPE_INT_ARGB -> PixelFormat.getIntArgbInstance();
default -> throw new InternalError("Failed to validate BufferedImage type");
};
pr.getPixels(0, 0, iw, ih, pf, data, offset, scan);
return bImg;
}
}

View File

@ -0,0 +1,2 @@
/** 工具 */
package com.imyeyu.fx.icon.util;

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,80 @@
package test;
import com.google.gson.GsonBuilder;
import com.imyeyu.io.IO;
import com.imyeyu.utils.Encoder;
import com.imyeyu.utils.Time;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* IcoMoon 生成的 xml 映射序列化为 Map&lt;图标名, Unicode&gt; 对象
*
* @author 夜雨
* @since 2022-07-28 21:16
*/
public class SerializeMapping {
public static void main(String[] args) throws Exception {
String subVersion = "a";
String versionExt = Time.ymd.format(Time.now()) + subVersion;
// 输出映射文件
File jsonFile = new File("src/test/resources/timi-icon_%s.json".formatted(versionExt));
File serializeFile = new File("src/main/resources/font/timi-icon.mapping");
System.out.println("serialize to " + serializeFile.getAbsolutePath());
// 读取 SVG 映射
String svgPath = "timi-icon.svg";
Document dom = new SAXReader().read(Thread.currentThread().getContextClassLoader().getResourceAsStream(svgPath));
List<?> glyphs = dom.getRootElement().element("defs").element("font").elements();
System.out.println("read dom xml successes");
// 解析 Unicode 映射
Map<String, String> json = new HashMap<>();
Map<String, Character> map = new HashMap<>();
for (int i = 0; i < glyphs.size(); i++) {
if (glyphs.get(i) instanceof Element glyph) {
String name = glyph.attributeValue("glyph-name");
String unicode = glyph.attributeValue("unicode");
if (name != null) {
json.put(name.trim(), Encoder.unicode(unicode));
map.put(name.trim(), unicode.charAt(0));
}
}
}
System.out.println("parse finish: map size = " + map.size());
// 序列化文件
IO.toFile(jsonFile, new GsonBuilder().setPrettyPrinting().create().toJson(json).replaceAll(" ", "\t").replaceAll("\\\\\\\\", "\\\\"));
FileOutputStream fos = new FileOutputStream(serializeFile);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(map);
oos.close();
fos.close();
Path ttfFrom = new File("src/test/resources/timi-icon.ttf").toPath();
Path ttfTo = new File("src/main/resources/font/timi-icon.ttf").toPath();
Files.copy(ttfFrom, ttfTo, StandardCopyOption.REPLACE_EXISTING);
IO.rename(new File("src/test/resources/timi-icon.svg"), "timi-icon_%s.svg".formatted(versionExt));
IO.rename(new File("src/test/resources/timi-icon.eot"), "timi-icon_%s.eot".formatted(versionExt));
IO.rename(new File("src/test/resources/timi-icon.ttf"), "timi-icon_%s.ttf".formatted(versionExt));
IO.rename(new File("src/test/resources/timi-icon.woff"), "timi-icon_%s.woff".formatted(versionExt));
System.out.println("serialize mapping successes");
}
}