Initial project
This commit is contained in:
128
.gitignore
vendored
128
.gitignore
vendored
@ -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/
|
target/
|
||||||
pom.xml.tag
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
pom.xml.releaseBackup
|
!**/src/main/**/target/
|
||||||
pom.xml.versionsBackup
|
!**/src/test/**/target/
|
||||||
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
|
|
||||||
|
|
||||||
# Eclipse m2e generated files
|
### IntelliJ IDEA ###
|
||||||
# Eclipse Core
|
.idea/modules.xml
|
||||||
.project
|
.idea/jarRepositories.xml
|
||||||
# JDT-specific (Eclipse Java Development Tools)
|
.idea/compiler.xml
|
||||||
|
.idea/libraries/
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
### Eclipse ###
|
||||||
|
.apt_generated
|
||||||
.classpath
|
.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
3
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
7
.idea/encodings.xml
generated
Normal file
7
.idea/encodings.xml
generated
Normal 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
14
.idea/misc.xml
generated
Normal 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
124
.idea/uiDesigner.xml
generated
Normal 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
6
.idea/vcs.xml
generated
Normal 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
43
pom.xml
Normal 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>
|
||||||
384
src/main/java/com/imyeyu/fx/icon/TimiFXIcon.java
Normal file
384
src/main/java/com/imyeyu/fx/icon/TimiFXIcon.java
Normal 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<字号, 字体> */
|
||||||
|
private static final Map<Integer, Font> FONT_MAPPING = new HashMap<>();
|
||||||
|
|
||||||
|
/** 映射缓存 Map<图标名, Unicode> */
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
src/main/java/com/imyeyu/fx/icon/package-info.java
Normal file
2
src/main/java/com/imyeyu/fx/icon/package-info.java
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/** 主程序 */
|
||||||
|
package com.imyeyu.fx.icon;
|
||||||
96
src/main/java/com/imyeyu/fx/icon/util/ImageConvertor.java
Normal file
96
src/main/java/com/imyeyu/fx/icon/util/ImageConvertor.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
2
src/main/java/com/imyeyu/fx/icon/util/package-info.java
Normal file
2
src/main/java/com/imyeyu/fx/icon/util/package-info.java
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/** 工具 */
|
||||||
|
package com.imyeyu.fx.icon.util;
|
||||||
BIN
src/main/resources/font/timi-icon.mapping
Normal file
BIN
src/main/resources/font/timi-icon.mapping
Normal file
Binary file not shown.
BIN
src/main/resources/font/timi-icon.ttf
Normal file
BIN
src/main/resources/font/timi-icon.ttf
Normal file
Binary file not shown.
80
src/test/java/test/SerializeMapping.java
Normal file
80
src/test/java/test/SerializeMapping.java
Normal 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<图标名, Unicode> 对象
|
||||||
|
*
|
||||||
|
* @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");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user