精华内容
下载资源
问答
  • 前阵子,工作搞了一下Fastdfs与nginx进行压缩图片比率存储服务器中,今天应用下工作时间记录下.
  • 1.缩略图压缩文件jar包 <!-- 图片缩略图 --> <groupId>net.coobird</groupId> <artifactId>thumbnailator <version>0.4.8   2.thumbnailator的一些功能 1、指定大小进行缩放 [java] view plain...

     

     

    1.缩略图压缩文件jar包

    <!-- 图片缩略图 -->
                <dependency>
                    <groupId>net.coobird</groupId>
                    <artifactId>thumbnailator</artifactId>
                    <version>0.4.8</version>
                </dependency>

     

    2.thumbnailator的一些功能

    1、指定大小进行缩放
    
    [java] view plain copy
    //size(宽度, 高度)  
      
    /* 
     * 若图片横比200小,高比300小,不变 
     * 若图片横比200小,高比300大,高缩小到300,图片比例不变 
     * 若图片横比200大,高比300小,横缩小到200,图片比例不变 
     * 若图片横比200大,高比300大,图片按比例缩小,横为200或高为300 
     */  
    Thumbnails.of("images/a380_1280x1024.jpg")  
        .size(200, 300)  
        .toFile("c:/a380_200x300.jpg");  
      
    Thumbnails.of("images/a380_1280x1024.jpg")  
        .size(2560, 2048)  
        .toFile("c:/a380_2560x2048.jpg");  
    
    
    2、按照比例进行缩放
    
    [java] view plain copy
    //scale(比例)  
    Thumbnails.of("images/a380_1280x1024.jpg")  
        .scale(0.25f)  
        .toFile("c:/a380_25%.jpg");  
      
    Thumbnails.of("images/a380_1280x1024.jpg")  
        .scale(1.10f)  
        .toFile("c:/a380_110%.jpg");  
    
    
    3、不按照比例,指定大小进行缩放
    
    [java] view plain copy
    //keepAspectRatio(false)默认是按照比例缩放的  
    Thumbnails.of("images/a380_1280x1024.jpg")  
        .size(200,200)  
        .keepAspectRatio(false)  
        .toFile("c:/a380_200x200.jpg");  
    
    
    4、旋转
    
    [java] view plain copy
    //rotate(角度),正数:顺时针负数:逆时针  
    Thumbnails.of("images/a380_1280x1024.jpg")  
        .size(1280,1024)  
        .rotate(90)  
        .toFile("c:/a380_rotate+90.jpg");  
      
    Thumbnails.of("images/a380_1280x1024.jpg")  
        .size(1280,1024)  
        .rotate(-90)  
        .toFile("c:/a380_rotate-90.jpg");  
    
    
    5、水印
    
    [java] view plain copy
    //watermark(位置,水印图,透明度)  
    Thumbnails.of("images/a380_1280x1024.jpg")  
        .size(1280,1024)  
        .watermark(Positions.BOTTOM_RIGHT,ImageIO.read(newFile("images/watermark.png")),0.5f)  
        .outputQuality(0.8f)  
        .toFile("c:/a380_watermark_bottom_right.jpg");  
      
    Thumbnails.of("images/a380_1280x1024.jpg")  
        .size(1280,1024)  
        .watermark(Positions.CENTER,ImageIO.read(newFile("images/watermark.png")),0.5f)  
        .outputQuality(0.8f)  
        .toFile("c:/a380_watermark_center.jpg");  
    
    
    6、裁剪
    
    [java] view plain copy
    //sourceRegion()  
      
    //图片中心400*400的区域  
    Thumbnails.of("images/a380_1280x1024.jpg")  
        .sourceRegion(Positions.CENTER,400,400)  
        .size(200,200)  
        .keepAspectRatio(false)  
        .toFile("c:/a380_region_center.jpg");  
      
    //图片右下400*400的区域  
    Thumbnails.of("images/a380_1280x1024.jpg")  
        .sourceRegion(Positions.BOTTOM_RIGHT,400,400)  
        .size(200,200)  
        .keepAspectRatio(false)  
        .toFile("c:/a380_region_bootom_right.jpg");  
      
    //指定坐标  
    Thumbnails.of("images/a380_1280x1024.jpg")  
        .sourceRegion(600,500,400,400)  
        .size(200,200)  
        .keepAspectRatio(false)  
        .toFile("c:/a380_region_coord.jpg");  
    
    
    
    7、转化图像格式
    
    [java] view plain copy
    //outputFormat(图像格式)  
    Thumbnails.of("images/a380_1280x1024.jpg")  
        .size(1280,1024)  
        .outputFormat("png")  
        .toFile("c:/a380_1280x1024.png");  
      
    Thumbnails.of("images/a380_1280x1024.jpg")  
        .size(1280,1024)  
        .outputFormat("gif")  
        .toFile("c:/a380_1280x1024.gif");  
     
    
    8、输出到OutputStream
    
    [java] view plain copy
    //toOutputStream(流对象)  
    OutputStreamos=newFileOutputStream("c:/a380_1280x1024_OutputStream.png");  
    Thumbnails.of("images/a380_1280x1024.jpg")  
        .size(1280,1024)  
        .toOutputStream(os);  
     
    
     9、输出到BufferedImage
    
    [java] view plain copy
    //asBufferedImage()返回BufferedImage  
    BufferedImagethumbnail=Thumbnails.of("images/a380_1280x1024.jpg")  
        .size(1280,1024)  
        .asBufferedImage();  
    ImageIO.write(thumbnail,"jpg",newFile("c:/a380_1280x1024_BufferedImage.jpg"));  

     

    3.java代码实现

    private static Logger log = LoggerFactory.getLogger(ActivitySpringArticleController.class);
    	
    	@ApiOperation(value="图片上传接口")
    	@RequestMapping(value = "activity/uploadActivitySpringFile")
    	@ResponseBody
    	public String uploadActivitySpringFile(HttpServletRequest request) {
    		MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
    	    MultipartFile imageFile = multipartRequest.getFile("upfile");
    	    if(imageFile == null ){
    	    	throw new BusinessException(new ErrorCode("imageFile不能为空"));
            }
            
            if (imageFile.getSize() >= 10*1024*1024)
            {
            	throw new BusinessException(new ErrorCode("文件不能大于10M"));
            }
            String uuid = UUID.randomUUID().toString();
            
            String fileDirectory = DateUtil.date2String(new Date(), DateUtil.SIMPLE_DATE_FORMAT);
            
            //拼接后台文件名称
            String pathName = fileDirectory + File.separator + uuid + "."
                                + FilenameUtils.getExtension(imageFile.getOriginalFilename());
            //构建保存文件路劲
            //2016-5-6 yangkang 修改上传路径为服务器上 
          //  String realPath = request.getServletContext().getRealPath("uploadPath");
            String realPath = "D://test//";
            //获取服务器绝对路径 linux 服务器地址  获取当前使用的配置文件配置
            //String urlString=PropertiesUtil.getInstance().getSysPro("uploadPath");
            //拼接文件路劲
            String filePathName = realPath + File.separator + pathName;
            log.info("图片上传路径:"+filePathName);
            //判断文件保存是否存在
            File file = new File(filePathName);
            if (file.getParentFile() != null || !file.getParentFile().isDirectory()) {
                //创建文件
                file.getParentFile().mkdirs();
            }
            
            InputStream inputStream = null;
            FileOutputStream fileOutputStream = null;
            try {
                inputStream = imageFile.getInputStream();
                fileOutputStream = new FileOutputStream(file);
                //写出文件
                //2016-05-12 yangkang 改为增加缓存
    //            IOUtils.copy(inputStream, fileOutputStream);
                byte[] buffer = new byte[2048];
                IOUtils.copyLarge(inputStream, fileOutputStream, buffer);
                buffer = null;
    
            } catch (IOException e) {
                filePathName = null;
                throw new BusinessException(new ErrorCode("操作失败"));
            } finally {
                try {
                    if (inputStream != null) {
                        inputStream.close();
                    }
                    if (fileOutputStream != null) {
                        fileOutputStream.flush();
                        fileOutputStream.close();
                    }
                } catch (IOException e) {
                    filePathName = null;
                    throw new BusinessException(new ErrorCode("操作失败"));
                } 
             }
        
            
            //        String fileId = FastDFSClient.uploadFile(file, filePathName);
            
            /**
             * 缩略图begin
             */
            
            //拼接后台文件名称
            String thumbnailPathName = fileDirectory + File.separator + uuid + "small."
                                        + FilenameUtils.getExtension(imageFile.getOriginalFilename());
            //added by yangkang 2016-3-30 去掉后缀中包含的.png字符串 
            if(thumbnailPathName.contains(".png")){
                thumbnailPathName = thumbnailPathName.replace(".png", ".jpg");
            }
            long size = imageFile.getSize();
            double scale = 1.0d ;
            if(size >= 200*1024){
                if(size > 0){
                    scale = (200*1024f) / size  ;
                }
            }
            
            
            //拼接文件路劲
            String thumbnailFilePathName = realPath + File.separator + thumbnailPathName;
            try {
                //added by chenshun 2016-3-22 注释掉之前长宽的方式,改用大小
              //  Thumbnails.of(filePathName).size(11, 12).toFile(thumbnailFilePathName);
                if(size < 200*1024){
                    Thumbnails.of(filePathName).scale(1f).outputFormat("jpg").toFile(thumbnailFilePathName);
                }else{
                    Thumbnails.of(filePathName).scale(1f).outputQuality(scale).outputFormat("jpg").toFile(thumbnailFilePathName);
                }
                
            } catch (Exception e1) {
            	 throw new BusinessException(new ErrorCode("操作失败"));
            }
            /**
             * 缩略图end
             */
            
            Map<String, Object> map = new HashMap<String, Object>();
            //原图地址
            map.put("originalUrl", pathName);
            //缩略图地址
            map.put("thumbnailUrl", thumbnailPathName);
            return pathName+"---------"+thumbnailPathName;
            //throw new BusinessException(new ErrorCode("操作成功"));
        }

     

     

    4.配置文件,为上传至linux使用

    获取当前使用的配置文件信息 
    
      /**
         * 根据key从gzt.properties配置文件获取配置信息  
         * @param key 键值
         * @return
         */
        public String getSysPro(String key){
            return getSysPro(key, null);
        }
        /**
         * 根据key从gzt.properties配置文件获取配置信息  
         * @param key 键值
         * @param defaultValue 默认值
         * @return
         */
        public String getSysPro(String key,String defaultValue){
            return getValue("spring/imageserver-"+System.getProperty("spring.profiles.active")+".properties", key, defaultValue);
        }
    例:
    
            //获取服务器绝对路径 linux 服务器地址   
            String urlString=PropertiesUtil.getInstance().getSysPro("uploadPath");

     

    5.工具类

    package com.xyz.imageserver.common.properties;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.util.Properties;
    import java.util.concurrent.ConcurrentHashMap;
    
    /**
     * 
     * @ClassName PropertiesUtil.java 
     * @Description 系统配置工具类
     * @author caijy
     * @date 2015年6月9日 上午10:50:38
     * @version 1.0.0
     */
    public class PropertiesUtil {
        private Logger logger = LoggerFactory.getLogger(PropertiesUtil.class);
        private ConcurrentHashMap<String, Properties> proMap;
        private PropertiesUtil() {
            proMap = new ConcurrentHashMap<String, Properties>();
        }
        private static PropertiesUtil instance = new PropertiesUtil();
    
        /**
         * 获取单例对象
         * @return
         */
        public static PropertiesUtil getInstance()
        {
            return instance;
        }
       
        /**
         * 根据key从gzt.properties配置文件获取配置信息  
         * @param key 键值
         * @return
         */
        public String getSysPro(String key){
            return getSysPro(key, null);
        }
        /**
         * 根据key从gzt.properties配置文件获取配置信息  
         * @param key 键值
         * @param defaultValue 默认值
         * @return
         */
        public String getSysPro(String key,String defaultValue){
            return getValue("spring/imageserver-"+System.getProperty("spring.profiles.active")+".properties", key, defaultValue);
        }
        /**
         * 从配置文件中获取对应key值
         * @param fileName 配置文件名
         * @param key   key值
         * @param defaultValue 默认值
         * @return
         */
        public String getValue(String fileName,String key,String defaultValue){
            String val = null;
            Properties properties = proMap.get(fileName);
            if(properties == null){
                InputStream inputStream = PropertiesUtil.class.getClassLoader().getResourceAsStream(fileName);
                  try {
                     properties = new Properties();
                    properties.load(new InputStreamReader(inputStream,"UTF-8"));
                    proMap.put(fileName, properties);
                    val = properties.getProperty(key,defaultValue);
                } catch (IOException e) {
                    logger.error("getValue",e);
                }finally{
                    try {
                        if (inputStream != null) {                        
                            inputStream.close();
                        }
                    } catch (IOException e1) {
                        logger.error(e1.toString());
                    }
                }
            }else{
                val = properties.getProperty(key,defaultValue);
            }
            return val;
        }
    }

     

     6. 测试

     

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <title>Getting Started: Serving Web Content</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    </head>
    <body>
    <p>Get your greeting <a href="/greeting">here</a></p>
    <form action="activity/downloadActivitySpringFile" method="POST" enctype="multipart/form-data">
        文件:<input type="file" name="upfile"/>
        <input type="submit" />
    </form>
    <a href="activity/downloadActivitySpringFile">下载test</a>
    <p>多文件上传</p>
    <form method="POST" enctype="multipart/form-data" action="/batch/upload">
        <p>文件1:<input type="file" name="file" /></p>
        <p>文件2:<input type="file" name="file" /></p>
        <p><input type="submit" value="上传" /></p>
    </form>
    </body>
    </html>
    
    

     

    转载于:https://my.oschina.net/u/3788556/blog/1647364

    展开全文
  • 需求背景说明 最近后端管理项目中需要...我主要是提供了两种方式进行图片压缩,第一种是使用Java自带的Image绘制图像,输入指定的宽高尺寸,最后在重新绘制新的图片,核心代码也就三四行左右,压缩绘制算法都是JDK底...

    需求背景说明 最近后端管理项目中需要用到用户一些证件图片进行表单文件的上传 如果每个人的证件照片都非常大,对服务器资源将是一种浪费, 因为用户量也不是很大,所以也没对接第三方的OSS或者七牛云存储对象,就写个简单的图像压缩吧,我主要是提供了两种方式进行图片压缩,第一种是使用Java自带的Image绘制图像,输入指定的宽高尺寸,最后在重新绘制新的图片,核心代码也就三四行左右,压缩绘制算法都是JDK底层已经封装完成了,直接调用就行。
    第二种是使用Google的压缩工具类Thumbnails 大名鼎鼎的不一般,只需要一行代码即可,可实现的功能那是相当的丰富,图像指定宽高压缩,原图压缩,添加水印,图像旋转,指定图像压缩质量比例等等。前端调用使用ajax通过表单对象形式获取文件,并设置formData参数传给后端。

    先看一下ajax前端发送请求需要注意的事项,我没有直接使用html表单的形式,设置相应的表单属性来请求action操作,而是new 一个新的表单对象,然后获取标签属性上的元素 来封装成一个完整的对象如下:

    需要注意的是上传文件时候data类型必须是formdata类型,Content-Type类型为: multipart/form-data; boundary=OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp,boundary是请求参数之间的界限标识,服务器会通过他来做参数隔离与获取,这个Content-Type并不是我们自己设置的,而是jQuery默认设置的formdata的Content-Type,如果我们自己设置了Content-Type,jQuery会通过设置的把原来默认的覆盖掉(默认jQuery会把ContentType设置为application/x-www-form-urlencoded),这样服务器在获取传入的参数时候会报错 no multipart boundary was found,当时也是想不明白是咋回事,因为服务器无法获取到boundary就无法区分参数与文件,所以我们的解决办法是把contentType设置为false,并把processData也设置为false,让那个jQuery不去处理formdata,如果不做限制jQuery会把formData转换成String类型,真的是有无穷多的细节在里面。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>图片上传测试</title>
    </head>
    <body>
    <div class="auth_wrapper">
        <div class="picture picture1">
            <span><h1>文件上传测试</h1></span>
            <span></span>
        </div>
        <div class="auth_right">
            <label>
                <input id="file" type="file" name="file" accept="image/png, image/jpeg, image/jpg" style="left: -9999px; position: absolute;">
                <div class="btn btn-default" onclick="change()">点我上传文件!!!</div>
            </label>
            <text class="load_img1_tip hidden"></text>
        </div>
    </div>
    //  此处需要引入相关的jQuery.js文件可自己下载到本地也可CDN网址加载
    <script type="text/javascript" src="../image/common/jquery-1.9.1.min.js"></script>
    <script type="text/javascript" src="../image/common/jquery.actual.min.js"></script>
    <script type="text/javascript" src="../image/common/bootstrap.min.js"></script>
    <script type="text/javascript" src="../image/common/fileinput.min.js"></script>
    <script type="text/javascript" src="../image/common/zh.js"></script>
    <script>
        /**
         * 监听元素变化时候执行该方法 可以看出监听的元素是 <input>标签中的file元素 也可直接不用change方法 调用submit()方法 但是需要注意的是直接点击后调用该方法 当我们选择了
         * 图片后不再再次出发上传图片的接口
         */
        function change () {
            $("#file").change(function () {
                submit()
            });
        }
        //上传图片到服务器 ajax 请求调用图片上传和压缩
        function submit() {
            var formdata = new FormData();
            formdata.append('imageFile', $('#file')[0].files[0]);
            $.ajax({
                async: false,
                type: 'POST',
                url: "http://127.0.0.1:8001/file/upload",
                dataType: 'json',
                data: formdata,
                contentType: false, //ajax上传图片需要添加
                processData: false, //ajax上传图片需要添加
                success: function (data) {
                    alert(data.responseText)
                },
                error: function (data) {
                    alert(data.responseText)
                }
            })
        }
    </script>
    </body>
    </html>

    最终显示效果图:

    原图:4.5M

    压缩后图片:19K

    上传文件效果图和目录结构:

    上传完成:

    服务端代码:

    Controller层代码如下:

    import com.sunlands.feo.common.util.FileCompress;
    import io.swagger.annotations.ApiOperation;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.bind.annotation.PostMapping;
    
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.multipart.MultipartFile;
    
    /**
     * @author :冉野
     * @date :Created in 2019-07-11 13:27
     * @description:文件处理Controller
     * @modified By:
     * @version: 1.0.4$
     */
    @Slf4j
    @RestController
    @RequestMapping("/file")
    public class FileProcessController {
    
        @ApiOperation("图片上传")
        @PostMapping(value = "/upload")
        public String upload(@RequestParam(name = "imageFile") MultipartFile imageFile) {
    
            String filePath = FileCompress.thumbnail(imageFile, 0, 0, "");
            log.info("图片存储路径:[{}]",filePath);
            return filePath;
    
        }
    }

    Java原生JDK压缩方式和Google工具类压缩和上传的两种方式:
     

    package com.sunlands.feo.common.util;
    
    import lombok.extern.slf4j.Slf4j;
    import net.coobird.thumbnailator.Thumbnails;
    import org.springframework.web.multipart.MultipartFile;
    
    
    import javax.imageio.ImageIO;
    import java.awt.*;
    import java.awt.image.BufferedImage;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.util.UUID;
    
    
    /**
     * @author :冉野
     * @date :Created in 2019-07-12 09:29
     * @description:测试图片压缩 测试使用写博客用 需求背景说明 最近后端管理项目中需要用到用户一些证件图片进行表单文件的上传 如果每个人的证件照片都非常大,对服务器资源将是一种浪费,
     * 因为用户量也不是很大,所以也没对接第三方的OSS或者七牛云存储对象,就写个简单的图像压缩吧,我主要是提供了两种方式进行图片压缩,第一种是使用Java自带的Image绘制图像,输入指定的宽高尺寸,最后
     * 在重新绘制新的图片,核心代码也就三四行左右,压缩绘制算法都是JDK底层已经封装完成了。
     * 第二种是使用Google的压缩工具类Thumbnails 大名鼎鼎的不一般,只需要一行代码即可,可实现的功能那是相当的丰富,图像指定宽高压缩,原图压缩,添加水印,图像旋转,指定图像压缩质量比例等等。
     * @modified By:不要重复造轮子 不要重复造轮子 不要重复造轮子
     * @version: 0.0.1$
     */
    @Slf4j
    public class ImageCompress {
    
            // 这链接地址是拼接对应的服务器地址 用于回显给前端该图片地址使用。最后返回的效果是这样的:https://ucr.nb01.xyz/image-ucr/700393939333.png
            // 前端通过该地址可在浏览器直接访问,需要说明一点是 图片上传在了/opt/image目录下,最后通过地址能访问到该图片,需要通过nginx做一层转发,具体那就是运维可以配置一下或者自己NGINX 配置一下。
            private static final String PROD_URL = "";
            private static final String TEST_URL = "https://ucr.nb01.xyz/image-ucr/";
            private static final String LOCAL_URL = "http://127.0.0.1:8802/feo/";
            // 用的MAC系统,所以直接放在了系统的根目录某个文件夹下 如果是Win系统也可指定在某个盘符下存储即可。
            private static final String dirPath = "/opt/image";
            // 方式一压缩
            public static String imageCompress(MultipartFile file, int targetWidth, int targetHeight) {
                long startTime = System.currentTimeMillis();
                //得到上传时的原文件名
                String originalFilename = file.getOriginalFilename();
                //获取文件后缀名
                String suffixName = originalFilename.substring(originalFilename.lastIndexOf("."));
                String imageType = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
                //通过系统时间戳来命名文件:不是非常的规范请勿模仿
                String name = String.valueOf(System.nanoTime());
                String saveName = name.concat(suffixName);
                //存储目录
                String savePath = UploadPathUtils.getPicUploadDir(targetWidth, targetHeight);
                //图片存储全路径
                String outputPath = savePath.concat("/").concat(saveName);
                log.info("图片存储路径:[{}]",outputPath);
                OutputStream fouts = null;
                // 以上都是前期的准备
                try {
                    //读取源图
                    BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
                    // 获取源图宽度
                    double srcWidth = bufferedImage.getWidth();
                    // 获取源图高度
                    double srcHeight = bufferedImage.getHeight();
                    // 判断是否是需要压缩的尺寸比原图小 否则不进行压缩
                    if ((int) srcWidth >= targetWidth && (int) srcHeight >= targetHeight) {
                        // 建立传输通道---文件输出流 最后以流的形式把文件内容传输过去
                        fouts = new FileOutputStream(outputPath);
                        // 绘制新图时,使用Image.SCALE_SMOOTH算法,压缩后的图片质量相对比较光滑,没有明显的锯齿形,又叫做图片压缩光滑算法
                        // 还可选择其他压缩算法 例如:SCALE_FAST 比光滑算法更快速,还有默认算法等可选。
                        Image image = bufferedImage.getScaledInstance(targetWidth, targetHeight, Image.SCALE_SMOOTH);
                        BufferedImage bufferedImage1 = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB);
                        Graphics g = bufferedImage1.getGraphics();
                        g.setColor(Color.RED);
                        //绘制处理后的图
                        g.drawImage(image, 0, 0, null);
                        g.dispose();
                        ImageIO.write(bufferedImage1, imageType, fouts);
                        log.info("图片压缩结束");
                    }
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (fouts != null) {
                        try {
                            fouts.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
                if (FileUtil.isLinux()) {
                    outputPath = TEST_URL.concat(saveName);
                }
                return outputPath;
            }
    
        /**
         * 方式二压缩 Google大法 因为Thumbnails.of() 方法是一个重载方法,参数不仅仅局限于是一个文件类型 可以是以流的形式 File形式,ImageBuffer对象,URL路径,String类型指定文件路径
         * 然后可通过链式构造器传入不通参数,压缩比例,指定输出的格式等最终通过toFile("文件存储路径")返回一个已经压缩完成的图片。
         * @param file 待压缩的文件
         * @return 压缩后图片路径 这个可自己指定
         */
        public static String thumbnail(MultipartFile file) {
            //得到上传时的原文件名
            String originalFilename = file.getOriginalFilename();
            //获取文件格式
            String ext = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
            //获取uuid作为文件名
            String name = UUID.randomUUID().toString().replaceAll("-", "");
            try {
                // 先尝试压缩并保存图片
                Thumbnails.of(file.getInputStream()).scale(0.5f)
                        .outputQuality(0.15f)
                        .outputFormat("jpeg")
                        .toFile("/image/" + name);
            } catch (IOException e) {
    
            }
            return TEST_URL.concat(name).concat(".").concat("jpeg");
        }
        }
    
    

     

     

    展开全文
  • 之前文章已经介绍了 MinIO 的环境搭建,已经对文件的上传下载方法,本篇文章一起与大家来学习图片压缩上传的方法 1、背景 最近客户总抱怨 APP 中图片显示较慢, 升级服务器带宽又没有多的预算,查看原因,是因为现在...

    之前文章已经介绍了 MinIO 的环境搭建,已经对文件的上传下载方法,本篇文章一起与大家来学习图片压缩上传的方法

    1、背景

    最近客户总抱怨 APP 中图片显示较慢, 升级服务器带宽又没有多的预算。查看原因,是因为现在大家都是用的智能手机拍照,拍出来的照片小则 2-3 M,大则十几 M,所以导致图片显示较慢。思考再三,决定将图片进行压缩再上传图片服务器来解决图片显示慢的问题

    2、开发前戏

    1、引入 maven 依赖

    <!-- 图片压缩 -->
    <dependency>
        <groupId>net.coobird</groupId>
        <artifactId>thumbnailator</artifactId>
        <version>0.4.8</version>
    </dependency>
    

    本次我们选择了使用 thumbnailator 来作为压缩的工具

    2、thumbnailator 简介

    • Thumbnailator 是一个用来生成图像缩略图的 Java 类库,通过很简单的代码即可生成图片缩略图,也可直接对一整个目录的图片生成缩略图
    • 支持图片缩放,区域裁剪,水印,旋转,保持比例

    3、压缩前戏

    • 判断是否是图片方法
    /**
     * 判断文件是否为图片
     */
    public boolean isPicture(String imgName) {
        boolean flag = false;
        if (StringUtils.isBlank(imgName)) {
            return false;
        }
        String[] arr = {"bmp", "dib", "gif", "jfif", "jpe", "jpeg", "jpg", "png", "tif", "tiff", "ico"};
        for (String item : arr) {
            if (item.equals(imgName)) {
                flag = true;
                break;
            }
        }
        return flag;
    }
    

    3、压缩上传

    /**
     * 上传文件
     *
     * @param file 文件
     * @return
     */
    public JSONObject uploadFile(MultipartFile file) throws Exception {
        JSONObject res = new JSONObject();
        res.put("code", 500);
        // 判断上传文件是否为空
        if (null == file || 0 == file.getSize()) {
            res.put("msg", "上传文件不能为空");
            return res;
        }
        // 判断存储桶是否存在
        if (!client.bucketExists("test")) {
            client.makeBucket("test");
        }
        // 拿到文件后缀名,例如:png
        String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1);
        // UUID 作为文件名
        String uuid = String.valueOf(UUID.randomUUID());
        // 新的文件名
        String fileName = DateUtils.getYyyymmdd() + "/" + uuid + "." + suffix;
        /**
         * 判断是否是图片
         * 判断是否超过了 100K
         */
        if (isPicture(suffix) && (1024 * 1024 * 0.1) <= file.getSize()) {
            // 在项目根目录下的 upload 目录中生成临时文件
            File newFile = new File(ClassUtils.getDefaultClassLoader().getResource("upload").getPath() + uuid + "." + suffix);
            // 小于 1M 的
            if ((1024 * 1024 * 0.1) <= file.getSize() && file.getSize() <= (1024 * 1024)) {
                Thumbnails.of(file.getInputStream()).scale(1f).outputQuality(0.3f).toFile(newFile);
            }
            // 1 - 2M 的
            else if ((1024 * 1024) < file.getSize() && file.getSize() <= (1024 * 1024 * 2)) {
                Thumbnails.of(file.getInputStream()).scale(1f).outputQuality(0.2f).toFile(newFile);
            }
            // 2M 以上的
            else if ((1024 * 1024 * 2) < file.getSize()) {
                Thumbnails.of(file.getInputStream()).scale(1f).outputQuality(0.1f).toFile(newFile);
            }
            // 获取输入流
            FileInputStream input = new FileInputStream(newFile);
            // 转为 MultipartFile
            MultipartFile multipartFile = new MockMultipartFile("file", newFile.getName(), "text/plain", input);
            // 开始上传
            client.putObject("test", fileName, multipartFile.getInputStream(), file.getContentType());
            // 删除临时文件
            newFile.delete();
            // 返回状态以及图片路径
            res.put("code", 200);
            res.put("msg", "上传成功");
            res.put("url", minioProp.getEndpoint() + "/" + "test" + "/" + fileName);
        }
        // 不需要压缩,直接上传
        else {
            // 开始上传
            client.putObject("test", fileName, file.getInputStream(), file.getContentType());
            // 返回状态以及图片路径
            res.put("code", 200);
            res.put("msg", "上传成功");
            res.put("url", minioProp.getEndpoint() + "/" + "test" + "/" + fileName);
        }
        return res;
    }
    
    • 这里我们判断了当文件为图片的时候,且当它大小超过了 (1024 * 1024 * 0.1),约为 100K 的时候,才进行压缩
    • 我们首先在根目录下的 upload 目录中创建了一个临时文件 newFile
    • Thumbnails.of(file.getInputStream()).scale(1f).outputQuality(0.3f).toFile(newFile);将压缩后的文件输出到临时文件中
    • 然后将 FileInputStream 转为 MultipartFile 上传
    • 最后删除临时文件 newFile.delete();
    • 完成图片压缩上传

    4、测试

    • 原图 706K

    原图

    • 压缩后 120K

    压缩后

    5、总结

    • 综合以上代码,可以看出 Thumbnails 对图片的处理是很方便的,且代码量也非常少
    • 通过测试,可以看出压缩后的图片质量也很高
    • thumbnailator 对图片的处理支持全面,缩放,裁剪等

    如您在阅读中发现不足,欢迎留言!!!

    展开全文
  • 在网站的开发中,经常会使用到...需要在FTP、共享和本地三种情况下实现图片压缩后上传下载,特在此对需要在代码进行分享记录,话不多说,直接上核心干货。 1、网页上下载图片压缩包 核心: 1)根据指定图片或图...

           在网站的开发中,经常会使用到上传和下载图片的功能,可是有时候由于图片过大,或者所需下载的图片过多,为减少下载时间,提高下载速度,很多人都会想到通过压缩的方式进行上传或下载图片,最近刚好有一个项目使用了此功能,需要在FTP、共享和本地三种情况下实现图片压缩后上传下载,特在此对需要在代码进行分享记录,话不多说,直接上核心干货。

    1、网页上下载图片压缩包

    核心:

    1)根据指定图片或图片路径获取到图片数据流

    2)把图片流下载到临时文件中,并对其进行压缩

    3)完成后删除临时文件,返回压缩包

    4)删除压缩包

    所需jar:

    commons-compress-1.6.jar

    核心处理代码如下:

    public void zipImg(ZipArchiveOutputStream zaos,String pathtemp,byte[] data,String name) throws Exception{
            if(data != null){ 
                String nameTemp = name+"_"+new Date().getTime();
                File imageFileTemp = new File(pathtemp+File.separator+nameTemp+".jpg"); 
                //创建输出流 
                FileOutputStream outStream = new FileOutputStream(imageFileTemp); 
                //写入数据 
                outStream.write(data); 
                //关闭输出流 
                outStream.close(); 
                
                //获取创建好的图片文件 
                File imageFile = new File(pathtemp+"/"+nameTemp+".jpg"); 
                ZipArchiveEntry zipArchiveEntry  = new ZipArchiveEntry(imageFile,imageFile.getName());
                zaos.putArchiveEntry(zipArchiveEntry);
                zaos.write(data);
                zaos.closeArchiveEntry(); 
                // 压缩完删除txt文件 
                if (imageFile.exists()) { 
                    imageFile.delete(); 
                } 
            }
        }
            //定义根路径 
            String rootPath = request.getSession().getServletContext().getRealPath("/");
            String pathtemp = rootPath + "temp_download";
            File file = new File(pathtemp); //创建临时目录
            if(!file.exists()){ //判断文件是否存在,如果不存在,则创建此文件夹 
               file.mkdir(); 
            } 
            String zipFileName = title+"行李图片压缩包_"+creatDate + ".zip"; 
            File zipFile = new File(pathtemp + "/" + zipFileName); 
            ZipArchiveOutputStream zaos = null;
            try {
                zaos = new ZipArchiveOutputStream(zipFile);
                zaos.setUseZip64(Zip64Mode.AsNeeded);
                
                PropertiesConfig prop = new PropertiesConfig("general.properties");
                String mode = prop.getPropertieString("mode");
                if(mode.equals("Local")){//本地
                    for(int i = 0 ;i<paths.size();i++){
                        try{
                            //调用工具类获取图片
                            byte[] data = ImageUtil.image2byte(paths.get(i));
                            zipImg(zaos,pathtemp,data,nameList.get(i));
                        }catch(Exception e){
                            System.out.println(e.getMessage());
                        }
                    }
                    zaos.finish();
                }else if(mode.equals("CIFS")){//共享文件
                    for(int i = 0 ;i<paths.size();i++){
                        try{
                            //调用工具类获取图片
                            byte[] data = SMBUtils.GetSMB().DownloadRemoteFile(paths.get(i));
                            zipImg(zaos,pathtemp,data,nameList.get(i));
                        }catch(Exception e){
                            System.out.println(e.getMessage());
                        }
                    }
                    zaos.finish();
                }else if(mode.equals("FTP")){//FTP
                    for(int i = 0 ;i<paths.size();i++){
                        try{
                            //调用工具类获取图片
                            byte[] data = FtpUtils.GetFTPClient().download(paths.get(i));
                            zipImg(zaos,pathtemp,data,nameList.get(i));
                        }catch(Exception e){
                            System.out.println(e.getMessage());
                        }
                    }
                    zaos.finish();
                }
                file.delete();//删除临时目录
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                try {
                    if(zaos != null) {
                        zaos.close();
                    }
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            
         // 输出到客户端 
            OutputStream out = null; 
            out = response.getOutputStream(); 
            response.reset(); 
            response.setHeader("Content-Disposition", "attachment;filename=" + new String(zipFileName.getBytes("GB2312"), "ISO-8859-1")); 
            response.setContentType("application/octet-stream; charset=utf-8"); 
            response.setCharacterEncoding("UTF-8"); 
            out.write(FileUtils.readFileToByteArray(zipFile)); 
            out.flush(); 
            out.close(); 
            // 输出客户端结束后,删除压缩包 
            if (zipFile.exists()) { 
                zipFile.delete(); 
            } 

    上传的流程与这差不多,就不在此共享了,另附赠一份完整的压缩解压工具类,用于压缩和解压指定目录下的所有文件

    package com.ljb.ImageUtil;
    
    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.util.ArrayList;
    import java.util.List;
     
    import org.apache.commons.compress.archivers.ArchiveEntry;
    import org.apache.commons.compress.archivers.zip.Zip64Mode;
    import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
    import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
    import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
     
    public class ZipUtil {
        public static void main(String[] args) {
            String dir = "D:\\zip";
            String zippath = "D:\\zip\\test2.zip";
            ZipUtil.zip(dir, zippath);
     
            String unzipdir = "D:\\test2";
    //        String unzipdir = "D:\\zip\\img";
    //        String unzipfile = "D:\\zip\\test2.zip";
    //        ZipUtil.unzip(unzipfile, unzipdir);
    //        System.out.println("success!");
        } 
        /**
         * zip压缩文件
         * @param dir
         * @param zippath
         */
        public static void zip(String dir ,String zippath){
            List<String> paths = getFiles(dir); 
            compressFilesZip(paths.toArray(new String[paths.size()]),zippath,dir);
        }
        /**
         * 递归取到当前目录所有文件
         * @param dir
         * @return
         */
        public static List<String> getFiles(String dir){
            List<String> lstFiles = null;       
            if(lstFiles == null){
                lstFiles = new ArrayList<String>();
            }
            File file = new File(dir);
            File [] files = file.listFiles(); 
            for(File f : files){
                if(f.isDirectory()){
                    lstFiles.add(f.getAbsolutePath());
                    lstFiles.addAll(getFiles(f.getAbsolutePath()));
                }else{ 
                    String str =f.getAbsolutePath();
                    lstFiles.add(str);
                }
            }
            return lstFiles;
        }
        
        /**
         * 文件名处理
         * @param dir
         * @param path
         * @return
         */
        public static String getFilePathName(String dir,String path){
            String p = path.replace(dir+File.separator, "");
            p = p.replace("\\", "/");
            return p;
        }
        /**
         * 把文件压缩成zip格式
         * @param files         需要压缩的文件
         * @param zipFilePath 压缩后的zip文件路径   ,如"D:/test/aa.zip";
         */
        public static void compressFilesZip(String[] files,String zipFilePath,String dir) {
            if(files == null || files.length <= 0) {
                return ;
            }
            ZipArchiveOutputStream zaos = null;
            try {
                File zipFile = new File(zipFilePath);
                zaos = new ZipArchiveOutputStream(zipFile);
                zaos.setUseZip64(Zip64Mode.AsNeeded);
                //将每个文件用ZipArchiveEntry封装
                //再用ZipArchiveOutputStream写到压缩文件中
                for(String strfile : files) {
                    File file = new File(strfile);
                    if(file != null) {
                        String name = getFilePathName(dir,strfile);
                        ZipArchiveEntry zipArchiveEntry  = new ZipArchiveEntry(file,name);
                        zaos.putArchiveEntry(zipArchiveEntry);
                        if(file.isDirectory()){
                            continue;
                        }
                        InputStream is = null;
                        try {
                            is = new BufferedInputStream(new FileInputStream(file));
                            byte[] buffer = new byte[1024 ]; 
                            int len = -1;
                            while((len = is.read(buffer)) != -1) {
                                //把缓冲区的字节写入到ZipArchiveEntry
                                zaos.write(buffer, 0, len);
                            }
                            zaos.closeArchiveEntry(); 
                        }catch(Exception e) {
                            throw new RuntimeException(e);
                        }finally {
                            if(is != null)
                                is.close();
                        }
                         
                    }
                }
                zaos.finish();
            }catch(Exception e){
                throw new RuntimeException(e);
            }finally {
                    try {
                        if(zaos != null) {
                            zaos.close();
                        }
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
            }
             
        }
        
       
        /**
        * 把zip文件解压到指定的文件夹
        * @param zipFilePath zip文件路径, 如 "D:/test/aa.zip"
        * @param saveFileDir 解压后的文件存放路径, 如"D:/test/" ()
        */
        public static void unzip(String zipFilePath, String saveFileDir) {
            if(!saveFileDir.endsWith("\\") && !saveFileDir.endsWith("/") ){
                saveFileDir += File.separator;
            }
            File dir = new File(saveFileDir);
            if(!dir.exists()){
                dir.mkdirs();
            }
            File file = new File(zipFilePath);
            if (file.exists()) {
                InputStream is = null; 
                ZipArchiveInputStream zais = null;
                try {
                    is = new FileInputStream(file);
                    zais = new ZipArchiveInputStream(is);
                    ArchiveEntry archiveEntry = null;
                    while ((archiveEntry = zais.getNextEntry()) != null) { 
                        // 获取文件名
                        String entryFileName = archiveEntry.getName();
                        // 构造解压出来的文件存放路径
                        String entryFilePath = saveFileDir + entryFileName;
                        OutputStream os = null;
                        try {
                            // 把解压出来的文件写到指定路径
                            File entryFile = new File(entryFilePath);
                            if(entryFileName.endsWith("/")){
                                entryFile.mkdirs();
                            }else{
                                os = new BufferedOutputStream(new FileOutputStream(
                                        entryFile));                            
                                byte[] buffer = new byte[1024 ]; 
                                int len = -1; 
                                while((len = zais.read(buffer)) != -1) {
                                    os.write(buffer, 0, len); 
                                }
                            }
                        } catch (IOException e) {
                            throw new IOException(e);
                        } finally {
                            if (os != null) {
                                os.flush();
                                os.close();
                            }
                        }
     
                    } 
                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    try {
                        if (zais != null) {
                            zais.close();
                        }
                        if (is != null) {
                            is.close();
                        }
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
    }
    

     

    展开全文
  • 最近要搞一个项目,需要上传相册和拍照的图片,不负所望,终于完成了! 不过需要说明一下,其实网上很多教程拍照的图片,都是缩略图不是很清晰,所以需要在调用照相机的时候,事先生成一个地址,用于标识拍照的图片...
  • 在android应用开发中,涉及到本地图片上传的一般都会先对图片进行压缩再上传。 常见的压缩方式有两种:一种是利用BitmapFactory.Options对图片进行尺寸上的压缩,具体方法如下: /** * 把原图按比例压缩 * ...
  • * 图片压缩,默认同比例压缩 * @param {Object} path * pc端传入的路径可以为相对路径,但是在移动端上必须传入的路径是照相图片储存的绝对路径 * @param {Object} obj * obj 对象 有 width, height, quality...
  • FastDFS合并存储以及图片压缩配置

    千次阅读 2019-07-21 02:05:55
    一、合并存储配置 FastDFS提供了合并存储功能的实现,所有的配置都在tracker...storage服务器磁盘上存储的合并后的实际文件,默认大小为64MB。Trunk文件文件名格式:fdfs_storage1/data/00/00/000001 文件名从1开始...
  • 前端压缩图片后上传到服务器 前端压缩图片后上传到服务器 ## 前端压缩图片后上传到服务器。 由于现在手机像素普遍较高,随手拍一张图片都6、7M,十几兆的图片也并不罕见。如果这些未处理的图片直接随数据上传向...
  • Android之图片压缩

    千次阅读 多人点赞 2016-09-09 16:09:54
    在开发中,对于图片的操作,稍有不慎,可能就会消耗大量的内存,导致程序崩溃,所以了解一种通用的技术去处理和加载图片,同时保证UI流畅避免OOM现象,是非常有必要的。那么为什么在Android中对于图片的处理会如此...
  • 复制代码 代码如下: <?... charset=gb2312”); $uptypes=array(‘image/jpg’, //上传文件类型列表 ‘image/jpeg’, ‘image/png’, ‘image/pjpeg’, ‘image/gif’, ‘image/bmp’, ‘application/x-shockwave-...
  • web前端 图片压缩后上传到阿里云oss

    千次阅读 2019-01-22 15:47:50
    当项目中有图片上传功能时,一般公司都是使用第三方的存储平台,这样便不会产生自己服务器资源占用问题, 为避免上传图片太大占用太多空间,提高用户访问的速度,需要将图片进行压缩之后再存储。 下面直接贴代码:...
  • 需求: 最近在做项目的时候采用了多模块的方案 ...方案一:自己搭建一个ftp服务器上传图片 然后再搭建一个nginx服务器来访问 方案二:采用七牛云存储平台 这里我采用的是方案二 因为没有体验过七牛 借
  • 实际上信息量大的网页和高清图片占用存储空间是非常大的,这样不利于服务器性能的优化 因此我们要在服务器上面将网页和图片进行压缩,让客户端去下载就可以了 2.实现网页压缩 (1)查看nginx服务器的默认发布文件 ...
  • web前端图片压缩方法可参考我这边文章:web前端 图片压缩后上传到阿里云oss 里面引用到的几个js文件可以在我的github上获取 https://github.com/hujinchen/alyoss-compression 结合layui框架使用,效果图 ...
  • 我的服务器上的程序,是用django写的,数据库为sqlite,图片文件存储在media目录下。 先看models.py,只有一个ImageField类型的变量picture,也就是一会压缩图片需要用到的变量。 class CrossPicture(models.Model)...
  • 图片压缩的两种方法

    千次阅读 2020-05-13 00:55:38
    图片处理,两种质量压缩,分辨率压缩对比,android中对于图片的处理非常的常见,总体上希望图片能占用内存小,View上显示刚刚好,并且上传服务器大小符合要求且图片不模糊。要达到这些要求我们得知道一些知识
  • iOS优秀的图片压缩处理方案

    千次阅读 2018-11-29 21:18:52
    最近遇到一个图片压缩的问题,项目需求压缩图片500k以内上传服务器,还要求图片要清晰一点。还有证明是图片500k已经确实很清晰了,那就没办法,做呗~~!(不喜欢听bb的可以直接去下面撸代码) 思路 本来以为很...
  • 参考: 1.... ... 1.背景: 最近一个项目的开发,需要用到相机拍照,裁剪,保存,上传图片到七牛云的操作,并在上传的过程中遇到了图片过大,服务器返回溢出的错误,难搞哦。在其中发现,...
  • 前端图片压缩上传(压缩篇)

    千次阅读 2020-02-14 21:25:43
    为什么说这是一篇比较适合小白的前端图片压缩文章呢?因为我也是一个刚工作半年的前端小白,最近接到了一个前端图片压缩上传的任务,通过各种百度博客完成了这项任务,但是任务完成后对各种技术细节却...
  • 在做网站开发时,我常常会做一些这样的工作:一张大图中包含了许多的小图,而网站中为了使用其中一张小图我不得不把大图切成一张张的小图。虽然这样的工作不多;...所以有了今天的服务器端剪切压缩图片的一章。
  • 基于Plupload的图片压缩上传

    千次阅读 2018-03-01 00:20:58
    为什么要做图片压缩? 现在手机拍照都快10M了,但是有时候图片上传只要看得清楚就可以了,比如上传身份证200k能看清楚,为什么要上传20M?这样做的好处是减少服务器存储压力、减少带宽占用。 为什么要自己做一个...
  • java 对图片进行压缩

    万次阅读 2018-09-14 17:32:44
    图片压缩大法 为了防止用户流量的丢失,即使在5g 即将来临的情况下,压缩算法依旧是很有必要的,额跑题了,不好意思,今天介绍的不是压缩算法,讲啥呢?主要讲讲如何通过 java 将图片进行压缩,尽可能的控制...
  • android关于选取本地图片,返回路径不同,不正确问题;调用相机返回压缩图片的解决方法;图片压缩上传;
  • Zimg—轻量级图片服务器搭建利器

    万次阅读 2018-08-31 08:53:25
    有稳定的可扩展的图片存储服务器就显得尤为的重要,云厂商们提供了便利的图片存储服务,花钱就可以解决了。这里简单介绍一个开源的一个分布式图片存储服务器——zimg,来自己搭建一个图片服务器。 当然你也可以利用...
  • Nginx - 实现图片压缩

    2020-05-27 01:00:22
    图片压缩的目的2. 图片压缩实现过程2.1 动态模块的编译安装2.2 将动态模块加载到文件中2.3 测试 1. 图片压缩的目的 在企业当中,nginx服务器上的资源要尽可能的占用的空间少一点; 实际上信息量大的网页和高清图片...
  • 前端进行图片压缩并传入后台

    千次阅读 2018-04-18 02:20:43
    图片转成image对象;2. 压缩成设置的最大尺寸;3. 通过canvas转成base64码;4. 后台(此处是java)进行base64解码存储。以下上具体代码。所有代码见:github客户端:&lt;!DOCTYPE html&gt; &lt;...
  •  之前的代码由于app的图片要上传到图片服务器,为了节省流量和减少上传时的耗时,所以图片应该尽量小,但却导致了图片不清晰。  好吧,问题来了,如何找一个让客户满意,图片大小和清晰度合适的参数呢?  我想了...
  • 最接近微信的图片压缩算法Luban

    千次阅读 2016-11-09 10:32:17
    Luban是一个国内很牛逼的图片压缩库:https://github.com/Curzibn/Luban 使用这个库有很多东西都没法自己修改了(比如压缩后图片保存的地址)。所以我把源码弄下来。自己做一个util包。用起来就很方便了。 这里把...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 63,589
精华内容 25,435
关键字:

服务器图片压缩存储