From 8afb054170dcf05af90a30a9c07e9b18b049a2b5 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Wed, 3 Sep 2014 10:44:02 -0700 Subject: [PATCH] Decode grayscale images to RGBA Part of the fix for servo/servo#3154. --- src/ffi.rs | 3 +++ src/lib.rs | 33 ++++++++++++++++++++------------- test/gray.png | Bin 0 -> 2318 bytes 3 files changed, 23 insertions(+), 13 deletions(-) create mode 100644 test/gray.png diff --git a/src/ffi.rs b/src/ffi.rs index 0b9a90f..4cfc562 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -70,6 +70,7 @@ extern { pub fn png_get_image_height(png_ptr: *mut png_struct, info_ptr: *mut png_info) -> u32; pub fn png_get_bit_depth(png_ptr: *mut png_struct, info_ptr: *mut png_info) -> u8; pub fn png_get_color_type(png_ptr: *mut png_struct, info_ptr: *mut png_info) -> u8; + pub fn png_get_valid(png_ptr: *mut png_struct, info_ptr: *mut png_info, flag: u32) -> u32; pub fn png_get_rows(png_ptr: *mut png_struct, info_ptr: *mut png_info) -> *mut *mut u8; pub fn png_set_IHDR(png_ptr: *mut png_struct, info_ptr: *mut png_info, width: u32, height: u32, bit_depth: c_int, color_type: c_int, interlace_method: c_int, compression_method: c_int, filter_method: c_int); @@ -79,7 +80,9 @@ extern { pub fn png_set_packing(png_ptr: *mut png_struct); pub fn png_set_palette_to_rgb(png_ptr: *mut png_struct); pub fn png_set_expand_gray_1_2_4_to_8(png_ptr: *mut png_struct); + pub fn png_set_gray_to_rgb(png_ptr: *mut png_struct); pub fn png_set_tRNS_to_alpha(png_ptr: *mut png_struct); + pub fn png_set_add_alpha(png_ptr: *mut png_struct, val: u32, flag: c_int); pub fn png_set_filler(png_ptr: *mut png_struct, val: u32, flag: c_int); pub fn png_set_interlace_handling(png_ptr: *mut png_struct); } diff --git a/src/lib.rs b/src/lib.rs index 4b1527d..96a8e96 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -105,22 +105,23 @@ pub fn load_png_from_memory(image: &[u8]) -> Result { let width = ffi::png_get_image_width(png_ptr, info_ptr); let height = ffi::png_get_image_height(png_ptr, info_ptr); - let bit_depth = ffi::png_get_bit_depth(png_ptr, info_ptr); let color_type = ffi::png_get_color_type(png_ptr, info_ptr); - // we convert palette to rgb - if color_type as c_int == ffi::COLOR_TYPE_PALETTE { - ffi::png_set_palette_to_rgb(png_ptr); - } - // make each channel use 1 byte - if (color_type as c_int == ffi::COLOR_TYPE_GRAY) && (bit_depth < 8) { - ffi::png_set_expand_gray_1_2_4_to_8(png_ptr); + // convert palette and grayscale to rgb + match color_type as c_int { + ffi::COLOR_TYPE_PALETTE => { + ffi::png_set_palette_to_rgb(png_ptr); + } + ffi::COLOR_TYPE_GRAY | ffi::COLOR_TYPE_GRAY_ALPHA => { + ffi::png_set_gray_to_rgb(png_ptr); + } + _ => {} } - // add alpha channels to palette and rgb - if (color_type as c_int == ffi::COLOR_TYPE_PALETTE) || - (color_type as c_int == ffi::COLOR_TYPE_RGB) { + + // add alpha channels + ffi::png_set_add_alpha(png_ptr, 0xff, ffi::FILLER_AFTER); + if ffi::png_get_valid(png_ptr, info_ptr, ffi::INFO_tRNS as u32) != 0 { ffi::png_set_tRNS_to_alpha(png_ptr); - ffi::png_set_filler(png_ptr, 0xff, ffi::FILLER_AFTER); } ffi::png_set_packing(png_ptr); @@ -285,6 +286,12 @@ mod test { load_rgba8("test/store.png", 10, 10); } + #[test] + fn test_load_grayscale() { + // grayscale images should be decoded to rgba + load_rgba8("test/gray.png", 100, 100); + } + fn bench_file_from_memory(file: &'static str, w: u32, h: u32, c: &'static str) { let mut reader = match File::open_mode(&Path::new(file), io::Open, io::Read) { Ok(r) => r, @@ -317,7 +324,7 @@ mod test { fn test_load_perf() { bench_file_from_memory("test/servo-screenshot.png", 831, 624, "RGBA8"); bench_file_from_memory("test/mozilla-dinosaur-head-logo.png", 1300, 929, "RGBA8"); - bench_file_from_memory("test/rust-huge-logo.png", 4000, 4000, "KA8"); + bench_file_from_memory("test/rust-huge-logo.png", 4000, 4000, "RGBA8"); } #[test] diff --git a/test/gray.png b/test/gray.png new file mode 100644 index 0000000000000000000000000000000000000000..e927b99281513eb7cd8f20e8c12c216cddb7e955 GIT binary patch literal 2318 zcmV+p3Gw!cP)#-D3 zqvc%$n4dJ`&SdHV5SWhz=Rp*}K+dS<-uF>}F9NEe`bzz*r`AKkzV6Rd*o+9W?`O>f z>{a)kGJmL?kw1B_h_e#_5VHQ*;f^aRNlxLpl3-T_l6s}>To4%!jyVXBjc97qq0z*HL!2w2_}!# z{(1kVw}(-;3p0g1;O8GZ6S=1a-$P?rYB+O0h$^e5WSxd?ARSoQ)pD1+8AC%)ij)0wR3871G|YJ@?ANrs7HL=Nq2kONej;@2 zHOTB^3&&p+E`Y3r+s#fW$$3vnIuF(bGze7AHFhV|HR-KJ64aS2OcApXlTXwGn|3DT zK<~*c4Gw7Ud7dzT^Ev&Ev<%@w>QjHF3V~IsX~Vpe<|!1XtoC-zR2$PIug2OcAjb{!g4|V0}jnGoK8?#U6%If${m#hkh_Wj95rk#>ofXO7^6*zsz${dglD+gu8gh;bPh7Z zxD5}4`ayIxQi3fd$ym>=@zOOPiR(R;IjQ*xeAIEM$A#SkPTw z#~-y1DdN^=0*`m&BEuLPHtrn#95v_ z%0oxFHMo+)Kn@SM3`lHRTAuXg?OZPU@UUu2vP_XiAs#ewEDRKbBaC5OHf7{aO*tH= zXq?5=1!tsiidxj5>#)O(=43e3vG>+=g@L{iyqKvi>Yey8EKuc3Zcq`=4d*_&hM2{r zSaR`4C77KtLT>onq*xDTZ*u1&!?1=)A+bU9o8Vh~$a2J`Huei}c!~mI$k7 zI=Xnkge9nTA8vHAc5|{~`4`_MZ*-MrIDAu2uz7M!j%*UyV5`nJH6E@dN1r#$Zw%z= zsj=mxd67jeH|0WEbdv7Ya^syNzk6&Rva#ww`%J#E*Akna^&_~f(o+lhc~k}r%geaI z$IZ^TF@L0rZqb}G=8Nu}Wy;pH>M>qk>0)2!@2wH)y?-)Dr!H)i#5+XU7uwv}%FM%+ zI~~l}^1NSCGF%wT-<_i1F-w-LxW2Vmb{abMEq!sER2s zz70Fpx^bqejSbI1b7hMbQuEFjN=P1}dQ5;S9HdWPYfH^yUkRMI#Vyh8Fii}l@w2-* z9BGNK%+n}4=*Z(-Ni!$bQfq><4YWh&YuNa;Vf)vha~*%R$IkDd_=2l&FX(sF{zc%i zDQZeGLZvtBR*aD5Kptyye7T`Sy4ru-u(9aQo)N!iOi=VP?^Z}SFkg?PP;mu<%=MP| zS6w!(KZ^yzwX5)arjvWUp1QB53y<8})6i6b#!K!nY7INqBgcl}kq@*Dwt6W$_|`G> zz$COa@Q3#O5z0nLu7eOBj!mb@h4U_}hk2~=PP2-z;p?HU4Q}bzu`LuPO`(mm zq)xG4I<6Cs=C<%UHx+l`Kp<&~CdJoRq?Z~Vt!4h@X7$8fxJTx2WTm!G{bb`~fFC!G z@?ari^^d!va%;KyTCMPw8@~*O9c-A}b8y zo7@)wx6|;DQ;wNa0LlK&VS;SuoX*?%qb$7xxIyZUHli_t-IWsEIiNZk5_Ze@n`qb| zBcD}j+`Ubvu14umOzm*c5B$`&`6$k9h3W%q> zsC9&!#_L-0wGqblc)Yl_xfW+*dUt;0yzagpp<@WIPNancwWU9e*06foo}*b~S^~Kk zrC(Fq{btLO5@})9239VQJ4t%F#EOsg{XjGS_q zqO1mU$DN)62t%<)d5P{M>ZFS9HZJe7wwU-fb$QH}4SKoq;B8B;T8QIq^05-nODVTq z)KAcO`Ddyt>XdN!O`0ifp|UDK(|T@ve<14^Dp*&1>6*pH~JQ| z`N)>&=w4TJpT{e2#z#FOT*GAZU5DxqJH;-E&4B>@zER+YsY^Cu{Ym35)G?7Ky387} zhRAUXopX&%s@u(5SN}Lpia)pquf+DZN>-PiKD9a!c!hX9CLXfX5^kZA;%~QImtuR* z)n4K0Fb?-Ojni*?^cFo>U-WW6JzB