Henry.Wang
3 years ago
2 changed files with 246 additions and 0 deletions
@ -0,0 +1,147 @@ |
|||||||
|
package com.fr.base.svg; |
||||||
|
|
||||||
|
import com.fr.general.IOUtils; |
||||||
|
import com.fr.log.FineLoggerFactory; |
||||||
|
import com.fr.stable.bridge.StableFactory; |
||||||
|
import com.fr.stable.fun.ResourcePathTransformer; |
||||||
|
import com.fr.stable.plugin.ExtraClassManagerProvider; |
||||||
|
|
||||||
|
import javax.swing.*; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.HashSet; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
/** |
||||||
|
* 主要是用来读取svgIcon的工具类 |
||||||
|
* @author Yvan |
||||||
|
* @version 10.0 |
||||||
|
* Created by Yvan on 2020/12/23 |
||||||
|
*/ |
||||||
|
public class IconUtils { |
||||||
|
|
||||||
|
private static final String ICON_SUFFIX_SVG = ".svg"; |
||||||
|
private static final String ICON_SUFFIX_PNG = ".png"; |
||||||
|
private static final String ICON_SUFFIX_GIF = ".gif"; |
||||||
|
private static final String SUFFIX_SEPARATOR = "."; |
||||||
|
|
||||||
|
public static final String ICON_TYPE_NORMAL= "_normal.svg"; |
||||||
|
public static final String ICON_TYPE_DISABLED= "_disabled.svg"; |
||||||
|
public static final String ICON_TYPE_PRESSED= "_pressed.svg"; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 可以读取SVG图标或者普通图标,并且可以读取不带扩展名的文件 |
||||||
|
* 不带扩展名时以svg优先、其次png,最后gif |
||||||
|
* @param resource 图片路径 |
||||||
|
* @return 图标 |
||||||
|
*/ |
||||||
|
public static Icon readIcon(String resource) { |
||||||
|
// 判断是否有.XXX文件后缀
|
||||||
|
if (resource.contains(SUFFIX_SEPARATOR)) { |
||||||
|
// 判断是否以.svg结尾
|
||||||
|
if (resource.endsWith(ICON_SUFFIX_SVG)) { |
||||||
|
if (IOUtils.readResource(resource) != null) { |
||||||
|
return SVGIcon.readSVGIcon(transformPath(resource)); |
||||||
|
} |
||||||
|
// 适配插件
|
||||||
|
return adjustPluginsPng(resource); |
||||||
|
} |
||||||
|
return IOUtils.readIcon(resource); |
||||||
|
} |
||||||
|
// 文件无后缀时
|
||||||
|
return readNoSuffixResource(resource, ICON_TYPE_NORMAL); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 适配插件中使用_normal.png、_selected.png、_disabled.png的情况 |
||||||
|
* @param resource 图片路径 |
||||||
|
* @return Icon |
||||||
|
*/ |
||||||
|
private static Icon adjustPluginsPng(String resource) { |
||||||
|
String pngResource = resource.replace(ICON_SUFFIX_SVG, ICON_SUFFIX_PNG); |
||||||
|
// 考虑到某些插件可能只会使用三种图标中的一部分,这里做个判断,不然就会因为资源不存在而报错
|
||||||
|
return IOUtils.readResource(pngResource) == null ? new ImageIcon() : IOUtils.readIcon(pngResource); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 尝试读取不带扩展名的图标,svg优先,其次png,最后gif,都没读到就打印错误日志,返回空白Icon |
||||||
|
* @param resource 图片路径 |
||||||
|
* @param svgIconType 针对svg来说的图标类型 |
||||||
|
* 取值为:ICON_TYPE_NORMAL、ICON_TYPE_DISABLED、ICON_TYPE_PRESSED |
||||||
|
* @return 图标 |
||||||
|
*/ |
||||||
|
private static Icon readNoSuffixResource(String resource, String svgIconType) { |
||||||
|
String svgPath = resource + svgIconType; |
||||||
|
if (IOUtils.readResource(svgPath) != null) { |
||||||
|
return SVGIcon.readSVGIcon(transformPath(svgPath)); |
||||||
|
} |
||||||
|
String pngPath = resource + ICON_SUFFIX_PNG; |
||||||
|
if (IOUtils.readResource(pngPath) != null) { |
||||||
|
return IOUtils.readIcon(transformPath(pngPath)); |
||||||
|
} |
||||||
|
String gifPath = resource + ICON_SUFFIX_GIF; |
||||||
|
if (IOUtils.readResource(gifPath) != null) { |
||||||
|
return IOUtils.readIcon(transformPath(gifPath)); |
||||||
|
} |
||||||
|
FineLoggerFactory.getLogger().error("File not exists:{}", resource); |
||||||
|
return new ImageIcon(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 读取指定类型的svgIcon |
||||||
|
* @param resource |
||||||
|
* @param svgIconType |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public static Icon readSVGIcon(String resource, String svgIconType) { |
||||||
|
// 判断下是否有后缀
|
||||||
|
if (!resource.contains(SUFFIX_SEPARATOR)) { |
||||||
|
return readNoSuffixResource(resource, svgIconType); |
||||||
|
} |
||||||
|
// 如果是".png"后缀,就替换为传入的svgIconType,然后读取图标
|
||||||
|
if (resource.endsWith(ICON_SUFFIX_PNG)) { |
||||||
|
return readSpecifiedTypeIcon(resource, ICON_SUFFIX_PNG, svgIconType); |
||||||
|
} |
||||||
|
// 如果是"_XXXXXX.svg"后缀
|
||||||
|
if (resource.endsWith(ICON_TYPE_NORMAL)) { |
||||||
|
return readSpecifiedTypeIcon(resource, ICON_TYPE_NORMAL, svgIconType); |
||||||
|
} |
||||||
|
if (resource.endsWith(ICON_TYPE_DISABLED)) { |
||||||
|
return readSpecifiedTypeIcon(resource, ICON_TYPE_DISABLED, svgIconType); |
||||||
|
} |
||||||
|
if (resource.endsWith(ICON_TYPE_PRESSED)) { |
||||||
|
return readSpecifiedTypeIcon(resource, ICON_TYPE_PRESSED, svgIconType); |
||||||
|
} |
||||||
|
return readIcon(resource); |
||||||
|
} |
||||||
|
|
||||||
|
private static Icon readSpecifiedTypeIcon(String resource, String oldSuffix, String newSuffix) { |
||||||
|
String iconPath = resource.replace(oldSuffix, newSuffix); |
||||||
|
if (IOUtils.readResource(iconPath) != null) { |
||||||
|
return SVGIcon.readSVGIcon(transformPath(iconPath)); |
||||||
|
} |
||||||
|
return readIcon(resource); |
||||||
|
} |
||||||
|
|
||||||
|
private static String transformPath(String path) { |
||||||
|
Set<ResourcePathTransformer> set = getResourcePathTransformers(); |
||||||
|
for (ResourcePathTransformer transformer : set) { |
||||||
|
if (transformer.accept(path)) { |
||||||
|
return transformer.transform(path); |
||||||
|
} |
||||||
|
} |
||||||
|
return path; |
||||||
|
} |
||||||
|
|
||||||
|
private static Set<ResourcePathTransformer> getResourcePathTransformers() { |
||||||
|
Set<ResourcePathTransformer> set = new HashSet<ResourcePathTransformer>(); |
||||||
|
ExtraClassManagerProvider provider = StableFactory.getExtraClassManager(); |
||||||
|
if (provider != null) { |
||||||
|
Set<ResourcePathTransformer> pluginProvided = provider.getArray(ResourcePathTransformer.MARK_STRING); |
||||||
|
set.addAll(pluginProvided); |
||||||
|
} |
||||||
|
ResourcePathTransformer[] oemSet = StableFactory.getMarkedObjectsFromCollection(ResourcePathTransformer.MARK_STRING, ResourcePathTransformer.class); |
||||||
|
set.addAll(Arrays.asList(oemSet)); |
||||||
|
return set; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,99 @@ |
|||||||
|
package com.fr.base.svg; |
||||||
|
|
||||||
|
import com.fr.general.IOUtils; |
||||||
|
|
||||||
|
import javax.swing.*; |
||||||
|
import java.awt.*; |
||||||
|
import java.awt.image.BufferedImage; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||||
|
|
||||||
|
/** |
||||||
|
* SVG转化而来的Icon |
||||||
|
* @author Yvan |
||||||
|
* @version 10.0 |
||||||
|
* Created by Yvan on 2020/12/17 |
||||||
|
*/ |
||||||
|
public class SVGIcon implements Icon { |
||||||
|
|
||||||
|
private BufferedImage image; |
||||||
|
|
||||||
|
private static final boolean HI_DPI_SURPORT = SystemScaleUtils.isJreHiDPIEnabled(); |
||||||
|
|
||||||
|
public static final float SYSTEM_SCALE = SystemScaleUtils.sysScale(); |
||||||
|
|
||||||
|
private static final String ICON_PREFIX = "/"; |
||||||
|
|
||||||
|
public SVGIcon(BufferedImage image) { |
||||||
|
this.image = image; |
||||||
|
} |
||||||
|
|
||||||
|
private static Map<String, Icon> iconCache = new ConcurrentHashMap<>(); |
||||||
|
|
||||||
|
@Override |
||||||
|
public void paintIcon(Component c, Graphics g, int x, int y) { |
||||||
|
if (HI_DPI_SURPORT) { |
||||||
|
Graphics2D graphics = (Graphics2D) g.create(x, y, image.getWidth(null), image.getHeight(null)); |
||||||
|
float scale = SYSTEM_SCALE; |
||||||
|
graphics.scale(1 / scale, 1 / scale); |
||||||
|
graphics.drawImage(image, 0, 0, null); |
||||||
|
graphics.scale(1.0D, 1.0D); |
||||||
|
graphics.dispose(); |
||||||
|
} else { |
||||||
|
g.drawImage(image, x, y, null); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getIconWidth() { |
||||||
|
return HI_DPI_SURPORT ? (int) (image.getWidth() / SYSTEM_SCALE) : image.getWidth(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getIconHeight() { |
||||||
|
return HI_DPI_SURPORT ? (int) (image.getHeight() / SYSTEM_SCALE) : image.getHeight(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 读取高清图标 |
||||||
|
* @param url |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public static Icon readSVGIcon(String url) { |
||||||
|
return readSVGIconWithCache(url, true); |
||||||
|
} |
||||||
|
|
||||||
|
public static Icon readSVGIconWithCache(String url, boolean cacheRead) { |
||||||
|
Icon icon = null; |
||||||
|
if (cacheRead) { |
||||||
|
icon = iconCache.get(url); |
||||||
|
} |
||||||
|
if (icon == null) { |
||||||
|
if (!url.startsWith(ICON_PREFIX)) { |
||||||
|
url = ICON_PREFIX + url; |
||||||
|
} |
||||||
|
BufferedImage image = (BufferedImage) SVGLoader.load(url); |
||||||
|
icon = image == null ? IOUtils.readIcon(url) : new SVGIcon(image); |
||||||
|
//只缓存svg图标
|
||||||
|
if (image != null){ |
||||||
|
iconCache.put(url, icon); |
||||||
|
} |
||||||
|
} |
||||||
|
return icon; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 读取指定尺寸的图标 |
||||||
|
* @param url 资源路径 |
||||||
|
* @param width 宽度 |
||||||
|
* @param height 高度 |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public static Icon readSVGIcon(String url, float width, float height) { |
||||||
|
if (!url.startsWith(ICON_PREFIX)) { |
||||||
|
url = ICON_PREFIX + url; |
||||||
|
} |
||||||
|
BufferedImage image = (BufferedImage) SVGLoader.load(url, width, height); |
||||||
|
return image == null ? IOUtils.readIcon(url) : new SVGIcon(image); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue