public PNG_INFO png_get_bKGD(ref png_color_16 background) { if ((info_ptr_valid & PNG_INFO.bKGD) != PNG_INFO.bKGD) { return(PNG_INFO.None); } background = info_ptr_background; return(PNG_INFO.bKGD); }
public PNG_INFO png_get_tRNS(ref byte[] trans_alpha, ref ushort num_trans, ref png_color_16 trans_color) { if ((info_ptr_valid & PNG_INFO.tRNS) != PNG_INFO.tRNS) { return(PNG_INFO.None); } trans_color = info_ptr_trans_color; trans_alpha = (info_ptr_color_type == PNG_COLOR_TYPE.PALETTE)?info_ptr_trans_alpha:null; num_trans = info_ptr_num_trans; return(PNG_INFO.tRNS); }
public void png_set_tRNS(png_color_16 trans_color) { int sample_max = (1 << info_ptr_bit_depth); if ((info_ptr_color_type == PNG_COLOR_TYPE.GRAY && (int)trans_color.gray > sample_max) || (info_ptr_color_type == PNG_COLOR_TYPE.RGB && ((int)trans_color.red > sample_max || (int)trans_color.green > sample_max || (int)trans_color.blue > sample_max))) { Debug.WriteLine("tRNS chunk has out-of-range samples for bit_depth"); } this.trans_color = info_ptr_trans_color = trans_color; num_trans = info_ptr_num_trans = 1; info_ptr_valid |= PNG_INFO.tRNS; }
public PNG_INFO png_get_tRNS(ref byte[] trans_alpha, ref ushort num_trans, ref png_color_16 trans_color) { if((info_ptr_valid&PNG_INFO.tRNS)!=PNG_INFO.tRNS) return PNG_INFO.None; trans_color=info_ptr_trans_color; trans_alpha=(info_ptr_color_type==PNG_COLOR_TYPE.PALETTE)?info_ptr_trans_alpha:null; num_trans=info_ptr_num_trans; return PNG_INFO.tRNS; }
public PNG_INFO png_get_bKGD(ref png_color_16 background) { if((info_ptr_valid&PNG_INFO.bKGD)!=PNG_INFO.bKGD) return PNG_INFO.None; background=info_ptr_background; return PNG_INFO.bKGD; }
void png_handle_bKGD(uint length) { if((mode&PNG_MODE.HAVE_IHDR)!=PNG_MODE.HAVE_IHDR) throw new PNG_Exception("Missing IHDR before bKGD"); else if((mode&PNG_MODE.HAVE_IDAT)==PNG_MODE.HAVE_IDAT) { Debug.WriteLine("Invalid bKGD after IDAT"); png_crc_finish(length); return; } else if(color_type==PNG_COLOR_TYPE.PALETTE&&!((mode&PNG_MODE.HAVE_PLTE)==PNG_MODE.HAVE_PLTE)) { Debug.WriteLine("Missing PLTE before bKGD"); png_crc_finish(length); return; } else if((info_ptr_valid&PNG_INFO.bKGD)==PNG_INFO.bKGD) { Debug.WriteLine("Duplicate bKGD chunk"); png_crc_finish(length); return; } uint truelen=2; if(color_type==PNG_COLOR_TYPE.PALETTE) truelen=1; else if((color_type&PNG_COLOR_TYPE.COLOR_MASK)==PNG_COLOR_TYPE.COLOR_MASK) truelen=6; if(length!=truelen) { Debug.WriteLine("Incorrect bKGD chunk length"); png_crc_finish(length); return; } byte[] buf=new byte[truelen]; png_crc_read(buf, truelen); if(png_crc_finish(0)) return; png_color_16 background=new png_color_16(); // We convert the index value into RGB components so that we can allow // arbitrary RGB values for background when we have transparency, and // so it is easy to determine the RGB values of the background color // from the info_ptr struct. if(color_type==PNG_COLOR_TYPE.PALETTE) { background.index=buf[0]; if(info_ptr_palette.Length!=0) { if(buf[0]>info_ptr_palette.Length) { Debug.WriteLine("Incorrect bKGD chunk index value"); return; } background.red=(ushort)palette[buf[0]].red; background.green=(ushort)palette[buf[0]].green; background.blue=(ushort)palette[buf[0]].blue; } } else if((color_type&PNG_COLOR_TYPE.COLOR_MASK)!=PNG_COLOR_TYPE.COLOR_MASK) { background.red=background.green=background.blue=background.gray=png_get_uint_16(buf); } else { background.red=png_get_uint_16(buf); background.green=png_get_uint_16(buf, 2); background.blue=png_get_uint_16(buf, 4); } png_set_bKGD(background); }
void png_handle_tRNS(uint length) { if((mode&PNG_MODE.HAVE_IHDR)!=PNG_MODE.HAVE_IHDR) throw new PNG_Exception("Missing IHDR before tRNS"); else if((mode&PNG_MODE.HAVE_IDAT)==PNG_MODE.HAVE_IDAT) { Debug.WriteLine("Invalid tRNS after IDAT"); png_crc_finish(length); return; } else if((info_ptr_valid&PNG_INFO.tRNS)==PNG_INFO.tRNS) { Debug.WriteLine("Duplicate tRNS chunk"); png_crc_finish(length); return; } trans_color=new png_color_16(); if(color_type==PNG_COLOR_TYPE.GRAY) { if(length!=2) { Debug.WriteLine("Incorrect tRNS chunk length"); png_crc_finish(length); return; } png_crc_read(buf4, 2); if(png_crc_finish(0)) return; num_trans=1; trans_color.gray=png_get_uint_16(buf4); png_set_tRNS(trans_color); } else if(color_type==PNG_COLOR_TYPE.RGB) { if(length!=6) { Debug.WriteLine("Incorrect tRNS chunk length"); png_crc_finish(length); return; } byte[] buf=new byte[6]; png_crc_read(buf, 6); if(png_crc_finish(0)) return; num_trans=1; trans_color.red=png_get_uint_16(buf); trans_color.green=png_get_uint_16(buf, 2); trans_color.blue=png_get_uint_16(buf, 4); png_set_tRNS(trans_color); } else if(color_type==PNG_COLOR_TYPE.PALETTE) { if(!((mode&PNG_MODE.HAVE_PLTE)==PNG_MODE.HAVE_PLTE)) Debug.WriteLine("Missing PLTE before tRNS"); // Should be an error, but we can cope with it. if(length>palette.Length||length>PNG.MAX_PALETTE_LENGTH) { Debug.WriteLine("Incorrect tRNS chunk length"); png_crc_finish(length); return; } if(length==0) { Debug.WriteLine("Zero length tRNS chunk"); png_crc_finish(length); return; } byte[] readbuf=new byte[length]; png_crc_read(readbuf, length); if(png_crc_finish(0)) return; num_trans=(ushort)length; png_set_tRNS(readbuf); } else { Debug.WriteLine("tRNS chunk not allowed with alpha channel"); png_crc_finish(length); num_trans=0; } }
public void png_set_bKGD(png_color_16 background) { info_ptr_background = background; info_ptr_valid |= PNG_INFO.bKGD; }
public void png_set_tRNS(png_color_16 trans_color) { int sample_max=(1<<info_ptr_bit_depth); if((info_ptr_color_type==PNG_COLOR_TYPE.GRAY&& (int)trans_color.gray>sample_max)|| (info_ptr_color_type==PNG_COLOR_TYPE.RGB&& ((int)trans_color.red>sample_max|| (int)trans_color.green>sample_max|| (int)trans_color.blue>sample_max))) Debug.WriteLine("tRNS chunk has out-of-range samples for bit_depth"); this.trans_color=info_ptr_trans_color=trans_color; num_trans=info_ptr_num_trans=1; info_ptr_valid|=PNG_INFO.tRNS; }
public void png_set_bKGD(png_color_16 background) { info_ptr_background=background; info_ptr_valid|=PNG_INFO.bKGD; }
// write the background chunk void png_write_bKGD(png_color_16 back, PNG_COLOR_TYPE color_type) { byte[] buf=new byte[6]; if(color_type==PNG_COLOR_TYPE.PALETTE) { uint num_palette=0; if(palette!=null) num_palette=(uint)palette.Length; if((num_palette!=0||(mng_features_permitted&PNG_FLAG_MNG.EMPTY_PLTE)!=PNG_FLAG_MNG.EMPTY_PLTE)&&back.index>=num_palette) { Debug.WriteLine("Invalid background palette index"); return; } buf[0]=back.index; png_write_chunk(PNG.bKGD, buf, 1); } else if((color_type&PNG_COLOR_TYPE.COLOR_MASK)==PNG_COLOR_TYPE.COLOR_MASK) { png_save_uint_16(buf, back.red); png_save_uint_16(buf, 2, back.green); png_save_uint_16(buf, 4, back.blue); if(bit_depth==8&&(buf[0]|buf[2]|buf[4])!=0) { Debug.WriteLine("Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8"); return; } png_write_chunk(PNG.bKGD, buf, 6); } else { if(back.gray>=(1<<bit_depth)) { Debug.WriteLine("Ignoring attempt to write bKGD chunk out-of-range for bit_depth"); return; } png_save_uint_16(buf, back.gray); png_write_chunk(PNG.bKGD, buf, 2); } }
// write the tRNS chunk void png_write_tRNS(byte[] trans_alpha, png_color_16 tran, int num_trans, PNG_COLOR_TYPE color_type) { byte[] buf=new byte[6]; if(color_type==PNG_COLOR_TYPE.PALETTE) { if(num_trans<=0||num_trans>palette.Length) { Debug.WriteLine("Invalid number of transparent colors specified"); return; } // write the chunk out as it is png_write_chunk(PNG.tRNS, trans_alpha, (uint)num_trans); } else if(color_type==PNG_COLOR_TYPE.GRAY) { // one 16 bit value if(tran.gray>=(1<<bit_depth)) { Debug.WriteLine("Ignoring attempt to write tRNS chunk out-of-range for bit_depth"); return; } png_save_uint_16(buf, tran.gray); png_write_chunk(PNG.tRNS, buf, 2); } else if(color_type==PNG_COLOR_TYPE.RGB) { // three 16 bit values png_save_uint_16(buf, tran.red); png_save_uint_16(buf, 2, tran.green); png_save_uint_16(buf, 4, tran.blue); if(bit_depth==8&&(buf[0]|buf[2]|buf[4])!=0) { Debug.WriteLine("Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8"); return; } png_write_chunk(PNG.tRNS, buf, 6); } else Debug.WriteLine("Can't write tRNS with an alpha channel"); }
// If the bit depth < 8, it is expanded to 8. Also, if the already // expanded transparency value is supplied, an alpha channel is built. static unsafe void png_do_expand_with_trans_values(ref png_row_info row_info, byte[] row, ref png_color_16 trans_value) { int shift, value; uint row_width=row_info.width; fixed(byte* row_=row) { byte* sp=row_+1; // skip filter value byte* dp=row_+1; // skip filter value if(row_info.color_type==PNG_COLOR_TYPE.GRAY) { ushort gray=trans_value.gray; if(row_info.bit_depth<8) { switch(row_info.bit_depth) { case 1: { gray=(ushort)((gray&0x01)*0xff); sp+=(row_width-1)>>3; dp+=row_width-1; shift=7-(int)((row_width+7)&0x07); for(uint i=0; i<row_width; i++) { if(((*sp>>shift)&0x01)==0x01) *dp=0xff; else *dp=0; if(shift==7) { shift=0; sp--; } else shift++; dp--; } } break; case 2: { gray=(ushort)((gray&0x03)*0x55); sp+=(row_width-1)>>2; dp+=row_width-1; shift=(int)((3-((row_width+3)&0x03))<<1); for(uint i=0; i<row_width; i++) { value=(*sp>>shift)&0x03; *dp=(byte)(value|(value<<2)|(value<<4)|(value<<6)); if(shift==6) { shift=0; sp--; } else shift+=2; dp--; } } break; case 4: { gray=(ushort)((gray&0x0f)*0x11); sp+=(row_width-1)>>1; dp+=row_width-1; shift=(int)((1-((row_width+1)&0x01))<<2); for(uint i=0; i<row_width; i++) { value=(*sp>>shift)&0x0f; *dp=(byte)(value|(value<<4)); if(shift==4) { shift=0; sp--; } else shift=4; dp--; } } break; } row_info.bit_depth=8; row_info.pixel_depth=8; row_info.rowbytes=row_width; // reset to start values sp=row_+1; // skip filter value dp=row_+1; // skip filter value } // if(row_info.bit_depth<8) if(row_info.bit_depth==8) { gray=(byte)(gray&0xff); sp+=row_width-1; dp+=(row_width<<1)-1; for(uint i=0; i<row_width; i++) { if(*sp==gray) *dp--=0; else *dp--=0xff; *dp--=*sp--; } } else if(row_info.bit_depth==16) { byte gray_high=(byte)((gray>>8)&0xff); byte gray_low=(byte)(gray&0xff); sp+=row_info.rowbytes-1; dp+=(row_info.rowbytes<<1)-1; for(uint i=0; i<row_width; i++) { if(*(sp-1)==gray_high&&*(sp)==gray_low) { *dp--=0; *dp--=0; } else { *dp--=0xff; *dp--=0xff; } *dp--=*sp--; *dp--=*sp--; } } row_info.color_type=PNG_COLOR_TYPE.GRAY_ALPHA; row_info.channels=2; row_info.pixel_depth=(byte)(row_info.bit_depth<<1); row_info.rowbytes=PNG_ROWBYTES(row_info.pixel_depth, row_width); } else if(row_info.color_type==PNG_COLOR_TYPE.RGB) { if(row_info.bit_depth==8) { byte red=(byte)(trans_value.red&0xff); byte green=(byte)(trans_value.green&0xff); byte blue=(byte)(trans_value.blue&0xff); sp+=row_info.rowbytes-1; dp+=(row_width<<2)-1; for(uint i=0; i<row_width; i++) { if(*(sp-2)==red&&*(sp-1)==green&&*(sp)==blue) *dp--=0; else *dp--=0xff; *dp--=*sp--; *dp--=*sp--; *dp--=*sp--; } } else if(row_info.bit_depth==16) { byte red_high=(byte)((trans_value.red>>8)&0xff); byte green_high=(byte)((trans_value.green>>8)&0xff); byte blue_high=(byte)((trans_value.blue>>8)&0xff); byte red_low=(byte)(trans_value.red&0xff); byte green_low=(byte)(trans_value.green&0xff); byte blue_low=(byte)(trans_value.blue&0xff); sp+=row_info.rowbytes-1; dp+=(row_width<<3)-1; for(uint i=0; i<row_width; i++) { if(*(sp-5)==red_high&&*(sp-4)==red_low&&*(sp-3)==green_high&&*(sp-2)==green_low&&*(sp-1)==blue_high&&*(sp)==blue_low) { *dp--=0; *dp--=0; } else { *dp--=0xff; *dp--=0xff; } *dp--=*sp--; *dp--=*sp--; *dp--=*sp--; *dp--=*sp--; *dp--=*sp--; *dp--=*sp--; } } row_info.color_type=PNG_COLOR_TYPE.RGB_ALPHA; row_info.channels=4; row_info.pixel_depth=(byte)(row_info.bit_depth<<2); row_info.rowbytes=PNG_ROWBYTES(row_info.pixel_depth, row_width); } } }
// Replace any alpha or transparency with the supplied background color. // "background" is already in the screen gamma, while "background_1" is // at a gamma of 1.0. Paletted files have already been taken care of. static unsafe void png_do_background(ref png_row_info row_info, byte[] row, ref png_color_16 trans_color, ref png_color_16 background, ref png_color_16 background_1, byte[] gamma_table, byte[] gamma_from_1, byte[] gamma_to_1, ushort[][] gamma_16, ushort[][] gamma_16_from_1, ushort[][] gamma_16_to_1, int gamma_shift) { uint i; uint row_width=row_info.width; int shift; if(!((row_info.color_type&PNG_COLOR_TYPE.ALPHA_MASK)!=PNG_COLOR_TYPE.ALPHA_MASK|| row_info.color_type!=PNG_COLOR_TYPE.PALETTE)) return; fixed(byte* row_=row) { byte* sp=row_+1; // skip filter value byte* dp=row_+1; // skip filter value switch(row_info.color_type) { case PNG_COLOR_TYPE.GRAY: { switch(row_info.bit_depth) { case 1: { shift=7; for(i=0; i<row_width; i++) { if((ushort)((*sp>>shift)&0x01)==trans_color.gray) { *sp&=(byte)((0x7f7f>>(7-shift))&0xff); *sp|=(byte)(background.gray<<shift); } if(shift==0) { shift=7; sp++; } else shift--; } } break; case 2: { shift=6; if(gamma_table!=null) { for(i=0; i<row_width; i++) { if((ushort)((*sp>>shift)&0x03)==trans_color.gray) { *sp&=(byte)((0x3f3f>>(6-shift))&0xff); *sp|=(byte)(background.gray<<shift); } else { byte p=(byte)((*sp>>shift)&0x03); byte g=(byte)((gamma_table[p|(p<<2)|(p<<4)|(p<<6)]>>6)&0x03); *sp&=(byte)((0x3f3f>>(6-shift))&0xff); *sp|=(byte)(g<<shift); } if(shift==0) { shift=6; sp++; } else shift-=2; } } else { for(i=0; i<row_width; i++) { if((ushort)((*sp>>shift)&0x03)==trans_color.gray) { *sp&=(byte)((0x3f3f>>(6-shift))&0xff); *sp|=(byte)(background.gray<<shift); } if(shift==0) { shift=6; sp++; } else shift-=2; } } } break; case 4: { shift=4; if(gamma_table!=null) { for(i=0; i<row_width; i++) { if((ushort)((*sp>>shift)&0x0f)==trans_color.gray) { *sp&=(byte)((0xf0f>>(4-shift))&0xff); *sp|=(byte)(background.gray<<shift); } else { byte p=(byte)((*sp>>shift)&0x0f); byte g=(byte)((gamma_table[p|(p<<4)]>>4)&0x0f); *sp&=(byte)((0xf0f>>(4-shift))&0xff); *sp|=(byte)(g<<shift); } if(shift==0) { shift=4; sp++; } else shift-=4; } } else { for(i=0; i<row_width; i++) { if((ushort)((*sp>>shift)&0x0f)==trans_color.gray) { *sp&=(byte)((0xf0f>>(4-shift))&0xff); *sp|=(byte)(background.gray<<shift); } if(shift==0) { shift=4; sp++; } else shift-=4; } } } break; case 8: { if(gamma_table!=null) { for(i=0; i<row_width; i++, sp++) { if(*sp==trans_color.gray) *sp=(byte)background.gray; else *sp=gamma_table[*sp]; } } else { for(i=0; i<row_width; i++, sp++) { if(*sp==trans_color.gray) *sp=(byte)background.gray; } } break; } case 16: { if(gamma_16!=null) { for(i=0; i<row_width; i++, sp+=2) { ushort v=(ushort)(((*sp)<<8)+*(sp+1)); if(v==trans_color.gray) { // background is already in screen gamma *sp=(byte)((background.gray>>8)&0xff); *(sp+1)=(byte)(background.gray&0xff); } else { v=gamma_16[*(sp+1)>>gamma_shift][*sp]; *sp=(byte)((v>>8)&0xff); *(sp+1)=(byte)(v&0xff); } } } else { for(i=0; i<row_width; i++, sp+=2) { ushort v=(ushort)(((*sp)<<8)+*(sp+1)); if(v==trans_color.gray) { *sp=(byte)((background.gray>>8)&0xff); *(sp+1)=(byte)(background.gray&0xff); } } } } break; } // switch(row_info->bit_depth) } break; case PNG_COLOR_TYPE.RGB: { if(row_info.bit_depth==8) { if(gamma_table!=null) { for(i=0; i<row_width; i++, sp+=3) { if(*sp==trans_color.red&&*(sp+1)==trans_color.green&&*(sp+2)==trans_color.blue) { *sp=(byte)background.red; *(sp+1)=(byte)background.green; *(sp+2)=(byte)background.blue; } else { *sp=gamma_table[*sp]; *(sp+1)=gamma_table[*(sp+1)]; *(sp+2)=gamma_table[*(sp+2)]; } } } else { for(i=0; i<row_width; i++, sp+=3) { if(*sp==trans_color.red&&*(sp+1)==trans_color.green&&*(sp+2)==trans_color.blue) { *sp=(byte)background.red; *(sp+1)=(byte)background.green; *(sp+2)=(byte)background.blue; } } } } else // if(row_info->bit_depth==16) { if(gamma_16!=null) { for(i=0; i<row_width; i++, sp+=6) { ushort r=(ushort)(((*sp)<<8)+*(sp+1)); ushort g=(ushort)(((*(sp+2))<<8)+*(sp+3)); ushort b=(ushort)(((*(sp+4))<<8)+*(sp+5)); if(r==trans_color.red&&g==trans_color.green&&b==trans_color.blue) { // background is already in screen gamma *sp=(byte)((background.red>>8)&0xff); *(sp+1)=(byte)(background.red&0xff); *(sp+2)=(byte)((background.green>>8)&0xff); *(sp+3)=(byte)(background.green&0xff); *(sp+4)=(byte)((background.blue>>8)&0xff); *(sp+5)=(byte)(background.blue&0xff); } else { ushort v=gamma_16[*(sp+1)>>gamma_shift][*sp]; *sp=(byte)((v>>8)&0xff); *(sp+1)=(byte)(v&0xff); v=gamma_16[*(sp+3)>>gamma_shift][*(sp+2)]; *(sp+2)=(byte)((v>>8)&0xff); *(sp+3)=(byte)(v&0xff); v=gamma_16[*(sp+5)>>gamma_shift][*(sp+4)]; *(sp+4)=(byte)((v>>8)&0xff); *(sp+5)=(byte)(v&0xff); } } } else { for(i=0; i<row_width; i++, sp+=6) { ushort r=(ushort)(((*sp)<<8)+*(sp+1)); ushort g=(ushort)(((*(sp+2))<<8)+*(sp+3)); ushort b=(ushort)(((*(sp+4))<<8)+*(sp+5)); if(r==trans_color.red&&g==trans_color.green&&b==trans_color.blue) { *sp=(byte)((background.red>>8)&0xff); *(sp+1)=(byte)(background.red&0xff); *(sp+2)=(byte)((background.green>>8)&0xff); *(sp+3)=(byte)(background.green&0xff); *(sp+4)=(byte)((background.blue>>8)&0xff); *(sp+5)=(byte)(background.blue&0xff); } } } } } break; case PNG_COLOR_TYPE.GRAY_ALPHA: { if(row_info.bit_depth==8) { if(gamma_to_1!=null&&gamma_from_1!=null&&gamma_table!=null) { for(i=0; i<row_width; i++, sp+=2, dp++) { ushort a=*(sp+1); if(a==0xff) *dp=gamma_table[*sp]; else if(a==0) *dp=(byte)background.gray; // background is already in screen gamma else { byte w, v=gamma_to_1[*sp]; //png_composite(w, v, a, background_1->gray); w=(byte)(((ushort)v*a+background_1.gray*(ushort)(255-a)+(ushort)127)/255); *dp=gamma_from_1[w]; } } } else { for(i=0; i<row_width; i++, sp+=2, dp++) { byte a=*(sp+1); if(a==0xff) *dp=*sp; else if(a==0) *dp=(byte)background.gray; else //png_composite(*dp, *sp, a, background_1->gray); *dp=(byte)(((ushort)(*sp)*a+background_1.gray*(ushort)(255-a)+(ushort)127)/255); } } } else // if(png_ptr->bit_depth==16) { if(gamma_16!=null&&gamma_16_from_1!=null&&gamma_16_to_1!=null) { for(i=0; i<row_width; i++, sp+=4, dp+=2) { ushort a=(ushort)(((*(sp+2))<<8)+*(sp+3)); if(a==(ushort)0xffff) { ushort v=gamma_16[*(sp+1)>>gamma_shift][*sp]; *dp=(byte)((v>>8)&0xff); *(dp+1)=(byte)(v&0xff); } else if(a==0) { // background is already in screen gamma *dp=(byte)((background.gray>>8)&0xff); *(dp+1)=(byte)(background.gray&0xff); } else { ushort v, w, g=gamma_16_to_1[*(sp+1)>>gamma_shift][*sp]; //png_composite_16(v, g, a, background_1->gray); v=(ushort)(((uint)g*(uint)a+(uint)background_1.gray*(uint)(65535-(uint)a)+(uint)32767)/(uint)65535); w=gamma_16_from_1[(v&0xff)>>gamma_shift][v>>8]; *dp=(byte)((w>>8)&0xff); *(dp+1)=(byte)(w&0xff); } } } else { for(i=0; i<row_width; i++, sp+=4, dp+=2) { ushort a=(ushort)(((*(sp+2))<<8)+*(sp+3)); if(a==(ushort)0xffff) { //memcpy(dp, sp, 2); *dp=*sp; *(dp+1)=*(sp+1); } else if(a==0) { *dp=(byte)((background.gray>>8)&0xff); *(dp+1)=(byte)(background.gray&0xff); } else { ushort v, g=(ushort)(((*sp)<<8)+*(sp+1)); //png_composite_16(v, g, a, background_1->gray); v=(ushort)(((uint)g*(uint)a+(uint)(background_1.gray)*(uint)(65535-(uint)a)+(uint)32767)/(uint)65535); *dp=(byte)((v>>8)&0xff); *(dp+1)=(byte)(v&0xff); } } } } } break; case PNG_COLOR_TYPE.RGB_ALPHA: { if(row_info.bit_depth==8) { if(gamma_to_1!=null&&gamma_from_1!=null&&gamma_table!=null) { for(i=0; i<row_width; i++, sp+=4, dp+=3) { byte a=*(sp+3); if(a==0xff) { *dp=gamma_table[*sp]; *(dp+1)=gamma_table[*(sp+1)]; *(dp+2)=gamma_table[*(sp+2)]; } else if(a==0) { // background is already in screen gamma *dp=(byte)background.red; *(dp+1)=(byte)background.green; *(dp+2)=(byte)background.blue; } else { byte w, v=gamma_to_1[*sp]; // png_composite(w, v, a, background_1->red); w=(byte)(((ushort)v*(ushort)a+background_1.red*(ushort)(255-(ushort)a)+(ushort)127)/255); *dp=gamma_from_1[w]; v=gamma_to_1[*(sp+1)]; //png_composite(w, v, a, background_1->green); w=(byte)(((ushort)v*(ushort)a+background_1.green*(ushort)(255-(ushort)a)+(ushort)127)/255); *(dp+1)=gamma_from_1[w]; v=gamma_to_1[*(sp+2)]; //png_composite(w, v, a, background_1->blue); w=(byte)(((ushort)v*(ushort)a+background_1.blue*(ushort)(255-(ushort)a)+(ushort)127)/255); *(dp+2)=gamma_from_1[w]; } } } else { for(i=0; i<row_width; i++, sp+=4, dp+=3) { byte a=*(sp+3); if(a==0xff) { *dp=*sp; *(dp+1)=*(sp+1); *(dp+2)=*(sp+2); } else if(a==0) { *dp=(byte)background.red; *(dp+1)=(byte)background.green; *(dp+2)=(byte)background.blue; } else { //png_composite(*dp, *sp, a, background->red); //png_composite(*(dp+1), *(sp+1), a, background->green); //png_composite(*(dp+2), *(sp+2), a, background->blue); *dp=(byte)(((ushort)(*sp)*(ushort)a+background.red*(ushort)(255-(ushort)a)+(ushort)127)/255); *(dp+1)=(byte)(((ushort)(*(sp+1))*(ushort)a+background.green*(ushort)(255-(ushort)a)+(ushort)127)/255); *(dp+2)=(byte)(((ushort)(*(sp+2))*(ushort)a+background.blue*(ushort)(255-(ushort)a)+(ushort)127)/255); } } } } else //if (row_info->bit_depth==16) { if(gamma_16!=null&&gamma_16_from_1!=null&&gamma_16_to_1!=null) { for(i=0; i<row_width; i++, sp+=8, dp+=6) { ushort a=(ushort)(((ushort)(*(sp+6))<<8)+(ushort)(*(sp+7))); if(a==(ushort)0xffff) { ushort v=gamma_16[*(sp+1)>>gamma_shift][*sp]; *dp=(byte)((v>>8)&0xff); *(dp+1)=(byte)(v&0xff); v=gamma_16[*(sp+3)>>gamma_shift][*(sp+2)]; *(dp+2)=(byte)((v>>8)&0xff); *(dp+3)=(byte)(v&0xff); v=gamma_16[*(sp+5)>>gamma_shift][*(sp+4)]; *(dp+4)=(byte)((v>>8)&0xff); *(dp+5)=(byte)(v&0xff); } else if(a==0) { // background is already in screen gamma *dp=(byte)((background.red>>8)&0xff); *(dp+1)=(byte)(background.red&0xff); *(dp+2)=(byte)((background.green>>8)&0xff); *(dp+3)=(byte)(background.green&0xff); *(dp+4)=(byte)((background.blue>>8)&0xff); *(dp+5)=(byte)(background.blue&0xff); } else { ushort w, x, v=gamma_16_to_1[*(sp+1)>>gamma_shift][*sp]; //png_composite_16(w, v, a, background_1->red); w=(ushort)(((uint)v*(uint)a+(uint)background_1.red*(uint)(65535-(uint)a)+(uint)32767)/(uint)65535); x=gamma_16_from_1[((w&0xff)>>gamma_shift)][w>>8]; *dp=(byte)((x>>8)&0xff); *(dp+1)=(byte)(x&0xff); v=gamma_16_to_1[*(sp+3)>>gamma_shift][*(sp+2)]; //png_composite_16(w, v, a, background_1->green); w=(ushort)(((uint)v*(uint)a+(uint)background_1.green*(uint)(65535-(uint)a)+(uint)32767)/(uint)65535); x=gamma_16_from_1[((w&0xff)>>gamma_shift)][w>>8]; *(dp+2)=(byte)((x>>8)&0xff); *(dp+3)=(byte)(x&0xff); v=gamma_16_to_1[*(sp+5)>>gamma_shift][*(sp+4)]; //png_composite_16(w, v, a, background_1->blue); w=(ushort)(((uint)v*(uint)a+(uint)background_1.blue*(uint)(65535-(uint)a)+(uint)32767)/(uint)65535); x=gamma_16_from_1[(w&0xff)>>gamma_shift][w>>8]; *(dp+4)=(byte)((x>>8)&0xff); *(dp+5)=(byte)(x&0xff); } } } else { for(i=0; i<row_width; i++, sp+=8, dp+=6) { ushort a=(ushort)(((ushort)(*(sp+6))<<8)+(ushort)(*(sp+7))); if(a==(ushort)0xffff) { //memcpy(dp, sp, 6); *dp=*sp; *(dp+1)=*(sp+1); *(dp+2)=*(sp+2); *(dp+3)=*(sp+3); *(dp+4)=*(sp+4); *(dp+5)=*(sp+5); } else if(a==0) { *dp=(byte)((background.red>>8)&0xff); *(dp+1)=(byte)(background.red&0xff); *(dp+2)=(byte)((background.green>>8)&0xff); *(dp+3)=(byte)(background.green&0xff); *(dp+4)=(byte)((background.blue>>8)&0xff); *(dp+5)=(byte)(background.blue&0xff); } else { ushort v; ushort r=(ushort)(((*sp)<<8)+*(sp+1)); ushort g=(ushort)(((*(sp+2))<<8)+*(sp+3)); ushort b=(ushort)(((*(sp+4))<<8)+*(sp+5)); //png_composite_16(v, r, a, background->red); v=(ushort)(((uint)r*(uint)a+(uint)background.red*(uint)(65535-(uint)a)+(uint)32767)/(uint)65535); *dp=(byte)((v>>8)&0xff); *(dp+1)=(byte)(v&0xff); //png_composite_16(v, g, a, background->green); v=(ushort)(((uint)g*(uint)a+(uint)background.green*(uint)(65535-(uint)a)+(uint)32767)/(uint)65535); *(dp+2)=(byte)((v>>8)&0xff); *(dp+3)=(byte)(v&0xff); //png_composite_16(v, b, a, background->blue); v=(ushort)(((uint)b*(uint)a+(uint)background.blue*(uint)(65535-(uint)a)+(uint)32767)/(uint)65535); *(dp+4)=(byte)((v>>8)&0xff); *(dp+5)=(byte)(v&0xff); } } } } } break; } // switch(row_info->color_type) } // fixed if((row_info.color_type&PNG_COLOR_TYPE.ALPHA_MASK)==PNG_COLOR_TYPE.ALPHA_MASK) { row_info.color_type&=~PNG_COLOR_TYPE.ALPHA_MASK; row_info.channels--; row_info.pixel_depth=(byte)(row_info.channels*row_info.bit_depth); row_info.rowbytes=PNG_ROWBYTES(row_info.pixel_depth, row_width); } }
// handle alpha and tRNS via a background color public void png_set_background(png_color_16 background_color, PNG_BACKGROUND_GAMMA background_gamma_code, bool need_expand, double background_gamma) { if(background_gamma_code==PNG_BACKGROUND_GAMMA.UNKNOWN) { Debug.WriteLine("Application must supply a known background gamma"); return; } transformations|=PNG_TRANSFORMATION.BACKGROUND; background=background_color; this.background_gamma=background_gamma; background_gamma_type=background_gamma_code; transformations|=(need_expand?PNG_TRANSFORMATION.BACKGROUND_EXPAND:PNG_TRANSFORMATION.None); }