Merge branch 'master' of http://47.93.189.255:8099/r/zhangshi_app_backend
| | |
| | | import com.ruoyi.common.annotation.Anonymous; |
| | | import com.ruoyi.common.utils.RenamedMultipartFile; |
| | | import com.ruoyi.common.utils.uuid.UUID; |
| | | import com.ruoyi.domain.MediaCompressRequest; |
| | | import com.ruoyi.service.DownLoadFileService; |
| | | import com.ruoyi.service.impl.VideoProcessService; |
| | | import lombok.Data; |
| | |
| | | |
| | | /** |
| | | * 压缩图片或提取视频封面并返回Base64 |
| | | * |
| | | * @param file 图片或视频文件 |
| | | * @param width 目标宽度,默认100 |
| | | * @param height 目标高度,默认100 |
| | | * @param quality 图片质量 0.1-1.0,默认0.8 |
| | | * @param mediaCompressRequest |
| | | * 包括 |
| | | * file 图片或视频文件 |
| | | * width 目标宽度,默认100 |
| | | * height 目标高度,默认100 |
| | | * quality 图片质量 0.1-1.0,默认0.8 |
| | | * @return Map包含压缩结果和Base64 |
| | | */ |
| | | @Anonymous |
| | | @PostMapping(value = "/images/zip", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) |
| | | public Map<String, Object> compressMediaToBase64( |
| | | @RequestParam(value = "file", required = false) MultipartFile file, |
| | | @RequestParam(value = "filePath", required = false) String filePath, |
| | | @RequestParam(value = "width", defaultValue = "0") int width, |
| | | @RequestParam(value = "height", defaultValue = "0") int height, |
| | | @RequestParam(value = "quality", defaultValue = "0.8") float quality) { |
| | | @PostMapping(value = "/images/zip") |
| | | public Map<String, Object> compressMediaToBase64(@RequestBody MediaCompressRequest mediaCompressRequest) { |
| | | Map<String, Object> result = new HashMap<>(); |
| | | |
| | | if (mediaCompressRequest == null && mediaCompressRequest.getFilePath() == null){ |
| | | result.put("success", false); |
| | | result.put("message", "文件不能为空"); |
| | | return result; |
| | | } |
| | | |
| | | String filePath = mediaCompressRequest.getFilePath(); |
| | | int width = mediaCompressRequest.getWidth(); |
| | | int height = mediaCompressRequest.getHeight(); |
| | | float quality = mediaCompressRequest.getQuality(); |
| | | |
| | | System.out.println("--------------"+mediaCompressRequest); |
| | | |
| | | File trueFile; |
| | | boolean deleteY = true; |
| | | |
| | | try { |
| | | // 验证文件 |
| | | if ((file == null || file.isEmpty()) && filePath == null ) { |
| | | result.put("success", false); |
| | | result.put("message", "文件不能为空"); |
| | | return result; |
| | | } |
| | | String fileUel = RuoYiConfig.getProfile() + filePath.replace("/profile","").replace("profile",""); |
| | | trueFile = new File(fileUel); |
| | | |
| | | if ((file == null || file.isEmpty())){ |
| | | deleteY = false; |
| | | String fileUel = RuoYiConfig.getProfile() + filePath.replace("/profile",""); |
| | | trueFile = new File(fileUel); |
| | | }else { |
| | | trueFile = videoProcessService.convertToFile(file); |
| | | } |
| | | |
| | | String fileName = trueFile.getName(); |
| | | if (fileName.isEmpty() && filePath == null) { |
| | | result.put("success", false); |
| | | result.put("message", "文件名不能为空"); |
| | | return result; |
| | | } |
| | | |
| | | System.out.println("-----------"+fileName); |
| | | |
| | |
| | | // 判断文件类型 |
| | | if (isImageFile(extension)) { |
| | | // 处理图片文件 |
| | | return videoProcessService.processImage(trueFile, width, height, quality, extension,deleteY); |
| | | return videoProcessService.processImage(trueFile, width, height, quality, extension); |
| | | } else if (isVideoFile(extension)) { |
| | | // 处理视频文件 |
| | | return videoProcessService.processVideo(trueFile,width,height,quality,extension,deleteY); |
| | | return videoProcessService.processVideo(trueFile,width,height,quality,extension); |
| | | } else { |
| | | result.put("success", false); |
| | | result.put("message", "不支持的文件格式:" + extension); |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 判断是否是图片文件 |
| | | */ |
| | |
| | | "localhost", |
| | | 8087, |
| | | |
| | | |
| | | |
| | | "http" |
| | | |
| | | ) |
| New file |
| | |
| | | package com.ruoyi.domain; |
| | | |
| | | import lombok.Data; |
| | | import org.springframework.web.bind.annotation.RequestParam; |
| | | |
| | | @Data |
| | | public class MediaCompressRequest { |
| | | |
| | | String filePath; |
| | | int width; |
| | | int height; |
| | | float quality; |
| | | } |
| | |
| | | * 处理图片文件 |
| | | */ |
| | | public Map<String, Object> processImage(File file, int width, int height, |
| | | float quality, String format,boolean deleteY) throws IOException { |
| | | float quality, String format) throws IOException { |
| | | Map<String, Object> result = new HashMap<>(); |
| | | |
| | | // 读取图片 |
| | |
| | | result.put("compressedHeight", height > 0 ? height : originalHeight); |
| | | result.put("base64", dataUrl); |
| | | result.put("message", "图片压缩成功"); |
| | | if (deleteY) { |
| | | file.delete(); |
| | | result.put("originalDeleted", false); |
| | | result.put("message", "图片压缩成功"); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | /** |
| | | * 压缩为PNG格式 |
| | | * 压缩为PNG格式(兼容性修复) |
| | | */ |
| | | private void compressAsPng(BufferedImage image, ByteArrayOutputStream output, int compressionLevel) |
| | | throws IOException { |
| | | Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("png"); |
| | | if (!writers.hasNext()) { |
| | | ImageIO.write(image, "png", output); |
| | | // 如果没有PNG编码器,使用默认方式 |
| | | boolean written = ImageIO.write(image, "png", output); |
| | | if (!written) { |
| | | throw new IOException("无法写入PNG格式"); |
| | | } |
| | | return; |
| | | } |
| | | |
| | | ImageWriter writer = writers.next(); |
| | | ImageWriteParam param = writer.getDefaultWriteParam(); |
| | | try { |
| | | ImageWriteParam param = writer.getDefaultWriteParam(); |
| | | |
| | | // PNG的压缩级别(0-9,0最快但压缩率低,9最慢但压缩率高) |
| | | if (compressionLevel >= 0) { |
| | | param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); |
| | | param.setCompressionType("Deflate"); |
| | | param.setCompressionQuality(Math.max(0.0f, Math.min(1.0f, compressionLevel / 9.0f))); |
| | | // PNG的压缩级别(0-9,0最快但压缩率低,9最慢但压缩率高) |
| | | if (compressionLevel >= 0) { |
| | | try { |
| | | // 先检查是否支持压缩模式 |
| | | if (param.canWriteCompressed()) { |
| | | param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); |
| | | // 检查是否支持Deflate压缩类型 |
| | | String[] compressionTypes = param.getCompressionTypes(); |
| | | if (compressionTypes != null) { |
| | | for (String type : compressionTypes) { |
| | | if ("Deflate".equalsIgnoreCase(type)) { |
| | | param.setCompressionType("Deflate"); |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | param.setCompressionQuality(Math.max(0.0f, Math.min(1.0f, compressionLevel / 9.0f))); |
| | | } else { |
| | | // 如果不支持压缩,使用默认设置 |
| | | log.debug("PNG编码器不支持压缩设置,使用默认压缩"); |
| | | } |
| | | } catch (UnsupportedOperationException e) { |
| | | // 捕获不支持的操作异常,继续使用默认设置 |
| | | log.warn("PNG压缩设置不被支持: {}", e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | writer.setOutput(new MemoryCacheImageOutputStream(output)); |
| | | writer.write(null, new IIOImage(image, null, null), param); |
| | | |
| | | } finally { |
| | | writer.dispose(); |
| | | } |
| | | |
| | | writer.setOutput(new MemoryCacheImageOutputStream(output)); |
| | | writer.write(null, new IIOImage(image, null, null), param); |
| | | writer.dispose(); |
| | | } |
| | | |
| | | |
| | |
| | | * 处理视频文件:生成Base64编码的封面 (使用JavaCV) |
| | | */ |
| | | public Map<String, Object> processVideo(File file, int width, int height, |
| | | float quality, String format, boolean deleteY) { |
| | | float quality, String format) { |
| | | Map<String, Object> result = new HashMap<>(); |
| | | |
| | | try { |
| | |
| | | log.error("视频封面生成失败", e); |
| | | result.put("success", false); |
| | | result.put("message", "封面生成失败: " + e.getMessage()); |
| | | } finally { |
| | | // 清理临时文件 |
| | | if (deleteY && file != null && file.exists()) { |
| | | try { |
| | | file.delete(); |
| | | } catch (Exception e) { |
| | | log.warn("删除临时视频文件时出错", e); |
| | | } |
| | | } |
| | | } |
| | | return result; |
| | | } |