图像透明处理
This commit is contained in:
@@ -299,7 +299,7 @@ public class ImageModelServiceImpl extends ServiceImpl<ImageModelMapper, ImageMo
|
||||
* 上传图片素材
|
||||
*
|
||||
* 实现图片素材上传的完整业务逻辑,包括:
|
||||
* 1. 文件验证和格式检查
|
||||
* 1. 文件验证和格式检查(根据阿里云参数要求)
|
||||
* 2. 上传到MinIO存储
|
||||
* 3. 生成永久URL和临时URL
|
||||
* 4. 保存上传记录到数据库
|
||||
@@ -307,17 +307,18 @@ public class ImageModelServiceImpl extends ServiceImpl<ImageModelMapper, ImageMo
|
||||
* @param file 上传的图片文件
|
||||
* @param ownerName 所属人姓名
|
||||
* @param ownerPhone 所属人电话
|
||||
* @param imageType 图片类型
|
||||
* @param imageType 图片类型(base_image主体图像 或 ref_image引导图像)
|
||||
* @param imageName 图像名称
|
||||
* @return 图像模型记录,包含上传结果和URL信息
|
||||
*/
|
||||
@Override
|
||||
public ImageModel uploadImageMaterial(MultipartFile file, String ownerName, String ownerPhone, String imageType,String imageName) {
|
||||
public ImageModel uploadImageMaterial(MultipartFile file, String ownerName, String ownerPhone, String imageType, String imageName) {
|
||||
try {
|
||||
log.info("开始上传图片素材,文件名:{},所属人:{},电话:{}",
|
||||
file.getOriginalFilename(), ownerName, ownerPhone);
|
||||
log.info("开始上传图片素材,文件名:{},所属人:{},电话:{},图像类型:{}",
|
||||
file.getOriginalFilename(), ownerName, ownerPhone, imageType);
|
||||
|
||||
// 1. 文件验证
|
||||
validateImageFile(file);
|
||||
// 1. 文件验证(根据阿里云参数要求)
|
||||
validateImageFile(file, imageType);
|
||||
|
||||
// 2. 生成唯一文件名
|
||||
String originalFilename = file.getOriginalFilename();
|
||||
@@ -340,9 +341,10 @@ public class ImageModelServiceImpl extends ServiceImpl<ImageModelMapper, ImageMo
|
||||
imageModel.setCreateTime(LocalDateTime.now());
|
||||
imageModel.setUpdateTime(LocalDateTime.now());
|
||||
|
||||
if ( imageName!=null && !imageName.trim().isEmpty()){
|
||||
if (imageName != null && !imageName.trim().isEmpty()) {
|
||||
imageModel.setImageName(imageName);
|
||||
}
|
||||
|
||||
// 5. 保存到数据库
|
||||
boolean saveResult = this.saveImageModel(imageModel);
|
||||
if (!saveResult) {
|
||||
@@ -368,14 +370,265 @@ public class ImageModelServiceImpl extends ServiceImpl<ImageModelMapper, ImageMo
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证图片文件
|
||||
* 上传引导图像
|
||||
*
|
||||
* 检查文件格式、大小等是否符合要求
|
||||
* 专门用于上传引导图像的方法,自动转换为带透明背景的RGBA四通道图像
|
||||
* 如果上传的图像不是RGBA格式,系统会自动转换为RGBA格式
|
||||
*
|
||||
* @param file 上传的引导图像文件
|
||||
* @param ownerName 所属人姓名
|
||||
* @param ownerPhone 所属人电话
|
||||
* @param imageName 图像名称
|
||||
* @return 图像模型记录,包含上传结果和URL信息
|
||||
*/
|
||||
@Override
|
||||
public ImageModel uploadRefImage(MultipartFile file, String ownerName, String ownerPhone, String imageName) {
|
||||
try {
|
||||
log.info("开始上传引导图像,文件名:{},所属人:{},电话:{}",
|
||||
file.getOriginalFilename(), ownerName, ownerPhone);
|
||||
|
||||
// 1. 基础文件验证(不限制格式,因为会自动转换)
|
||||
validateBasicImageFile(file);
|
||||
|
||||
// 2. 转换为RGBA格式
|
||||
log.info("开始转换图像为RGBA格式");
|
||||
byte[] rgbaImageBytes = convertToRGBA(file);
|
||||
log.info("图像转换完成,RGBA格式大小: {} bytes", rgbaImageBytes.length);
|
||||
|
||||
// 3. 生成唯一文件名(固定为PNG格式)
|
||||
String uniqueFileName = generateUniqueFileName("png");
|
||||
|
||||
// 4. 上传转换后的RGBA图像到MinIO
|
||||
log.info("开始上传转换后的RGBA图像到MinIO,文件名:{}", uniqueFileName);
|
||||
String materialUrl = minIOService.uploadFile(rgbaImageBytes, uniqueFileName, "image/png");
|
||||
String materialTempUrl = minIOService.generateTempUrl(uniqueFileName);
|
||||
|
||||
// 5. 构建图像模型记录
|
||||
ImageModel imageModel = new ImageModel();
|
||||
imageModel.setImageName(file.getOriginalFilename());
|
||||
imageModel.setOwnerName(ownerName);
|
||||
imageModel.setOwnerPhone(ownerPhone);
|
||||
imageModel.setImageType("ref_image"); // 设置为引导图像类型
|
||||
imageModel.setMaterialUrl(materialUrl);
|
||||
imageModel.setMaterialTempUrl(materialTempUrl);
|
||||
imageModel.setCreateTime(LocalDateTime.now());
|
||||
imageModel.setUpdateTime(LocalDateTime.now());
|
||||
|
||||
if (imageName != null && !imageName.trim().isEmpty()) {
|
||||
imageModel.setImageName(imageName);
|
||||
}
|
||||
|
||||
// 6. 保存到数据库
|
||||
boolean saveResult = this.saveImageModel(imageModel);
|
||||
if (!saveResult) {
|
||||
log.error("保存引导图像上传记录失败");
|
||||
throw new RuntimeException("保存引导图像上传记录失败");
|
||||
}
|
||||
|
||||
log.info("引导图像上传成功,已转换为RGBA格式,ID: {},永久URL: {},临时URL: {}",
|
||||
imageModel.getUuid(), materialUrl, materialTempUrl);
|
||||
|
||||
return imageModel;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("上传引导图像异常", e);
|
||||
throw new RuntimeException("上传引导图像失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 图像处理(支持主体图像和引导图像)
|
||||
*
|
||||
* 根据阿里云图像参数要求进行图像处理:
|
||||
* - base_image_url: 主体图像URL(必选,PNG格式,RGBA四通道,长边不超过2048像素)
|
||||
* - ref_image_url: 引导图像URL(可选,PNG格式,RGBA四通道,长边不超过2048像素)
|
||||
*
|
||||
* @param baseImageModel 主体图像模型记录
|
||||
* @param refImageModel 引导图像模型记录(可选)
|
||||
* @param prompt 处理提示词
|
||||
* @param functionName 功能名称
|
||||
* @return 处理后的图像模型记录
|
||||
*/
|
||||
@Override
|
||||
public ImageModel processImageWithRef(ImageModel baseImageModel, ImageModel refImageModel,
|
||||
String prompt, String functionName) {
|
||||
try {
|
||||
log.info("开始图像处理,主体图像ID: {},引导图像ID: {},提示词: {},功能: {}",
|
||||
baseImageModel.getUuid(),
|
||||
refImageModel != null ? refImageModel.getUuid() : "无",
|
||||
prompt, functionName);
|
||||
|
||||
// 1. 验证主体图像
|
||||
if (baseImageModel.getMaterialTempUrl() == null || baseImageModel.getMaterialTempUrl().trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("主体图像URL不能为空");
|
||||
}
|
||||
|
||||
String baseImageUrl = baseImageModel.getMaterialTempUrl().trim();
|
||||
if (!isPublicAccessibleUrl(baseImageUrl)) {
|
||||
throw new IllegalArgumentException("主体图像URL必须是公网可访问的地址");
|
||||
}
|
||||
|
||||
// 2. 验证引导图像(如果提供)
|
||||
String refImageUrl = null;
|
||||
if (refImageModel != null && refImageModel.getMaterialTempUrl() != null &&
|
||||
!refImageModel.getMaterialTempUrl().trim().isEmpty()) {
|
||||
refImageUrl = refImageModel.getMaterialTempUrl().trim();
|
||||
if (!isPublicAccessibleUrl(refImageUrl)) {
|
||||
throw new IllegalArgumentException("引导图像URL必须是公网可访问的地址");
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 设置处理参数
|
||||
baseImageModel.setPrompt(prompt);
|
||||
baseImageModel.setModelName("wanx2.1-imageedit");
|
||||
baseImageModel.setFunctionName(functionName);
|
||||
|
||||
// 4. 调用阿里云AI模型
|
||||
log.info("调用阿里云AI模型进行图像处理,主体图像URL: {},引导图像URL: {}",
|
||||
baseImageUrl, refImageUrl);
|
||||
|
||||
String apiKey = System.getenv("DASHSCOPE_API_KEY");
|
||||
Map<String, Object> parameters = new HashMap<>();
|
||||
parameters.put("prompt_extend", true);
|
||||
|
||||
ImageSynthesisParam param = ImageSynthesisParam.builder()
|
||||
.apiKey(apiKey)
|
||||
.model(baseImageModel.getModelName())
|
||||
.function(baseImageModel.getFunctionName())
|
||||
.prompt(baseImageModel.getPrompt())
|
||||
.baseImageUrl(baseImageUrl)
|
||||
.n(1)
|
||||
.size("1024*1024")
|
||||
.parameters(parameters)
|
||||
.build();
|
||||
|
||||
ImageSynthesis imageSynthesis = new ImageSynthesis();
|
||||
ImageSynthesisResult result = null;
|
||||
try {
|
||||
log.info("开始同步调用阿里云AI模型,参数: {}", param);
|
||||
result = imageSynthesis.call(param);
|
||||
log.info("AI模型调用完成,结果: {}", JsonUtils.toJson(result));
|
||||
|
||||
// 处理结果
|
||||
if (result != null && result.getOutput() != null && !result.getOutput().getResults().isEmpty()) {
|
||||
String resultImageUrl = result.getOutput().getResults().get(0).get("url");
|
||||
if (resultImageUrl != null && !resultImageUrl.trim().isEmpty()) {
|
||||
log.info("开始下载AI处理结果图片: {}", resultImageUrl);
|
||||
|
||||
try {
|
||||
// 下载图片到字节数组
|
||||
byte[] imageBytes = downloadImageToBytes(resultImageUrl);
|
||||
log.info("图片下载成功,大小: {} bytes", imageBytes.length);
|
||||
|
||||
// 生成唯一文件名
|
||||
String resultFileName = generateUniqueFileName("jpg");
|
||||
|
||||
// 上传到MinIO
|
||||
String resultImageMinIOUrl = minIOService.uploadFile(imageBytes, resultFileName, "image/jpeg");
|
||||
log.info("图片上传到MinIO成功: {}", resultImageMinIOUrl);
|
||||
|
||||
// 生成7天临时访问链接
|
||||
String resultImageTempUrl = minIOService.generateTempUrl(resultFileName);
|
||||
log.info("生成7天临时访问链接: {}", resultImageTempUrl);
|
||||
|
||||
// 更新ImageModel对象
|
||||
baseImageModel.setResultImageUrl(resultImageMinIOUrl);
|
||||
baseImageModel.setResultImageTempUrl(resultImageTempUrl);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("下载或上传AI处理结果图片失败", e);
|
||||
throw new RuntimeException("处理结果图片失败: " + e.getMessage(), e);
|
||||
}
|
||||
} else {
|
||||
log.warn("AI处理结果中没有有效的图片URL");
|
||||
}
|
||||
} else {
|
||||
log.warn("AI处理结果为空或无效");
|
||||
}
|
||||
|
||||
} catch (ApiException | NoApiKeyException e) {
|
||||
log.error("阿里云API调用失败", e);
|
||||
throw new RuntimeException("AI模型调用失败: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
// 5. 保存处理记录
|
||||
boolean saveResult = this.updateById(baseImageModel);
|
||||
if (!saveResult) {
|
||||
log.error("保存图像处理记录失败");
|
||||
throw new RuntimeException("保存图像处理记录失败");
|
||||
}
|
||||
|
||||
log.info("图像处理完成,ID: {},结果URL: {}",
|
||||
baseImageModel.getUuid(), baseImageModel.getResultImageTempUrl());
|
||||
|
||||
return baseImageModel;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("图像处理异常", e);
|
||||
throw new RuntimeException("图像处理失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 基础文件验证
|
||||
*
|
||||
* 验证文件的基本要求,不限制格式(用于引导图像自动转换)
|
||||
*
|
||||
* @param file 上传的文件
|
||||
* @throws IllegalArgumentException 文件不符合要求时抛出异常
|
||||
*/
|
||||
private void validateImageFile(MultipartFile file) {
|
||||
private void validateBasicImageFile(MultipartFile file) {
|
||||
if (file == null || file.isEmpty()) {
|
||||
throw new IllegalArgumentException("上传文件不能为空");
|
||||
}
|
||||
|
||||
// 检查文件大小(限制为10MB)
|
||||
long maxSize = 10 * 1024 * 1024; // 10MB
|
||||
if (file.getSize() > maxSize) {
|
||||
throw new IllegalArgumentException("文件大小不能超过10MB");
|
||||
}
|
||||
|
||||
// 检查文件格式
|
||||
String contentType = file.getContentType();
|
||||
if (contentType == null || !contentType.startsWith("image/")) {
|
||||
throw new IllegalArgumentException("只能上传图片文件");
|
||||
}
|
||||
|
||||
// 检查文件扩展名
|
||||
String originalFilename = file.getOriginalFilename();
|
||||
if (originalFilename == null || originalFilename.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("文件名不能为空");
|
||||
}
|
||||
|
||||
// 支持常见图像格式
|
||||
String extension = getFileExtension(originalFilename).toLowerCase();
|
||||
String[] allowedExtensions = {"jpg", "jpeg", "png", "gif", "bmp", "webp"};
|
||||
boolean isValidExtension = false;
|
||||
for (String allowedExt : allowedExtensions) {
|
||||
if (extension.equals(allowedExt)) {
|
||||
isValidExtension = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isValidExtension) {
|
||||
throw new IllegalArgumentException("不支持的图片格式,支持的格式:jpg, jpeg, png, gif, bmp, webp");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证图片文件
|
||||
*
|
||||
* 根据阿里云图像参数要求进行验证:
|
||||
* - 主体图像必须为PNG格式,带透明背景的RGBA四通道图像
|
||||
* - 引导图像必须为PNG格式,带透明背景的RGBA四通道图像
|
||||
* - 图像长边不超过2048像素
|
||||
*
|
||||
* @param file 上传的文件
|
||||
* @param imageType 图像类型(base_image主体图像 或 ref_image引导图像)
|
||||
* @throws IllegalArgumentException 文件不符合要求时抛出异常
|
||||
*/
|
||||
private void validateImageFile(MultipartFile file, String imageType) {
|
||||
if (file == null || file.isEmpty()) {
|
||||
throw new IllegalArgumentException("上传文件不能为空");
|
||||
}
|
||||
@@ -399,17 +652,71 @@ public class ImageModelServiceImpl extends ServiceImpl<ImageModelMapper, ImageMo
|
||||
}
|
||||
|
||||
String extension = getFileExtension(originalFilename).toLowerCase();
|
||||
String[] allowedExtensions = {"jpg", "jpeg", "png", "gif", "bmp", "webp"};
|
||||
boolean isValidExtension = false;
|
||||
for (String allowedExt : allowedExtensions) {
|
||||
if (extension.equals(allowedExt)) {
|
||||
isValidExtension = true;
|
||||
break;
|
||||
|
||||
// 根据图像类型进行不同的验证
|
||||
if ("base_image".equals(imageType)) {
|
||||
// 主体图像必须是PNG格式
|
||||
if (!"png".equals(extension)) {
|
||||
throw new IllegalArgumentException("主体图像必须是PNG格式,且为带透明背景的RGBA四通道图像");
|
||||
}
|
||||
|
||||
// 验证图像尺寸(长边不超过2048像素)
|
||||
validateImageDimensions(file);
|
||||
|
||||
} else if ("ref_image".equals(imageType)) {
|
||||
// 引导图像必须是PNG格式,带透明背景的RGBA四通道图像
|
||||
if (!"png".equals(extension)) {
|
||||
throw new IllegalArgumentException("引导图像必须是PNG格式,且为带透明背景的RGBA四通道图像");
|
||||
}
|
||||
|
||||
// 验证图像尺寸(长边不超过2048像素)
|
||||
validateImageDimensions(file);
|
||||
} else {
|
||||
// 默认验证(兼容原有逻辑)
|
||||
String[] allowedExtensions = {"jpg", "jpeg", "png", "gif", "bmp", "webp"};
|
||||
boolean isValidExtension = false;
|
||||
for (String allowedExt : allowedExtensions) {
|
||||
if (extension.equals(allowedExt)) {
|
||||
isValidExtension = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isValidExtension) {
|
||||
throw new IllegalArgumentException("不支持的图片格式,支持的格式:jpg, jpeg, png, gif, bmp, webp");
|
||||
}
|
||||
}
|
||||
|
||||
if (!isValidExtension) {
|
||||
throw new IllegalArgumentException("不支持的图片格式,支持的格式:jpg, jpeg, png, gif, bmp, webp");
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证图像尺寸
|
||||
*
|
||||
* 检查图像长边是否超过2048像素
|
||||
*
|
||||
* @param file 上传的文件
|
||||
* @throws IllegalArgumentException 图像尺寸不符合要求时抛出异常
|
||||
*/
|
||||
private void validateImageDimensions(MultipartFile file) {
|
||||
try {
|
||||
// 使用BufferedImage读取图像尺寸
|
||||
java.awt.image.BufferedImage image = javax.imageio.ImageIO.read(file.getInputStream());
|
||||
if (image == null) {
|
||||
throw new IllegalArgumentException("无法读取图像文件");
|
||||
}
|
||||
|
||||
int width = image.getWidth();
|
||||
int height = image.getHeight();
|
||||
int maxDimension = Math.max(width, height);
|
||||
|
||||
if (maxDimension > 2048) {
|
||||
throw new IllegalArgumentException("图像长边不能超过2048像素,当前尺寸:" + width + "x" + height);
|
||||
}
|
||||
|
||||
log.info("图像尺寸验证通过:{}x{}", width, height);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("验证图像尺寸失败", e);
|
||||
throw new IllegalArgumentException("验证图像尺寸失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -440,6 +747,113 @@ public class ImageModelServiceImpl extends ServiceImpl<ImageModelMapper, ImageMo
|
||||
return timestamp + "_" + uuid + "." + extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证URL是否为公网可访问的地址
|
||||
*
|
||||
* 检查URL是否符合阿里云图像参数要求:
|
||||
* - 必须是HTTP或HTTPS协议
|
||||
* - 必须是公网可访问的地址
|
||||
*
|
||||
* @param url 要验证的URL
|
||||
* @return 是否为公网可访问的URL
|
||||
*/
|
||||
private boolean isPublicAccessibleUrl(String url) {
|
||||
if (url == null || url.trim().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// 检查协议
|
||||
if (!url.startsWith("http://") && !url.startsWith("https://")) {
|
||||
log.warn("URL协议不支持,必须是HTTP或HTTPS: {}", url);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否为内网地址(简单检查)
|
||||
if (url.contains("localhost") || url.contains("127.0.0.1") ||
|
||||
url.contains("192.168.") || url.contains("10.") || url.contains("172.")) {
|
||||
log.warn("URL为内网地址,不是公网可访问: {}", url);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 尝试访问URL验证可访问性
|
||||
URL urlObj = new URL(url);
|
||||
try (InputStream inputStream = urlObj.openStream()) {
|
||||
// 如果能打开流,说明URL可访问
|
||||
log.info("URL验证通过,可公网访问: {}", url);
|
||||
return true;
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.warn("URL验证失败,无法公网访问: {},错误: {}", url, e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将图像转换为RGBA格式
|
||||
*
|
||||
* 将任意格式的图像转换为带透明背景的RGBA四通道PNG格式
|
||||
*
|
||||
* @param file 原始图像文件
|
||||
* @return RGBA格式的图像字节数组
|
||||
* @throws IOException 转换失败时抛出异常
|
||||
*/
|
||||
private byte[] convertToRGBA(MultipartFile file) throws IOException {
|
||||
try {
|
||||
log.info("开始转换图像为RGBA格式,原始文件: {}", file.getOriginalFilename());
|
||||
|
||||
// 读取原始图像
|
||||
java.awt.image.BufferedImage originalImage = javax.imageio.ImageIO.read(file.getInputStream());
|
||||
if (originalImage == null) {
|
||||
throw new IllegalArgumentException("无法读取图像文件");
|
||||
}
|
||||
|
||||
int width = originalImage.getWidth();
|
||||
int height = originalImage.getHeight();
|
||||
|
||||
// 验证图像尺寸
|
||||
int maxDimension = Math.max(width, height);
|
||||
if (maxDimension > 2048) {
|
||||
throw new IllegalArgumentException("图像长边不能超过2048像素,当前尺寸:" + width + "x" + height);
|
||||
}
|
||||
|
||||
log.info("原始图像尺寸: {}x{}", width, height);
|
||||
|
||||
// 创建RGBA格式的图像
|
||||
java.awt.image.BufferedImage rgbaImage = new java.awt.image.BufferedImage(
|
||||
width, height, java.awt.image.BufferedImage.TYPE_INT_ARGB);
|
||||
|
||||
// 获取图形上下文
|
||||
java.awt.Graphics2D g2d = rgbaImage.createGraphics();
|
||||
|
||||
// 设置渲染提示以获得更好的质量
|
||||
g2d.setRenderingHint(java.awt.RenderingHints.KEY_INTERPOLATION,
|
||||
java.awt.RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
g2d.setRenderingHint(java.awt.RenderingHints.KEY_RENDERING,
|
||||
java.awt.RenderingHints.VALUE_RENDER_QUALITY);
|
||||
g2d.setRenderingHint(java.awt.RenderingHints.KEY_ANTIALIASING,
|
||||
java.awt.RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
|
||||
// 绘制原始图像到RGBA图像上
|
||||
g2d.drawImage(originalImage, 0, 0, null);
|
||||
g2d.dispose();
|
||||
|
||||
// 将RGBA图像转换为字节数组
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
javax.imageio.ImageIO.write(rgbaImage, "PNG", baos);
|
||||
byte[] rgbaBytes = baos.toByteArray();
|
||||
|
||||
log.info("图像转换完成,RGBA格式大小: {} bytes", rgbaBytes.length);
|
||||
|
||||
return rgbaBytes;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("转换图像为RGBA格式失败", e);
|
||||
throw new IOException("转换图像为RGBA格式失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载图片到字节数组
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user