C#编写批量jpg文件压缩小工具

有一天,客户领导说网站加载慢

客户的网站请广告公司设计的,堆叠了大量的高精度美图。忽然有一天,老总说网站怎么这么慢?

客户不懂技术,只管提需求

网站在建立的时候就已经告知会有什么优点和弱项了,但是客户都是善于遗忘的人。他们只管现在,不管过去。所以唯一不必的是变化这句话就又被验证了一次。
怎么办呢?

  1. 全新的界面设计 ,重构网站?显然不太现实,刚做好没两个月。
  2. 缩小图片文件大小是唯一可行可试的方案。第一步缩小时将png全部改为了jpg,因为不用考虑透明度的问题。第二步就是降低jpg图片的质量,随之减小文件大小。
    tinypng.com 做了几张,感觉太麻烦了,这要做到几时去呢?
    于是自己写了一个小工具,可以批量的缩小jpg文件的大小,当然图片质量会略有下降了,但是普通访问者都几乎无法注意到,是可以接受的。

为了方便,写了一个Console应用,命令行方式运行:
Please enter resize argument.
Usage: JpgResizer -r 75 -o -b
Usage: JpgResizer *.jpg -r 75 -o -b -s
-b : 备份原始文件,在覆盖模式时有用 backup the original file. use when -o is set.
-o : 覆盖模式,直接重写原文件 overwrite the original file.
-s : 搜索当前目录下的所有子目录下的文件 search all jpg files in sub-directories. ignore filename.
-r : 压缩后图片质量级别 compress level. default is 75, 100 is best.

源代码,复制可用

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;

namespace JpgResizer
{
    class Program
    {
        static bool isOverwrite = false;
        static Int64 ratio = 75L;
        static bool isIncludeSubDirectories = false;
        static bool isBackup = false;

        static void Main(string[] args)
        {
            
            string filename = "*.jpg";

            if (args.Length == 0)
            {
                Console.WriteLine("============== JPG Compress tool ==================");
                Console.WriteLine("= Author : shrek");
                Console.WriteLine("= Contact: (QQ390652)");
                Console.WriteLine("= Date   : 2021.01.21");
                Console.WriteLine("= Hangzhou Codans Cyberinfo Company. ");
                Console.WriteLine("===================================================");
                Console.WriteLine("Please enter resize argument.");
                Console.WriteLine("Usage: JpgResizer <filename> -r 75 -o -b");
                Console.WriteLine("Usage: JpgResizer *.jpg -r 75 -o -b -s");
                Console.WriteLine(" -b  : backup the original file. use when -o is set.");
                Console.WriteLine(" -o  : overwrite the original file. ");
                Console.WriteLine(" -s  : search all jpg files in sub-directories. ignore filename.");
                Console.WriteLine(" -r  : compress level. default is 75, 100 is best.");

                return;
            }

            filename = args[0];
            if (!filename.Contains(".jpg") && !filename.Contains(".jpeg") && !filename.Contains("*"))
            {
                Console.WriteLine("   missing filename.");
                return;
            }

            var index = 1;
            foreach (var item in args.Skip(1))
            {
                if (item.ToLower() == "-o")
                {
                    isOverwrite = true;
                }
                if (item.ToLower() == "-b")
                {
                    isBackup = true;
                }
                else if (item.ToLower()== "-s")
                {
                    isIncludeSubDirectories = true;
                }
                else if (item.ToLower()=="-r")
                {
                    if (args.Length >= index+1)
                    {
                        ratio = Int64.Parse(args[index + 1]);
                    }
                    else
                    {
                        Console.WriteLine("  missing ratio paramenter.");
                        return;
                    }
                }
                index++;
            }

            if (isIncludeSubDirectories)
            {
                ListJpg(AppContext.BaseDirectory);
            }
            else { 
                VaryQualityLevel(filename, ratio, isOverwrite);
            }

        }

        private static void ListJpg(string dir)
        {
            DirectoryInfo d = new DirectoryInfo(dir);
            FileInfo[] files = d.GetFiles("*.jpg");//文件
            DirectoryInfo[] directs = d.GetDirectories();//文件夹
            foreach (FileInfo f in files)
            {
                VaryQualityLevel(f.FullName, ratio, isOverwrite);  
            }
            //获取子文件夹内的文件列表,递归遍历  
            foreach (DirectoryInfo dd in directs)
            {
                ListJpg(dd.FullName);
            }
        }

        private static ImageCodecInfo GetEncoder(ImageFormat format)
        {
            ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
            foreach (ImageCodecInfo codec in codecs)
            {
                if (codec.FormatID == format.Guid)
                {
                    return codec;
                }
            }
            return null;
        }

        private static void VaryQualityLevel(string fileName,Int64 ratio,bool isOverwrite)
        {
            Console.WriteLine($"filename : {fileName}");
            // Get a bitmap. The using statement ensures objects  
            // are automatically disposed from memory after use.  
            var originalSize = new FileInfo(fileName).Length;
            var newSize = 0L;


            var newFileName = Path.GetFileNameWithoutExtension(fileName) + "_new" + Path.GetExtension(fileName);
            if (isOverwrite)
            {
                newFileName = fileName;
                if (isBackup)
                {
                    var backupFileName = Path.GetFileNameWithoutExtension(fileName) + "_original" + Path.GetExtension(fileName);
                    File.Copy(fileName, backupFileName, true);
                }
            }
            using (Bitmap bmp0 = new Bitmap(fileName))
            {
                var bmp1 = new Bitmap(bmp0);
                bmp0.Dispose();
                ImageCodecInfo jpgEncoder = GetEncoder(ImageFormat.Jpeg);

                // Create an Encoder object based on the GUID  
                // for the Quality parameter category.  
                System.Drawing.Imaging.Encoder myEncoder =
                    System.Drawing.Imaging.Encoder.Quality;

                // Create an EncoderParameters object.  
                // An EncoderParameters object has an array of EncoderParameter  
                // objects. In this case, there is only one  
                // EncoderParameter object in the array.  
                EncoderParameters myEncoderParameters = new EncoderParameters(1);

                EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, ratio);
                myEncoderParameters.Param[0] = myEncoderParameter;
                bmp1.Save(newFileName, jpgEncoder, myEncoderParameters);
                newSize = new FileInfo(newFileName).Length;
                Console.WriteLine($"  resize ok. {originalSize} -> {newSize} { ((originalSize - newSize) * 100 / originalSize).ToString("0.#") }% compressed.");
            }
        }
    }
}

总结

参考了以下信息,站在别人的肩膀上就看得远一些。

【日月谈】是自己维护的一个微信小程序,可以在线写日记,有好多朋友写了快20年,您如果有兴趣,可以去用用看。
https://everyday.yuelvsu.com

Github: https://github.com/ihugang/JpgResizer

posted @   ihugang  阅读(96)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗
点击右上角即可分享
微信分享提示