How to save / convert 24-bit PNG as 8-bit PNG?

I create images using ImageNew (and related) in Railo , which uses JAI under covers.

When I save the image, I get 24-bit PNG, but I only need 8-bit. (Just re-saving the file with an 8-bit graphics editor results in half as few bytes.)

ImageWrite does not offer any functionality regarding PNG bit depth, and I cannot find any details about this with JAI itself (getting a DNS error for <a3> )

Update:

Using Quantize ImageFilter, I can reduce the number of colors to 256 - this significantly reduces the file size (but still not processed manually), but still leads to a 24-bit / unallocated PNG file. Unfortunately, it also removes the transparency I need to maintain (or at least reapply.)

If I take a file, it creates and runs it through OptiPNG (PNG lossless optimizer), it produces an indexed 8-bit file and discards quite a few bytes and gives acceptable files.

So, the rest of the puzzle: how to reapply transparency after ImageFilter has removed it (or, better, without deleting it).

I guess I need to somehow do Image.replace('white','transparent')either as a Railo / Java solution or for a cross-platform command line tool.

+5
source share
3 answers

Ok, so I have a working solution that gives acceptable results - the final files are slightly smaller than my initial manual process, but visually indistinguishable.

The solution is not as cross-platform as we would like (you need to find / create a Linux binary for OptiPNG), but it is still a good enough solution.

, , , 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 ImageFilter MapColors, , , :

<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>
+2

pngquant cfexecute .

0

JPEG, "" ImageWrite(), PNG? . .3 .4, ?

-1

All Articles