static void fz_predictpng(fz_predict *p, unsigned char *in, unsigned char *out, int predictor) { int upleft[MAXC], left[MAXC], i, k; for (k = 0; k < p->bpp; k++) { left[k] = 0; upleft[k] = 0; } for (k = 0, i = 0; i < p->stride; k = (k + 1) % p->bpp, i ++) { switch (predictor) { case 0: out[i] = in[i]; break; case 1: out[i] = in[i] + left[k]; break; case 2: out[i] = in[i] + p->ref[i]; break; case 3: out[i] = in[i] + (left[k] + p->ref[i]) / 2; break; case 4: out[i] = in[i] + paeth(left[k], p->ref[i], upleft[k]); break; } left[k] = out[i]; upleft[k] = p->ref[i]; } }
void png_read_filter_row_paeth4_neon(png_row_infop row_info, png_bytep row, png_const_bytep prev_row) { png_bytep rp = row; png_bytep rp_stop = row + row_info->rowbytes; png_const_bytep pp = prev_row; uint8x8_t vlast = vdup_n_u8(0); uint8x8x4_t vdest; vdest.val[3] = vdup_n_u8(0); png_debug(1, "in png_read_filter_row_paeth4_neon"); for (; rp < rp_stop; rp += 16, pp += 16) { uint32x2x4_t vtmp; uint8x8x4_t *vrpt, *vppt; uint8x8x4_t vrp, vpp; uint32x2x4_t *temp_pointer; vtmp = vld4_u32(png_ptr(uint32_t,rp)); vrpt = png_ptr(uint8x8x4_t,&vtmp); vrp = *vrpt; vtmp = vld4_u32(png_ptrc(uint32_t,pp)); vppt = png_ptr(uint8x8x4_t,&vtmp); vpp = *vppt; vdest.val[0] = paeth(vdest.val[3], vpp.val[0], vlast); vdest.val[0] = vadd_u8(vdest.val[0], vrp.val[0]); vdest.val[1] = paeth(vdest.val[0], vpp.val[1], vpp.val[0]); vdest.val[1] = vadd_u8(vdest.val[1], vrp.val[1]); vdest.val[2] = paeth(vdest.val[1], vpp.val[2], vpp.val[1]); vdest.val[2] = vadd_u8(vdest.val[2], vrp.val[2]); vdest.val[3] = paeth(vdest.val[2], vpp.val[3], vpp.val[2]); vdest.val[3] = vadd_u8(vdest.val[3], vrp.val[3]); vlast = vpp.val[3]; vst4_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2x4_t,&vdest), 0); } }
static inline void refilter(const unsigned char* flt, const unsigned char* pre, int row_bytes, int alignment, stretchy_buffer<unsigned char>& row) { int alignmentc = alignment; switch (*flt++) { case 0: while (row_bytes--) row.append(*flt++); break; case 1: while (alignmentc--) row.append(*flt++), --row_bytes; while (row_bytes--) row.append(*flt++ + row.end()[-alignment]); break; case 2: while (row_bytes--) row.append(*flt++ + *pre++); break; case 3: while (alignmentc--) row.append(*flt++ + *pre++ / 2), --row_bytes; while (row_bytes--) row.append(*flt++ + (row.end()[-alignment] + *pre++) / 2); break; case 4: while (alignmentc--) row.append(*flt++ + *pre++), --row_bytes; while (row_bytes--) row.append(*flt++ + paeth(row.end()[-alignment], pre[0], pre[-alignment])), ++pre; break; default: throw "invalid filter type"; } }
static void png_predict(unsigned char *samples, unsigned int width, unsigned int height, unsigned int n, unsigned int depth) { unsigned int stride = (width * n * depth + 7) / 8; unsigned int bpp = (n * depth + 7) / 8; unsigned int i, row; for (row = 0; row < height; row ++) { unsigned char *src = samples + (unsigned int)((stride + 1) * row); unsigned char *dst = samples + (unsigned int)(stride * row); unsigned char *a = dst; unsigned char *b = dst - stride; unsigned char *c = dst - stride; switch (*src++) { default: case 0: /* None */ for (i = 0; i < stride; i++) *dst++ = *src++; break; case 1: /* Sub */ for (i = 0; i < bpp; i++) *dst++ = *src++; for (i = bpp; i < stride; i++) *dst++ = *src++ + *a++; break; case 2: /* Up */ if (row == 0) for (i = 0; i < stride; i++) *dst++ = *src++; else for (i = 0; i < stride; i++) *dst++ = *src++ + *b++; break; case 3: /* Average */ if (row == 0) { for (i = 0; i < bpp; i++) *dst++ = *src++; for (i = bpp; i < stride; i++) *dst++ = *src++ + (*a++ >> 1); } else { for (i = 0; i < bpp; i++) *dst++ = *src++ + (*b++ >> 1); for (i = bpp; i < stride; i++) *dst++ = *src++ + ((*b++ + *a++) >> 1); } break; case 4: /* Paeth */ if (row == 0) { for (i = 0; i < bpp; i++) *dst++ = *src++ + paeth(0, 0, 0); for (i = bpp; i < stride; i++) *dst++ = *src++ + paeth(*a++, 0, 0); } else { for (i = 0; i < bpp; i++) *dst++ = *src++ + paeth(0, *b++, 0); for (i = bpp; i < stride; i++) *dst++ = *src++ + paeth(*a++, *b++, *c++); } break; } }
void png_read_filter_row_paeth3_neon(png_row_infop row_info, png_bytep row, png_const_bytep prev_row) { png_bytep rp = row; png_const_bytep pp = prev_row; png_bytep rp_stop = row + row_info->rowbytes; uint8x16_t vtmp; uint8x8x2_t *vrpt; uint8x8x2_t vrp; uint8x8_t vlast = vdup_n_u8(0); uint8x8x4_t vdest; vdest.val[3] = vdup_n_u8(0); vtmp = vld1q_u8(rp); vrpt = png_ptr(uint8x8x2_t,&vtmp); vrp = *vrpt; png_debug(1, "in png_read_filter_row_paeth3_neon"); for (; rp < rp_stop; pp += 12) { uint8x8x2_t *vppt; uint8x8x2_t vpp; uint8x8_t vtmp1, vtmp2, vtmp3; uint32x2_t *temp_pointer; vtmp = vld1q_u8(pp); vppt = png_ptr(uint8x8x2_t,&vtmp); vpp = *vppt; vdest.val[0] = paeth(vdest.val[3], vpp.val[0], vlast); vdest.val[0] = vadd_u8(vdest.val[0], vrp.val[0]); vtmp1 = vext_u8(vrp.val[0], vrp.val[1], 3); vtmp2 = vext_u8(vpp.val[0], vpp.val[1], 3); vdest.val[1] = paeth(vdest.val[0], vtmp2, vpp.val[0]); vdest.val[1] = vadd_u8(vdest.val[1], vtmp1); vtmp1 = vext_u8(vrp.val[0], vrp.val[1], 6); vtmp3 = vext_u8(vpp.val[0], vpp.val[1], 6); vdest.val[2] = paeth(vdest.val[1], vtmp3, vtmp2); vdest.val[2] = vadd_u8(vdest.val[2], vtmp1); vtmp1 = vext_u8(vrp.val[1], vrp.val[1], 1); vtmp2 = vext_u8(vpp.val[1], vpp.val[1], 1); vtmp = vld1q_u8(rp + 12); vrpt = png_ptr(uint8x8x2_t,&vtmp); vrp = *vrpt; vdest.val[3] = paeth(vdest.val[2], vtmp2, vtmp3); vdest.val[3] = vadd_u8(vdest.val[3], vtmp1); vlast = vtmp2; vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[0]), 0); rp += 3; vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[1]), 0); rp += 3; vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[2]), 0); rp += 3; vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[3]), 0); rp += 3; } }
static int png_reverse_filter_copy_line(uint32_t *data, const struct png_ihdr *ihdr, struct rpng_process_t *pngp, unsigned filter) { unsigned i; switch (filter) { case PNG_FILTER_NONE: memcpy(pngp->decoded_scanline, pngp->inflate_buf, pngp->pitch); break; case PNG_FILTER_SUB: for (i = 0; i < pngp->bpp; i++) pngp->decoded_scanline[i] = pngp->inflate_buf[i]; for (i = pngp->bpp; i < pngp->pitch; i++) pngp->decoded_scanline[i] = pngp->decoded_scanline[i - pngp->bpp] + pngp->inflate_buf[i]; break; case PNG_FILTER_UP: for (i = 0; i < pngp->pitch; i++) pngp->decoded_scanline[i] = pngp->prev_scanline[i] + pngp->inflate_buf[i]; break; case PNG_FILTER_AVERAGE: for (i = 0; i < pngp->bpp; i++) { uint8_t avg = pngp->prev_scanline[i] >> 1; pngp->decoded_scanline[i] = avg + pngp->inflate_buf[i]; } for (i = pngp->bpp; i < pngp->pitch; i++) { uint8_t avg = (pngp->decoded_scanline[i - pngp->bpp] + pngp->prev_scanline[i]) >> 1; pngp->decoded_scanline[i] = avg + pngp->inflate_buf[i]; } break; case PNG_FILTER_PAETH: for (i = 0; i < pngp->bpp; i++) pngp->decoded_scanline[i] = paeth(0, pngp->prev_scanline[i], 0) + pngp->inflate_buf[i]; for (i = pngp->bpp; i < pngp->pitch; i++) pngp->decoded_scanline[i] = paeth(pngp->decoded_scanline[i - pngp->bpp], pngp->prev_scanline[i], pngp->prev_scanline[i - pngp->bpp]) + pngp->inflate_buf[i]; break; default: return PNG_PROCESS_ERROR_END; } switch (ihdr->color_type) { case PNG_IHDR_COLOR_GRAY: png_reverse_filter_copy_line_bw(data, pngp->decoded_scanline, ihdr->width, ihdr->depth); break; case PNG_IHDR_COLOR_RGB: png_reverse_filter_copy_line_rgb(data, pngp->decoded_scanline, ihdr->width, ihdr->depth); break; case PNG_IHDR_COLOR_PLT: png_reverse_filter_copy_line_plt(data, pngp->decoded_scanline, ihdr->width, ihdr->depth, pngp->palette); break; case PNG_IHDR_COLOR_GRAY_ALPHA: png_reverse_filter_copy_line_gray_alpha(data, pngp->decoded_scanline, ihdr->width, ihdr->depth); break; case PNG_IHDR_COLOR_RGBA: png_reverse_filter_copy_line_rgba(data, pngp->decoded_scanline, ihdr->width, ihdr->depth); break; } memcpy(pngp->prev_scanline, pngp->decoded_scanline, pngp->pitch); return PNG_PROCESS_NEXT; }
inline T strange( T a, T b, T c ){ if( a < b && b < c ) return paeth( a, b, c ); else return a + b - c; }
static bool png_reverse_filter(uint32_t *data, const struct png_ihdr *ihdr, const uint8_t *inflate_buf, size_t inflate_buf_size, const uint32_t *palette) { unsigned i, h; bool ret = true; unsigned bpp; unsigned pitch; size_t pass_size; png_pass_geom(ihdr, ihdr->width, ihdr->height, &bpp, &pitch, &pass_size); if (inflate_buf_size < pass_size) return false; uint8_t *prev_scanline = (uint8_t*)calloc(1, pitch); uint8_t *decoded_scanline = (uint8_t*)calloc(1, pitch); if (!prev_scanline || !decoded_scanline) GOTO_END_ERROR(); for (h = 0; h < ihdr->height; h++, inflate_buf += pitch, data += ihdr->width) { unsigned filter = *inflate_buf++; switch (filter) { case 0: // None memcpy(decoded_scanline, inflate_buf, pitch); break; case 1: // Sub for (i = 0; i < bpp; i++) decoded_scanline[i] = inflate_buf[i]; for (i = bpp; i < pitch; i++) decoded_scanline[i] = decoded_scanline[i - bpp] + inflate_buf[i]; break; case 2: // Up for (i = 0; i < pitch; i++) decoded_scanline[i] = prev_scanline[i] + inflate_buf[i]; break; case 3: // Average for (i = 0; i < bpp; i++) { uint8_t avg = prev_scanline[i] >> 1; decoded_scanline[i] = avg + inflate_buf[i]; } for (i = bpp; i < pitch; i++) { uint8_t avg = (decoded_scanline[i - bpp] + prev_scanline[i]) >> 1; decoded_scanline[i] = avg + inflate_buf[i]; } break; case 4: // Paeth for (i = 0; i < bpp; i++) decoded_scanline[i] = paeth(0, prev_scanline[i], 0) + inflate_buf[i]; for (i = bpp; i < pitch; i++) decoded_scanline[i] = paeth(decoded_scanline[i - bpp], prev_scanline[i], prev_scanline[i - bpp]) + inflate_buf[i]; break; default: GOTO_END_ERROR(); } if (ihdr->color_type == 0) copy_line_bw(data, decoded_scanline, ihdr->width, ihdr->depth); else if (ihdr->color_type == 2) copy_line_rgb(data, decoded_scanline, ihdr->width, ihdr->depth); else if (ihdr->color_type == 3) copy_line_plt(data, decoded_scanline, ihdr->width, ihdr->depth, palette); else if (ihdr->color_type == 4) copy_line_gray_alpha(data, decoded_scanline, ihdr->width, ihdr->depth); else if (ihdr->color_type == 6) copy_line_rgba(data, decoded_scanline, ihdr->width, ihdr->depth); memcpy(prev_scanline, decoded_scanline, pitch); } end: free(decoded_scanline); free(prev_scanline); return ret; }