Java实现快捷图片快捷编码
大约 5 分钟
需求
写md博文时候经常需要插入图片,由于直接插入图片需要图床支持,略显麻烦,所以需要将图片转成base64编码,然后直接复制到md中,这样就可以直接插入图片了.
图片base64编码互转
图片转base64字符串
/*
* 读取剪切板方式
*/
public void toBase64(BufferedImage image) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
// 如果估算大小大于500k,则进行有损压缩,否则无损,反复压缩可能导致图像过于模糊
try {
if (getImageSize(image) > (1024 * 500)) {
Thumbnails.of(image).scale(1.0) // 根据需求调整缩放比例或尺寸
.outputQuality(0.6) // 设置JPEG质量
.outputFormat("jpeg") // 设置图片格式 Thumbnails不支持png,请使用jpg或者jpeg
.toOutputStream(bos);
} else {
ImageIO.write(image, "png", bos);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte[] byteArray = bos.toByteArray();
String encodeToString = Base64.getEncoder().encodeToString(byteArray);
// 输出base64编码到剪切板
Paste.setSysClipboardText("data:image/jpeg;base64," + encodeToString);
}
/*
* 读取文件方式
*/
public void toBase64(String fileString) {
// 在linux可能为 file:///home/bjtang/图片/Screenshot_20240312_233916.png
// 需要首先进行转换
int indexOf = fileString.indexOf("file://");
if (indexOf >= 0) {
fileString = fileString.substring("file://".length());
}
try {
File inputFile = new File(fileString);
BufferedImage originalImage = ImageIO.read(inputFile);
toBase64(originalImage);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 在Java中,BufferedImage对象的大小(即占用内存存储)并不直接提供一个API来获取。但是,你可以通过计算图像像素数量乘以每个像素的字节数来估算其内存占用。
* 对于不带Alpha通道的RGB图像,每个像素通常占用3个字节(红、绿、蓝各1字节)。如果图像有Alpha通道,则每个像素占用4个字节(红、绿、蓝、透明度各1字节)。
* */
public long getImageSize(BufferedImage image) {
int width = image.getWidth();
int height = image.getHeight();
// 获取图像类型并判断是否包含Alpha通道
int type = image.getType();
boolean hasAlpha = (type == BufferedImage.TYPE_4BYTE_ABGR || type == BufferedImage.TYPE_4BYTE_ABGR_PRE
|| type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_ARGB_PRE);
double bytesPerPixel = hasAlpha ? 4.0 : 3.0; // 带Alpha通道或不带Alpha通道
long estimatedSizeInBytes = (long) (width * height * bytesPerPixel);
return estimatedSizeInBytes;
}
base64字符串转图片
public void toImages(String string) {
try {
int indexOf = string.indexOf("data");
if (indexOf >= 0) {
string = string.substring("data:image/jpeg;base64,".length());
}
Decoder decoder2 = Base64.getDecoder();
byte[] decode = decoder2.decode(string);
ByteArrayInputStream bis = new ByteArrayInputStream(decode);
BufferedImage image = ImageIO.read(bis);
Paste.setClipboardImage(image);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
快速转换实现
注册快捷键到全局热键
private void initWindow() {
// 主类是Provider,获取当前平台(操作系统)的提供者
// Provider provider = Provider.getCurrentProvider(useSwingEventQueue);
Provider provider = Provider.getCurrentProvider(true);
// 转换图片和base64编码 image
provider.register(KeyStroke.getKeyStroke("control alt I"), new HotKeyListener() {
@Override
public void onHotKey(HotKey arg0) {
try {
Thread.sleep(300); // 参数为毫秒,所以需要将0.3转换成对应的毫秒值
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
BufferedImage imageFromClipboard = Paste.getImageFromClipboard();
// 从粘贴板中取得对象,如果为空则判断复制了文本
if (imageFromClipboard == null) {
String trim = Paste.getSysClipboardText().trim();
// 如果长度过短,则判断是复制了文件路径
if (trim.length() < 100) {
toBase64(trim);
} else {
toImages(trim);
}
} else {
toBase64(imageFromClipboard);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
粘贴板操作
/**
* 3. 从剪切板获得图片。
*/
public static BufferedImage getImageFromClipboard() throws Exception {
Clipboard sysc = Toolkit.getDefaultToolkit().getSystemClipboard();
Transferable cc = sysc.getContents(null);
if (cc == null)
return null;
else if (cc.isDataFlavorSupported(DataFlavor.imageFlavor)) {
return (BufferedImage) cc.getTransferData(DataFlavor.imageFlavor);
}
return null;
}
/**
* 4.复制图片到剪切板。
*/
public static void setClipboardImage(final BufferedImage image) throws Exception {
Transferable trans = new Transferable() {
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[] { DataFlavor.imageFlavor };
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
return DataFlavor.imageFlavor.equals(flavor);
}
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
if (isDataFlavorSupported(flavor))
return image;
throw new UnsupportedFlavorException(flavor);
}
};
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(trans, null);
}
效果
剪切板中存在图片或者base64字符串 ctrl + alt + I,即可转换,并存入剪切板
支持windows/linux/mac
参考
开发-示例集合-Java-系统快捷键
开发-示例集合-Java-系统粘贴板
TODO
可以进一步优化转换性能,和压缩效率.由于转换后的文本基本>100kb,写入剪切板时会导致卡顿.