| // Copyright 2012 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package png |
| |
| // intSize is either 32 or 64. |
| const intSize = 32 << (^uint(0) >> 63) |
| |
| func abs(x int) int { |
| // m := -1 if x < 0. m := 0 otherwise. |
| m := x >> (intSize - 1) |
| |
| // In two's complement representation, the negative number |
| // of any number (except the smallest one) can be computed |
| // by flipping all the bits and add 1. This is faster than |
| // code with a branch. |
| // See Hacker's Delight, section 2-4. |
| return (x ^ m) - m |
| } |
| |
| // paeth implements the Paeth filter function, as per the PNG specification. |
| func paeth(a, b, c uint8) uint8 { |
| // This is an optimized version of the sample code in the PNG spec. |
| // For example, the sample code starts with: |
| // p := int(a) + int(b) - int(c) |
| // pa := abs(p - int(a)) |
| // but the optimized form uses fewer arithmetic operations: |
| // pa := int(b) - int(c) |
| // pa = abs(pa) |
| pc := int(c) |
| pa := int(b) - pc |
| pb := int(a) - pc |
| pc = abs(pa + pb) |
| pa = abs(pa) |
| pb = abs(pb) |
| if pa <= pb && pa <= pc { |
| return a |
| } else if pb <= pc { |
| return b |
| } |
| return c |
| } |
| |
| // filterPaeth applies the Paeth filter to the cdat slice. |
| // cdat is the current row's data, pdat is the previous row's data. |
| func filterPaeth(cdat, pdat []byte, bytesPerPixel int) { |
| var a, b, c, pa, pb, pc int |
| for i := 0; i < bytesPerPixel; i++ { |
| a, c = 0, 0 |
| for j := i; j < len(cdat); j += bytesPerPixel { |
| b = int(pdat[j]) |
| pa = b - c |
| pb = a - c |
| pc = abs(pa + pb) |
| pa = abs(pa) |
| pb = abs(pb) |
| if pa <= pb && pa <= pc { |
| // No-op. |
| } else if pb <= pc { |
| a = b |
| } else { |
| a = c |
| } |
| a += int(cdat[j]) |
| a &= 0xff |
| cdat[j] = uint8(a) |
| c = b |
| } |
| } |
| } |