5

我在Railo中使用ImageNew(及相关)创建图像,它在幕后使用JAI

当我保存图像时,我得到一个 24 位的 PNG,但我只需要 8 位。(只需使用图形编辑器将文件重新保存为 8 位,就会产生四分之一到一半的字节数。)

ImageWrite 不提供有关 PNG 位深度的任何功能,我也找不到使用 JAI 本身执行此操作的任何详细信息(获取http://jai-core.dev.java.net/的 DNS 错误)

更新:

使用Quantize ImageFilter,我可以将颜色数量减少到 256 - 这会显着减少文件大小(但仍不如手动处理),但仍会生成 24 位/未调色的 PNG 文件。不幸的是,它也消除了我需要保留(或至少重新应用)的透明度。

如果我获取这个生成的文件并通过OptiPNG(一种无损 PNG 优化器)运行它,它确实会生成索引的 8 位文件,并且会减少相当多的字节并提供可接受的文件大小。

因此,难题的剩余步骤:如何在 ImageFilter 移除透明度后重新应用透明度(或者更好的是,防止它被移除)。

我想我需要一些方法来Image.replace('white','transparent')作为基于 Railo/Java 的解决方案或跨平台命令行工具。

4

3 回答 3

2

好的,所以我有一个可以产生可接受结果的工作解决方案 - 最终文件比我原来的手动过程略小,但在视觉上无法区分。

该解决方案不像我想要的那样跨平台(需要为 OptiPNG 查找/构建 Linux 二进制文件),但它仍然是一个足够好的解决方案。

正如 Leigh 在问题评论中所建议的那样,我使用的是量化器来减少颜色,然后使用 MapColorsFilter 来修复量化器破坏透明度的事实,最后使用 OptiPNG 将生成的文件压缩到合理的大小。

以下是相关代码:

<cfscript>
    var Filename = './filename.png'
    var MyImage = NewImage(Filename)

    ImageFilter(MyImage,'quantize',{numColors:256,dither:false})

    // ImageFilter(MyImage,'MapColors',{oldColor:'white',newColor:'ffffff00'})
    var TransImage = ImageMapColors(MyImage,'white','ffffff00')

    ImageWrite( TransImage , Filename )
</cfscript>

<cfexecute
    name      = "#Variables.OptiPngExecutable#"
    arguments = "-o9 #Filename#"
    timeout   = 30
/>

Railo 的 MapColors 过滤器的 ImageFilter 目前存在一个错误,因此我必须直接访问过滤器,这是我用来解决此问题的代码:

<cffunction name="ImageMapColors" output=false >
    <cfargument name="Image" rtype="Image" required />
    <cfargument name="Old"   type="String" required />
    <cfargument name="New"   type="String" required />

    <cfset var ObjKey = 'ColorReplacer_#Arguments.Old#_#Arguments.New#' />

    <cfif NOT StructKeyExists(Variables,ObjKey)>
        <cfset var Old = createObject('java','railo.commons.color.ColorCaster').toColor(Arguments.Old) />
        <cfset var New = createObject('java','railo.commons.color.ColorCaster').toColor(Arguments.New) />
        <cfset Variables[ObjKey] = createObject("java","railo.runtime.img.filter.MapColorsFilter")
            .init(Old.getRGB(),New.getRGB()) />
    </cfif>

    <cfreturn ImageNew( Variables[ObjKey].filter(ImageGetBufferedImage(Arguments.Image),{}) ) />
</cffunction>
于 2012-09-05T23:14:30.487 回答
0

pngquant withcfexecute应该可以满足您的需求。

于 2012-09-04T18:14:55.140 回答
-1

您是否尝试过使用中间步骤首先使用 的“质量”属性ImageWrite()保存为 JPEG,然后保存为 PNG?只是一个想法。猜测使用.3.4作为价值可能有效?

于 2012-09-04T00:46:24.420 回答