为什么有这么多图片压缩工具,还要再做一个?

34 天前
 littletong

最近频繁使用图片压缩功能,发现目前主流图片压缩工具还是有些不足:

所以叒整了一个新的图片压缩工具,算是把几个痛点都解决了:

  1. 隐私安全,不上传图片,压缩速度也成倍提升;
  2. 批量压缩,不限制个数;
  3. 大图片压缩,不限制大小;
  4. 支持指定 KB 压缩;
  5. 支持指定尺寸和压缩质量,图片格式;
  6. 支持压缩后对比效果;
  7. 默认高效的 WebP 格式,透明度+小+质量高,主流浏览器和系统都支持;

欢迎大家体验并提出改进意见 https://compressimage.cn

3271 次点击
所在节点    分享创造
59 条回复
iMusic
34 天前
第 4 点怎么做到的?
zqjilove
34 天前
界面舒服,点个赞
zqjilove
34 天前
给个建议,添加到列表里待处理的,无法删除,这个体验不够好。
miaomiao888
34 天前
ltaoo1o
34 天前
这类工具核心是压缩算法

刚刚试了下,一张 280kb 的 PNG 图片,你的压缩率 0 。。。TinyPNG 能压缩到 76KB

https://image.988589.xyz/api/cfile/AgACAgUAAyEGAASC5r41AAMoZ1AdKZVcixStxWYgMs8oBpLgC8IAAtq9MRsNv4FW6VqTga4eZuIBAAMCAAN5AAM2BA
ltaoo1o
34 天前
@miaomiao888 笑死
bugoftime
34 天前
👍。试了下,保持原格式 png ,80p 质量,变大了好多啊
ypzhou
34 天前
@li1218040201 有原图吗 我想试下我的压缩工具
ltaoo1o
34 天前
Outshine
34 天前
页面很清爽干净啊。

你这 cn 域名放 vercel ?

不考虑盈利?
siweipancc
34 天前
移动端不友好啊
lizhenda
34 天前
cn 域名不太好做海外吧
liu731
34 天前
试了一下,建议别叫压缩工具,叫图片格式转换算了
chutsetien
34 天前
首先,webp 的画质非常差,用 cwebp -mt -q 100 -m 6 -sharp_yuv -af -alpha_filter best -sns 0 压出来的 webp 都会与原图有放大后能够看到的明显区别,毕竟是 VP8 打底,最高水准也就那样了。当然,确实,体积小。
目前建议 jpegli. jpegli 的 q 90 感觉和上面那个各项打满的 q 100 的质量差不多。当然要求高一些的话可以往 q 95+ 走。
我有个自用的 batch 档,也是做转换和切割图片的——我不是 programmer, 真不是,而且 batch 纯自用,因此各种不足之处还请见谅了。不知道 V 站怎么贴,就试试看 markdown 了。
```
@echo off
chcp 65001
setlocal enabledelayedexpansion
set "a="
set "i="
set "fn="
set "bn="
set "on="
set "gn="
set "np="
set "op="
set "cm="
set "sm="
set "hg="
set "jq="
set "wq="
set "sl="
set "sp="
set "ss="
set "sx="
set "sy="
set "cr1="
set "cr2="
set "cx1="
set "cx2="
set "sf1="
set "sf2="
set "cmb="
set "smb="
set "vfb="
set "cpf="
set "spf="
set "jpg="
set "png="
set "wbp="
set "sns="
:a
if "%~1"=="" goto p
set "a=%~1"
if "!a:~0,1!"=="-" (
if "!a!"=="-op" (set "np=%~2" & shift)
if "!a!"=="-on" (set "gn=%~2" & set "hg=1" & shift)
if "!a!"=="-ob" (set "bn=%~2" & shift)
if "!a!"=="-p" (set "png=1")
if "!a!"=="-wpq" (set "wbp=1" & set "sns=80" & set "wq=80")
if "!a!"=="-wlq" (set "wbp=1" & set "sns=50" & set "wq=85")
if "!a!"=="-wmq" (set "wbp=1" & set "sns=20" & set "wq=90")
if "!a!"=="-w" (set "wbp=1" & set "sns=0" & set "wq=95")
if "!a!"=="-whq" (set "wbp=1" & set "sns=0" & set "wq=99")
if "!a!"=="-jpq" (set "jpg=1" & set "jq=80")
if "!a!"=="-jlq" (set "jpg=1" & set "jq=85")
if "!a!"=="-jmq" (set "jpg=1" & set "jq=90")
if "!a!"=="-j" (set "jpg=1" & set "jq=95")
if "!a!"=="-jhq" (set "jpg=1" & set "jq=99")
if "!a!"=="-rg" (set "cm=rg" & set "cpf=rgr")
if "!a!"=="-cx" (set "cm=cx" & set "cx1=%~2" & set "cx2=%~3" & set "cpf=wth!cx1!t!cx2!" & shift & shift)
if "!a!"=="-cr" (set "cm=cr" & set "cr1=%~2" & set "cr2=%~3" & set "cpf=lts!cr1!t!cr2!" & shift & shift)
if "!a!"=="-gy" (set "cm=gy" & set "cpf=grv")
if "!a!"=="-gx" (set "cm=gx" & set "cpf=grh")
if "!a!"=="-gr" (set "cm=gr" & set "cpf=gr")
if "!a!"=="-sq" (set "cm=sq" & set "cpf=sq")
if "!a!"=="-up" (set "sm=up" & set "sp=%~2" & set "spf=!sp!pc" & shift)
if "!a!"=="-uf" (set "sm=uf" & set "sf1=%~2" & set "sf2=%~3" & set "spf=!sf1!d!sf2!" & shift & shift)
if "!a!"=="-uy" (set "sm=uy" & set "sy=%~2" & set "spf=x!sy!" & shift)
if "!a!"=="-ux" (set "sm=ux" & set "sx=%~2" & set "spf=!sx!x" & shift)
if "!a!"=="-us" (set "sm=us" & set "ss=%~2" & set "spf=s!ss!" & shift)
if "!a!"=="-ul" (set "sm=ul" & set "sl=%~2" & set "spf=l!sl!" & shift)
if "!a!"=="-sp" (set "sm=sp" & set "sp=%~2" & set "spf=!sp!pc" & shift)
if "!a!"=="-sf" (set "sm=sf" & set "sf1=%~2" & set "sf2=%~3" & set "spf=!sf1!d!sf2!" & shift & shift)
if "!a!"=="-sy" (set "sm=sy" & set "sy=%~2" & set "spf=x!sy!" & shift)
if "!a!"=="-sx" (set "sm=sx" & set "sx=%~2" & set "spf=!sx!x" & shift)
if "!a!"=="-ss" (set "sm=ss" & set "ss=%~2" & set "spf=s!ss!" & shift)
if "!a!"=="-sl" (set "sm=sl" & set "sl=%~2" & set "spf=l!sl!" & shift)
) else (
if not defined i set "i=%~1"
for %%f in ("!i!") do set "op=%%~dpf" & set "on=%%~nf"
)
shift
goto a
:p
if "!np!"=="" set "np=!op!"
if not "!np:~-1!"=="\" set "np=!np!\"
if not exist "!np!" md "!np!"
if "!bn!"=="" set "bn=!on!"
if defined cpf set "cpf=-!cpf!"
if defined spf set "spf=-!spf!"
if "!gn!"=="" set "gn=!bn!!cpf!!spf!"
if defined cm (
if "!cm!"=="cx" set "cmb=crop='floor(if(gte(iw/ih,!cx1!/!cx2!),ih*!cx1!/!cx2!,iw)/2)*2:floor(if(gte(iw/ih,!cx1!/!cx2!),ih,iw*!cx2!/!cx1!)/2)*2'"
if "!cm!"=="cr" set "cmb=crop='floor(if(gte(iw,ih),min(iw,ih*(!cr1!/!cr2!)),min(iw,ih*(!cr2!/!cr1!)))/2)*2:floor(if(gte(iw,ih),min(ih,iw*(!cr2!/!cr1!)),min(ih,iw*(!cr1!/!cr2!)))/2)*2'"
if "!cm!"=="rg" set "cmb=crop='floor(if(gte(iw,ih),min(iw,ih*(17711/28657)),min(iw,ih*(28657/17711)))/2)*2:floor(if(gte(iw,ih),min(ih,iw*(28657/17711)),min(ih,iw*(17711/28657)))/2)*2'"
if "!cm!"=="gy" set "cmb=crop='floor(if(gte(iw/ih,17711/28657),ih*17711/28657,iw)/2)*2:floor(if(gte(iw/ih,17711/28657),ih,iw*28657/17711)/2)*2'"
if "!cm!"=="gx" set "cmb=crop='floor(if(gte(iw/ih,28657/17711),ih*28657/17711,iw)/2)*2:floor(if(gte(iw/ih,28657/17711),ih,iw*17711/28657)/2)*2'"
if "!cm!"=="gr" set "cmb=crop='floor(if(gte(iw,ih),min(iw,ih*(28657/17711)),min(iw,ih*(17711/28657)))/2)*2:floor(if(gte(iw,ih),min(ih,iw*(17711/28657)),min(ih,iw*(28657/17711)))/2)*2'"
if "!cm!"=="sq" set "cmb=crop='floor(min(iw,ih)/2)*2:floor(min(iw,ih)/2)*2'"
)
if defined sm (
if "!sm!"=="sp" set "smb=scale='if(lte(!sp!,100),floor(iw*!sp!/100),iw):if(lte(!sp!,100),floor(ih*!sp!/100),ih)'"
if "!sm!"=="sf" set "smb=scale='if(lte(iw*!sf1!/!sf2!,iw),floor(iw*!sf1!/!sf2!),iw):if(lte(ih*!sf1!/!sf2!,ih),floor(ih*!sf1!/!sf2!),ih)'"
if "!sm!"=="sy" set "smb=scale='-2:if(lte(!sy!,ih),!sy!,ih)'"
if "!sm!"=="sx" set "smb=scale='if(lte(!sx!,iw),!sx!,iw):-2'"
if "!sm!"=="ss" set "smb=scale='if(lt(iw,ih),min(!ss!,iw),-2):if(gte(iw,ih),min(!ss!,ih),-2)'"
if "!sm!"=="sl" set "smb=scale='if(gte(iw,ih),min(!sl!,iw),-2):if(lt(iw,ih),min(!sl!,ih),-2)'"
if "!sm!"=="up" set "smb=scale='floor(iw*!sp!/100):floor(ih*!sp!/100)'"
if "!sm!"=="uf" set "smb=scale='floor(iw*!sf1!/!sf2!):floor(ih*!sf1!/!sf2!)'"
if "!sm!"=="uy" set "smb=scale=-2:!sy!"
if "!sm!"=="ux" set "smb=scale=!sx!:-2"
if "!sm!"=="us" set "smb=scale='if(lt(iw,ih),!ss!,-2):if(gte(iw,ih),!ss!,-2)'"
if "!sm!"=="ul" set "smb=scale='if(gte(iw,ih),!sl!,-2):if(lt(iw,ih),!sl!,-2)'"
)
if defined cm if not defined sm (set "vfb=!cmb!")
if not defined cm if defined sm (set "vfb=!smb!")
if defined cm if defined sm (set "vfb=!cmb!,!smb!")
if not defined vfb (
ffmpeg -i "!i!" -vframes:v 1 -update true -compression_level 0 "!op!!on!_intermediateagzk3kXe8nDr.png" -y
) else (
ffmpeg -i "!i!" -vframes:v 1 -update true -compression_level 0 -vf "!vfb!" -sws_flags lanczos+accurate_rnd+full_chroma_inp+full_chroma_int "!op!!on!_intermediateagzk3kXe8nDr.png" -y
)
if "!jpg!"=="1" (
cjpegli -q !jq! --chroma_subsampling=444 "!op!!on!_intermediateagzk3kXe8nDr.png" "!op!!on!_intermediateagzk3kXe8nDr.jpg"
exiftool -overwrite_original -all= "!op!!on!_intermediateagzk3kXe8nDr.jpg"
if "!hg!"=="1" (
move /y "!op!!on!_intermediateagzk3kXe8nDr.jpg" "!np!!gn!.jpg"
) else (
move /y "!op!!on!_intermediateagzk3kXe8nDr.jpg" "!np!!gn!-q!jq!.jpg"
)
)
if "!wbp!"=="1" (
cwebp -mt -q !wq! -m 6 -sharp_yuv -af -alpha_filter best -sns !sns! "!op!!on!_intermediateagzk3kXe8nDr.png" -o "!op!!on!_intermediateagzk3kXe8nDr.webp"
exiftool -overwrite_original -all= "!op!!on!_intermediateagzk3kXe8nDr.webp"
if "!hg!"=="1" (
move /y "!op!!on!_intermediateagzk3kXe8nDr.webp" "!np!!gn!.webp"
) else (
move /y "!op!!on!_intermediateagzk3kXe8nDr.webp" "!np!!gn!-q!wq!.webp"
)
)
if "!png!"=="1" (
optipng -o7 -zm1-9 "!op!!on!_intermediateagzk3kXe8nDr.png"
exiftool -overwrite_original -all= "!op!!on!_intermediateagzk3kXe8nDr.png"
move /y "!op!!on!_intermediateagzk3kXe8nDr.png" "!np!!gn!.png"
) else (
del /q "!op!!on!_intermediateagzk3kXe8nDr.png"
)
endlocal
```
givebest
34 天前
Mac 上可以试下这个仅 3MB 的 App: https://hp60.com/image2webp/
chutsetien
34 天前
@chutsetien 顺附自写的该 batch 档的用法解释:

A tiny little Windows Batch script used for the cropping, scaling, and format conversion of images. It requires the following software to be properly set up in %PATH% (here in my case is C:\_c\):

ffmpeg;
libwebp;
optipng; and
exiftool.

Understanding ‘orientation-adaptive’ and ‘orientation-irrelevant’

As the script is used for the cropping and scaling of images, it would require the clarification of two concepts: ‘orientation-adaptive’ and ‘orientation-irrelevant’.

The former, as its name indicates, takes the image’s orientation into account. This can be easily understood in the context of scaling, as we often do need to scale an image by its ‘long edge’ or ‘short edge’, regardless of whether it is the width or the height.

It might get a little bit confusing when it comes to cropping. In cropping, by saying ‘orientation-adaptive’, it means that when given a ratio, the long edge always takes the first number, while the short edge takes the second. For example, if we have a horizontal image (which means its width is greater than its height), and we want to crop it to 4:3 orientation-adaptively, then the long edge, the width, will take the ‘4’ while the short edge, the height, will take the ‘3’. And when done, it would indeed be an image of 4:3. But if we have a vertical image (which means the height is the longer edge), and we still want to orientation-adaptively crop it to 4:3, then the height of the image, now the long edge, shall take the ‘4’, while the width of the image will take the ‘3’, and the final result we get is actually an image of 3:4.

What makes the ‘orientation-adaptive cropping’ more confusing is that it can be used to crop ‘against’ the image’s orientation by setting a ratio smaller than 1, in that it can force the long edge to take the smaller number in the ratio to become the new short edge while the original short edge can take the larger number and becomes the new long edge.

The ‘orientation-irrelevant’ scaling or cropping is much easier to understand—as its name indicates, it does not take the image’s orientation into account, only focusing on scaling or cropping based on the width and height, regardless of which one is longer.

Cropping switches

The script accepts switches used for cropping in an order of precedence as follows—if more than one switch is detected in one operation, a switch with a higher rank surpasses the lower ones:

-sq: crops the image to a 1:1 square;
-gr: orientation-adaptively crops the image to the golden ratio;
-gx: orientation-irrelevantly crops the image to the golden ratio by setting its width as the long edge;
-gy: orientation-irrelevantly crops the image to the golden ratio by setting its height as the long edge;
-cr x y: orientation-adaptively crops the image to a set ratio of x:y, where the long edge of the image takes the x, and the short edge takes the y;
-cx x y: orientation-irrelevantly crops the image to a set ratio of x:y, where the width of the image takes the x, and the height takes the y; and
-rg: performs a ‘reversed’ orientation-adaptive golden ratio cropping, where the long edge of the image takes the smaller number of the golden ratio, and the short edge takes the larger (not very useful actually, and that’s why it gets the lowest precedence).

Scaling switches

The script accepts switches used for scaling in an order of precedence as follows—if more than one switch is detected in one operation, a switch with a higher rank surpasses the lower ones:

-sl x: proportionally scales the image by setting its long edge to x;
-ss x: proportionally scales the image by setting its short edge to x;
-sx x: proportionally scales the image by setting its width to x;
-sy x: proportionally scales the image by setting its height to x;
-sf x y: proportionally scales the image by a given fraction of x/y; and
-sp x: proportionally scales the image by a given percentage x (‘%’ is not needed when giving the percentage number).

The script, by default, prohibits upscaling, unless the user explicitly orders the script to do so by changing the first letter of these scaling switches to ‘u’ (-ul, -us, -ux, etc). I strongly dissuade anyone who intends to use this script to upscale any image, for that image upscaling simply shall not be done in this way as it needs much more complicated algorithms and should be done with dedicated manual tuning.

Output file format and quality switches

The script accepts switches -p, -j, and -w to indicate an output of a .png image, a .jpg image, or a .webp image. These switches can be used simultaneously to output more than one image. For -j and -w, there are four quality suffixes, hq (‘highest quality’), mq (‘medium quality’), lq (‘low quality’), and pq (‘poor quality’), each representing a fixed quality parameter (or a group of fixed quality-related parameters in the case of -w), that can be used by immediately appending to the letter j or q, with no spaces in between, to form a five-tier image quality levels (together with the two default ones of no sticking letters, the -j and -w, which are both ranked second best in the hierarchy) for the user to choose. And by knowing me, you can rest assured that even by using -jpq or -wpq, the output will still be acceptable. But since I use ffmpeg to encode JPEG files—which uses mjpeg as its encoder—the output files will then always be added with a ‘dash’ label in the names, indicating that they are intended for quick sharing uses, and are not expected to be used in serious scenarios. If -p is detected, then the output .png file will be compressed by optipng with maximum tries, which means it will take a considerably long period of time if the image is large. Lastly, all of the output files will be cleaned of EXIF information in the end.

Designating output filename and path

By default, the output file or files will be saved in the same location as the input file, using the original filename as the basename with text labels of the process or processes being done to it and of the image quality parameter appended in the end. And yet the output filename and path are designatable with the switches listed below:

-op "path\to\the\designated location\": if used, the output files will then be exported to the designated location;
-ob new_basename: if used, then the given string will surpass the file’s original name and be used as the designated basename—the text labels for processed and image quality will still be appended to the given basename; and
-on "new filename": if used, then the given string will be used as the full filename of the output file, with no more appendings.

Since one operation of the script can produce more than one file in different formats, strings given after -ob and -on shall not contain a file extension, as it will be added automatically according to the output format.
chutsetien
34 天前
@chutsetien 虽然知道可能没什么人看,但是加注一下:

> But since I use ffmpeg to encode JPEG files—which uses mjpeg as its encoder—the output files will then always be added with a ‘dash’ label in the names, indicating that they are intended for quick sharing uses, and are not expected to be used in serious scenarios.

这句是老版本里的,现在的这个脚本用的是 cjpegli, 不是 ffmpeg 的 mjpeg 了。
vsean
34 天前
compressimage + cn 这个域名搭配,不知道该说什么好
ltaoo1o
34 天前
@chutsetien 贴个文件链接就好了,回复越长消耗铜币数越多的,而且确实太长了。。
chutsetien
34 天前
@li1218040201 在我的个人 Wiki 上,因此不太方便贴。我真不是程序员,就是个从 DOS 一路走来的老一代电脑使用者,所以没有把这些放在 GitHub 之类的地方,自己的小站也是自娱自乐,就不献丑了 :)

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1095000

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX