前言
手游上架各大游戏应用商店(渠道)时候,很多渠道对游戏icon有要求, 需要加上渠道提供的角标才能正常上架,最开始的时候需要让美术去完成游戏icon和游戏角标合成工作, 客户端需要将美工合成后的图片复制到对应路径,多个游戏多个渠道都要来一遍,想想这个工作量就酸爽。合成图片这个工作太依赖美术 重复复制合成后的图片到对应路径 浪费大量的人力和时间成本。懒是第一生产力,反复重复的工作能用代码 解决绝不手动复制。
实现效果和说明
- 合成图片首先要有2张图片,放一个512 * 512游戏图标的ICON。注意一定要是
。另需要一个512 * 512带渠道角标的图片(一般渠道都会提供)
icon.png - 用代码方式进行2张图片合成,合成后效果如下图app_icon.png
代码逻辑
-
用java.awt.Graphics2D 类 进行2张图片合成,建议游戏icon和渠道角标放在同一个路径下,合成后的icon放到另一个路径下。
-
文件复制用到 FileUtils.copyFile()需要下载对应jar如有需要私信我。
-
app_icon这个命名是获取AndroidMainfest.xml中application节点中配置的图标名称
例如android:icon=@drawable/app_icon ,@drawable对应着res下的
"drawable-hdpi","drawable-ldpi", "drawable-mdpi",
"drawable-xhdpi","drawable-xxhdpi", "drawable-xxxhdpi"。 -
android:icon=@mipmap/app_icon,@mipmap对应着 "mipmap-hdpi",
"mipmap-mdpi","mipmap-xhdpi","mipmap-xxhdpi","mipmap-xxxhdpi"
"mipmap-xxxhdpi-v4","mipmap-xxhdpi-v4","mipmap-xhdpi-v4","
mipmap-mdpi-v4", "mipmap-ldpi-v4","mipmap-hdpi-v4" 文件夹,
合成后的icon需要复制到res/路径下替换。 -
Java版本是打包工具合成icon功能中拆分出来的部分代码,有需要可以在这个基础上做下代码调整。python 版只是简单实现并没有处理多余的逻辑。
代码实现(java版本)
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import javax.imageio.ImageIO;
import org.apache.commons.io.FileUtils;
/**
*JDK1.8
* @author sjr 2020-6-30
*/
public class ChannelMergeImg {
/**
* 写入指定路径
*/
private static void writeImageToLocal(String marketIconPath,BufferedImage mergeImage) throws IOException {
if (marketIconPath == "" || marketIconPath == null) {
return;
}
if (mergeImage == null) {
return;
}
ImageIO.write(mergeImage, "png", new File(marketIconPath));
}
private static BufferedImage getImageFromLocal(String path) throws IOException {
return ImageIO.read(new File(path));
}
/**
* @param gameIconPath 游戏icon路径
* @param marketIconPath 渠道角标路径
* @param mergeIconPath 合成后的角标路径
*/
public static void saveMergeImage(String gameIconPath, String marketIconPath,String mergeIconPath) {
System.out.println("图片开始合成");
try {
writeImageToLocal(mergeIconPath,mergeImage(getImageFromLocal(gameIconPath),getImageFromLocal(marketIconPath)));
System.out.println("图片合成结束");
} catch (IOException e) {
System.out.println("图片合成异常");
e.printStackTrace();
}
}
/**
* 合并图片核心代码
*/
private static BufferedImage mergeImage(BufferedImage gameIconPath,BufferedImage marketIconPath) {
if (gameIconPath != null && marketIconPath != null) {
Graphics2D graphics2D = marketIconPath.createGraphics();
graphics2D.drawImage(gameIconPath, 0, 0, 512, 512, null);
graphics2D.dispose();
}
return marketIconPath;
}
public static List<String> getIconOutPutListDir(String outPutDir) {
String[] dirList = new String[] {"drawable-hdpi",
"drawable-ldpi", "drawable-mdpi", "drawable-xhdpi",
"drawable-xxhdpi", "drawable-xxxhdpi", "mipmap-hdpi",
"mipmap-mdpi", "mipmap-xhdpi", "mipmap-xxhdpi",
"mipmap-xxxhdpi", "mipmap-xxxhdpi-v4", "mipmap-xxhdpi-v4",
"mipmap-xhdpi-v4", "mipmap-mdpi-v4", "mipmap-ldpi-v4",
"mipmap-hdpi-v4" };
return Arrays.stream(dirList).map(
dir -> outPutDir + dir)
.collect(Collectors.toList());
}
/**
* 替换普通图标为带角标图片
* @throws Exception
*/
public static void replaceGameIcon(String outPutDir ,String marketMargeIconPath) throws Exception {
getIconOutPutListDir(outPutDir).stream().forEach(
dir -> {
if (!new File(outPutDir).exists()) { //如果文件不存在 return
return;
}
try {
FileUtils.copyFile(new File(marketMargeIconPath), new File(dir+ File.separator + "app_icon.png"));
System.out.println("开始拷贝文件:"+dir+File.separator+"app_icon.png");
} catch (IOException e) {
e.printStackTrace();
}
});
System.out.println("拷贝图片结束");
}
public static void main(String[] args) {
String gameIconPath="C:\\Users\\Administrator\\Desktop\\master\\icon\\channelIcon\\common_icon.png";
String marketIconPath="C:\\Users\\Administrator\\Desktop\\master\\icon\\channelIcon\\icon_marker.png";
String mergeIconPath="C:\\Users\\Administrator\\Desktop\\master\\icon\\app_icon.png";
ChannelMergeImg.saveMergeImage(marketIconPath,gameIconPath, mergeIconPath);
String outPutDir="C:\\Users\\Administrator\\Desktop\\master\\output\\res\\";
try {
ChannelMergeImg.replaceGameIcon(outPutDir, mergeIconPath);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Python版icon合成(python2.7)
pip命令安装 pip install Pillow
Pillow使用方式详见: http://pillow.readthedocs.io/en/latest/reference/Image.html
# -*- coding: utf-8 -*-
from PIL import Image
'''
图片合成
'''
def mergePicture():
commonIcon= Image.open("C:/Users/Administrator/Desktop/common_icon.png")
markIcon = Image.open("C:/Users/Administrator/Desktop/icon_marker.png")
markLayer = Image.new('RGBA', commonIcon.size, (0, 0, 0, 0))
markLayer.paste(markIcon, (0, 0))
out = Image.composite(markLayer, commonIcon, markLayer)
out.save("C:/Users/Administrator/Desktop/app_icon.png", quality=95, subsampling=0)
print ('Merge picture Successful')
if __name__== '__main__':
mergePicture()
python2.7版本合成icon 参考借鉴了博客:http://www.uustory.com/?p=1778
结语:
写blog的目的很明确:记录下自己的学习和工作经验,分享给有需要的人。如果有那里写的不对或者不理解,欢迎大家的指正。
网友评论