Topic: Lossy PNG compression

Image Analyzer has the best lossy PNG compression I've ever seen. The only downside is, I need to boot Windows to use it.

Would you allow me to port the lossy PNG compressor to Linux, as a command line tool? I am an experienced programmer and could probably do it in a few days.

We could distribute it however you want, open source, closed source; your website, my website, whatever. I just want to use it.

2

Re: Lossy PNG compression

Hi
IA is in general not Open source, but I don't mind giving this specific part away.
Basically the lossy compression is done by a filtering of the image fore the actual compression, where the filtering modifies the pixels to be better suited for the specific compression scheme used in PNG. The filtering algorithm looks like this:

function OptimizeForPNG(Image: TLinearBitmap; QuantizationSteps: Integer; TransparentColor: TColor=-1): Integer;
var
  X, Y, P, I : Integer;
  Line, LastLine : PByteArray;
  BPP, HalfStep : Integer;
  NewPal : TPalette;
  ColorMap : TColorMap;
  XModBPP, NewValue : Integer;
begin
  if Image.PixelFormat=pf8bit then
  begin
    if not Image.IsGrayScale then // Palette image
    begin
      // Create new palette
      SortPalette(Image.Palette^,ColorMap);
      if InRange(TransparentColor,0,255) then
      begin
        I:=TransparentColor;
        for X:=0 to 255 do if ColorMap.Map[X]=TransparentColor then
        begin
          I:=X;
          Break;
        end;
        ColorMap.Map[i]:=ColorMap.Map[TransparentColor];
        ColorMap.Map[TransparentColor]:=TransparentColor;
      end;

      // Apply palette changes
      for I:=0 to 255 do NewPal[ColorMap.Map[i]]:=Image.Palette^[i];
      ColorMap.Apply(Image);
      Image.Palette^:=NewPal;

      // Optimize for Paeth filtering
      LastLine:=Image.Map;
      for Y:=1 to Image.Height-1 do
      begin
        Line:=Image.ScanLine[Y];
        for X:=1 to Image.BytesPerLine-1 do
        begin
          if (Line^[X]=TransparentColor) and (TransparentColor<>-1) then Continue; // Transparent
          P:=PaethPredictor(Line^[X-1],LastLine^[X],LastLine^[X-1]); // Paeth filter
          if (ColorDiff(NewPal[P],NewPal[Line^[X]])<QuantizationSteps) and (P<>TransparentColor) then Line^[X]:=P;
        end;
        LastLine:=Line;
      end;
      Result:=slfPaeth;
      Exit;
    end;
    BPP:=1;
  end
  else BPP:=3;
  // 24 bit or grayscale, optimize for average filter
  HalfStep:=(QuantizationSteps+1) div 2;
  LastLine:=Image.Map;
  XModBPP:=0;
  for Y:=1 to Image.Height-1 do
  begin
    Line:=Image.ScanLine[Y];
    for X:=BPP to Image.BytesPerLine-1 do
    begin
      if TransparentColor<>-1 then // Dont't change transparent pixels
      begin
         if BPP=1 then
         begin
           if Line^[X]=TransparentColor then Continue;
         end
         else
         begin
           XModBPP:=X mod 3;
           if PInteger(@Line^[X-XModBPP])^ and $ffffff=TransparentColor then Continue;
         end;
      end;

      P:=(Word(Line^[X-BPP])+LastLine^[X]) div 2; // Average filter
      if Abs(P-Line^[X])<=QuantizationSteps then NewValue:=P
      else
      begin
        I:=Byte(Line^[X]-P) mod QuantizationSteps;
        if I<HalfStep then NewValue:=Max(Line^[X]-I,0)
        else NewValue:=Min(Line^[X]+QuantizationSteps-I,255);
      end;

       // Dont't change pixel to transparent color key
      if TransparentColor=-1 then Line^[X]:=NewValue
      else if BPP=1 then
      begin
        if NewValue<>TransparentColor then Line^[X]:=NewValue;
      end
      else // BPP=3, TransparentColor<>-1
      begin
        Line^[X]:=NewValue;
        if (XModBPP=2) and (PInteger(@Line^[X-2])^ and $ffffff=TransparentColor) then Line^[X]:=NewValue xor 1;
      end;
    end;
    LastLine:=Line;
  end;
  Result:=slfAverage;
end;

function PaethPredictor(a,b,c: Byte): Byte;
var
  p, pa, pb, pc : Integer;
begin
   // a = left, b = above, c = upper left
   p:=a+b-c;         // Initial estimate
   pa:=abs(p-a);     // Distances to a, b, c
   pb:=abs(p-b);
   pc:=abs(p-c);
   // Return nearest of a,b,c, breaking ties in order a,b,c.
   if (pa<=pb) and (pa<=pc) then Result:=a
   else if pb<=pc then Result:=b
   else Result:=c;
end;

You are welcome to create a command line tool that uses this.

Michael Vinther

> software developer <

Re: Lossy PNG compression

Thanks! It's a lot simpler than I thought it would be. I'll put it on Github with credit to you and post again when it's done.

Re: Lossy PNG compression

My command-line lossy PNG compressor is up on github now. I still have to write documentation but it works well. Unlike your code, my version will alter transparent pixels. I would like to add recognition of transparent colors later but for my initial version I wanted to keep it simple.

https://github.com/foobaz/lossypng/

5 (edited by apple78 2013-07-17 10:20:41)

Re: Lossy PNG compression

hi there,

quick searching on Google brings me here.and Im currently working on image compression ,does fithub provide any codes written in .Net? If yes ,Plz give me some detail guide,thx in adv.It would be greatly appreciated if someone can provide me free open source regarding image processing.Btw, Im doing it with my windows project. any suggestion?