From 0a426f981b6ecd57fbcbc5666b3f6704e01e9221 Mon Sep 17 00:00:00 2001 From: Jeremy Hu Date: Sun, 12 Feb 2017 19:29:51 +0930 Subject: [PATCH] Add dark theme and icons --- CMakeLists.txt | 16 +- README.md | 3 +- icons/README.md | 6 + icons/files/eye.png | Bin 0 -> 311 bytes icons/files/eyedropper.png | Bin 0 -> 324 bytes icons/files/file.png | Bin 0 -> 167 bytes icons/files/folder.png | Bin 0 -> 142 bytes icons/files/image.png | Bin 0 -> 187 bytes icons/files/info.png | Bin 0 -> 265 bytes icons/files/link.png | Bin 0 -> 350 bytes icons/files/lock.png | Bin 0 -> 196 bytes icons/files/minus.png | Bin 0 -> 125 bytes icons/files/monitor.png | Bin 0 -> 190 bytes icons/files/pause.png | Bin 0 -> 127 bytes icons/files/pencil.png | Bin 0 -> 200 bytes icons/files/pin.png | Bin 0 -> 202 bytes icons/files/play.png | Bin 0 -> 164 bytes icons/files/plus.png | Bin 0 -> 139 bytes icons/files/reload.png | Bin 0 -> 336 bytes icons/files/stop.png | Bin 0 -> 125 bytes icons/files/tool.png | Bin 0 -> 265 bytes icons/files/trash.png | Bin 0 -> 204 bytes icons/files/undo.png | Bin 0 -> 278 bytes icons/files/unlink.png | Bin 0 -> 329 bytes icons/files/unlock.png | Bin 0 -> 196 bytes icons/licenses/open-iconic/ICON-LICENSE | 21 + icons/licenses/open-iconic/README.md | 114 + res/icons.png | Bin 0 -> 2375 bytes screenshot/dust3d_glw_preview_dark.png | Bin 0 -> 177590 bytes src/editor.c | 58 +- src/glw.c | 146 +- src/glw.h | 2 +- src/glw_internal.h | 7 + src/glw_osx.m | 13 +- src/glw_style.h | 16 +- src/icons.c | 28 + src/icons.h | 48 + src/lodepng.c | 6224 +++++++++++++++++++++++ src/lodepng.h | 1760 +++++++ 39 files changed, 8402 insertions(+), 60 deletions(-) create mode 100644 icons/README.md create mode 100755 icons/files/eye.png create mode 100755 icons/files/eyedropper.png create mode 100755 icons/files/file.png create mode 100755 icons/files/folder.png create mode 100755 icons/files/image.png create mode 100755 icons/files/info.png create mode 100755 icons/files/link.png create mode 100755 icons/files/lock.png create mode 100755 icons/files/minus.png create mode 100755 icons/files/monitor.png create mode 100755 icons/files/pause.png create mode 100755 icons/files/pencil.png create mode 100755 icons/files/pin.png create mode 100755 icons/files/play.png create mode 100755 icons/files/plus.png create mode 100755 icons/files/reload.png create mode 100755 icons/files/stop.png create mode 100755 icons/files/tool.png create mode 100755 icons/files/trash.png create mode 100755 icons/files/undo.png create mode 100755 icons/files/unlink.png create mode 100755 icons/files/unlock.png create mode 100755 icons/licenses/open-iconic/ICON-LICENSE create mode 100755 icons/licenses/open-iconic/README.md create mode 100644 res/icons.png create mode 100644 screenshot/dust3d_glw_preview_dark.png create mode 100644 src/icons.c create mode 100644 src/icons.h create mode 100755 src/lodepng.c create mode 100755 src/lodepng.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 595d7193..29f35e10 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.8) project(dust3d) -file(GLOB_RECURSE sources +file(GLOB_RECURSE SOURCES src/glw_osx.m src/glw_internal.h src/glw_style.h @@ -29,17 +29,21 @@ file(GLOB_RECURSE sources src/draw.c src/skeleton.h src/skeleton.c + src/icons.h + src/icons.c src/editor.c + src/lodepng.h + src/lodepng.c ) IF(APPLE) - add_executable(dust3d MACOSX_BUNDLE ${sources}) + file(GLOB_RECURSE RES_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/res/*.png") + add_executable(dust3d MACOSX_BUNDLE ${SOURCES} ${RES_SOURCES}) + SET_SOURCE_FILES_PROPERTIES(${RES_SOURCES} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) find_package(OpenGL REQUIRED) include_directories(${OPENGL_INCLUDE_DIRS}) target_link_libraries(dust3d ${OPENGL_LIBRARIES}) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework AppKit -framework Quartz") - set_target_properties(dust3d PROPERTIES - MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/src/Info.plist) - install(TARGETS dust3d - DESTINATION ".") + set_target_properties(dust3d PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/src/Info.plist) + install(TARGETS dust3d DESTINATION ".") ENDIF (APPLE) diff --git a/README.md b/README.md index 1820b190..6573588f 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,8 @@ This todo already done in the B-Mesh algorithm implementation. **Feb 11, 2017:** Qt removed, so C++ removed, but Objective-C imported for just support the OpenGL environment on OSX. - + + - [ ] Render rigid animation - [ ] png exporter for isometric 2.5D game diff --git a/icons/README.md b/icons/README.md new file mode 100644 index 00000000..67455023 --- /dev/null +++ b/icons/README.md @@ -0,0 +1,6 @@ +**Icons are not made by me, so if you want use these icons please check the listed license details inside current folder.** + +The following command line is using [squeezer](https://github.com/huxingyi/squeezer) to pack all the icons to one png. +```sh +./squeezerw files --verbose --width 128 --height 128 --border 0 --allowRotations 0 --outputTexture ../res/icons.png --outputInfo ../src/icons.c --infoHeader "//THIS FILE IS GENERATED AUTOMATICALLY BY https://github.com/huxingyi/squeezer, PLEASE DONT MODIFY IT MANUALLY.\n\n#include \"icons.h\"\n\nconst int iconTable[][ICON_ITEM_MAX] = {\n" --infoFooter "\n};\n" --infoBody " {%w, %h, %x, %y, %l, %t, %c, %r} /*\"%n\"*/" --infoSplit ",\n" +``` diff --git a/icons/files/eye.png b/icons/files/eye.png new file mode 100755 index 0000000000000000000000000000000000000000..b6d55edfeffaa1406e3dab3104ff672862e50deb GIT binary patch literal 311 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ za0`PlBg3pY5hVqL%Euqd1T#P*6qyOPfq z-f@*n7ClhibK!8k=?UJWmI$@H@(KheJ*k<;P6UuH?tZHwc)^J;rOi%gfj^zX(!##iw{8*=Y4nJ za0`PlBg3pY51&zU>nCP$&X0t$Wk2vPyLeOJykf!9nKgWJ zEz{qBa58=v$+$=GX;nl*-KO@|4|A68w)J?BDSk&S;NfbKbDScFEgO@5$Qw_}4tV`( S>3^V)89ZJ6T-G@yGywpE>4EnE literal 0 HcmV?d00001 diff --git a/icons/files/file.png b/icons/files/file.png new file mode 100755 index 0000000000000000000000000000000000000000..4196c44da842147328112fb85ccc0fcbc09e8f94 GIT binary patch literal 167 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ za0`PlBg3pY54nJ za0`PlBg3pY54nJ za0`PlBg3pY5$e*WFKFd~@|jh0ElfA}f^o9av{F882aRIbrlbklDxY eY3|ngM~prq5l3tbek=i6#Ng@b=d#Wzp$Py%NI%a2 literal 0 HcmV?d00001 diff --git a/icons/files/info.png b/icons/files/info.png new file mode 100755 index 0000000000000000000000000000000000000000..36c3cf812ee46f1b0714a7adab8124925ab2b53d GIT binary patch literal 265 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ za0`PlBg3pY5k literal 0 HcmV?d00001 diff --git a/icons/files/link.png b/icons/files/link.png new file mode 100755 index 0000000000000000000000000000000000000000..b157e9b7c13d6f49dc8904f4b7678929041881d1 GIT binary patch literal 350 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ za0`PlBg3pY5)2HC44y8IAr`&8m-l)(I|{Ttd@c~ox^<(VORxP#0i7$-ADs4RIl2gl zgm?tJKWNmkbn2qH8nccZ3hF$1bHbcn^*8Ld&%Cj&G2ZPwOKQhKcMIJ$>YJv0Y^^J? zityG9aOY2-ahS)?dE)92@r}zqcHg_w;vId%L45lU$&;ZISjCfX9hsZ7-+x7GP1+47 z?Y8o#f4_a~P?P&0m6L8^Ci5suvPL3@Z;ESy`0dmWjx0{1>Zt{bS@s?0*85Hda_NV|;_UM=eL-t(CEd4w0^e}?bg{=UV5!JB{q#Ng@b=d#Wzp$P!h;)-kl literal 0 HcmV?d00001 diff --git a/icons/files/lock.png b/icons/files/lock.png new file mode 100755 index 0000000000000000000000000000000000000000..f2646f58c7ddbafc6f38d02a513a6c27a0bc2b5f GIT binary patch literal 196 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ za0`PlBg3pY54nJ za0`PlBg3pY5+JpnE{-7 literal 0 HcmV?d00001 diff --git a/icons/files/monitor.png b/icons/files/monitor.png new file mode 100755 index 0000000000000000000000000000000000000000..47cdfc13a624d7300464d0bdde579c95eb6e5cae GIT binary patch literal 190 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ za0`PlBg3pY50TY@RWk|28E51o>zX)Zv=u)q1*1f z5;|-Fb0*A?kdW{TT<~9F-<9@vMr*QGN_9B$@bIjc6tLu--Tlwlz+g{OLc)jRX%d^# eoPMbK2s1S7QZGvXbq#101B0ilpUXO@geCxO@jC?o literal 0 HcmV?d00001 diff --git a/icons/files/pause.png b/icons/files/pause.png new file mode 100755 index 0000000000000000000000000000000000000000..19a7b0924d168d764ac7f9b1a14da5615bd1922f GIT binary patch literal 127 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ za0`PlBg3pY54nJ za0`PlBg3pY5~`ed^h48*u+E4nJ za0`PlBg3pY5M!VG^U@r5y}D|3sOYo9#ETY)VV|=$#bfe!{gtKY+!JHz6V6 rpmO=7#>R)ts%`BC1_l|zK`adMO{x|gTe~DWM4fn*=(M literal 0 HcmV?d00001 diff --git a/icons/files/play.png b/icons/files/play.png new file mode 100755 index 0000000000000000000000000000000000000000..e934b0a2e1df1618938346ec8896de12bbd33a6f GIT binary patch literal 164 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ za0`PlBg3pY5TmNj{ppNZMhOn}kC2;{!|#`#;!RZ20}?EYL&-Pgg&ebxsLQ E0E(9_EC2ui literal 0 HcmV?d00001 diff --git a/icons/files/plus.png b/icons/files/plus.png new file mode 100755 index 0000000000000000000000000000000000000000..667b035915290c08b925de47089622888a212203 GIT binary patch literal 139 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ za0`PlBg3pY54nJ za0`PlBg3pY5>Y*U9P$-MRL!(@9^X8fhq)(E zFJr#NVI#l5GfnbJnH`@4HZ}2mE9hQ-qOz;b%b=q*ea-b7vyRl=n5ChmHt%@F;V9;a z6Z5u)Owe0%kz&bqH;`{=)pW(4FHy7Od@(eJR=g%=_#4 zi__yCxo)1S*Z0cIYSL7p_d6W?wLbFf-tj58wY^j&QX})1kLtS(w^GujuU`_^dvqmc e)r~mQpVIIC_*-03aXkd|J%gvKpUXO@geCw(qlWDO literal 0 HcmV?d00001 diff --git a/icons/files/stop.png b/icons/files/stop.png new file mode 100755 index 0000000000000000000000000000000000000000..c261089092d9a07cec2aef1aea64f8face21af98 GIT binary patch literal 125 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ za0`PlBg3pY5+JpnE{-77$U3lsvH5UABRj)3Z$=5>>?P-b PN*O#|{an^LB{Ts52^1bA literal 0 HcmV?d00001 diff --git a/icons/files/tool.png b/icons/files/tool.png new file mode 100755 index 0000000000000000000000000000000000000000..ec4a206ce345ed60eb0a4bf89611c8d2806cf41b GIT binary patch literal 265 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ za0`PlBg3pY5{F*Rz~K>HvfK(ckl97+zPMYvtzOcEBe5!XIq|u7irI6}=pN z4%3D1FdwvD!Fo#~hN)Iz!mddVPVJuXDzxc3)1BRx$8z(Mr<)&8c%zqW{r8Ph!P3TT zM!7pOq4N$fMN}26ZC!qVWya2^1pYf)m>SmpKC1lulezrMf1zI`c;+Mnoz39s>gTe~ HDWM4f91~wf literal 0 HcmV?d00001 diff --git a/icons/files/trash.png b/icons/files/trash.png new file mode 100755 index 0000000000000000000000000000000000000000..de1127e873e012ec6ac85627258a6634e47bef2e GIT binary patch literal 204 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ za0`PlBg3pY5-dDykDmZ{B#VnN{+`|ePR8h>eS1v3m7xzFZ;(G7qLKSGh;-9 u-eP8xM>*Qg)qVDiE&c|gY0NoA8<_X>8Q$tw(~}0;%;4$j=d#Wzp$P!U06=X3 literal 0 HcmV?d00001 diff --git a/icons/files/undo.png b/icons/files/undo.png new file mode 100755 index 0000000000000000000000000000000000000000..ef5679e02c2223e8e63c9688b033c44b9c2b8a3e GIT binary patch literal 278 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ za0`PlBg3pY5 zY1r1p;iMqGLGbmR!%nIjp4@zMDDCdi*lh(5LXAH^uXQf1y>>!OE1|7jt)YQ+5s(m- zJKZF^C#h3jM&LOE%xZ0XRimqZHUV;TDF-H&!O S@CX9^z~JfX=d#Wzp$PzLL1vu* literal 0 HcmV?d00001 diff --git a/icons/files/unlink.png b/icons/files/unlink.png new file mode 100755 index 0000000000000000000000000000000000000000..6af40b0292145b0a0390e7e89dfed27632e263cb GIT binary patch literal 329 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ za0`PlBg3pY5!8xw_+pTv|@`GW!)rL$3aI4E_2c{JayI* zUW0?xfA$@e+g2c3+^^c~Ym?lTxVpS2zox7=@RC{Ghl$#L8!j^Qn<(pCdbD!GoaJ&q zoHieMEVJiWCF8o5*C`JpbNsGy`ft=Z!2EDdz9!Fi!F_KUvSlACghz0i%YHvFSL)l7 z^&gaM)P8*WzOeVzv#OTpH%ap4vx47F;ko6Vb3ABA-;o5B#VbE_hY8MkZ1D1=)E}nB Xf#I$nE_faWdYi%1)z4*}Q$iB}7=4AZ literal 0 HcmV?d00001 diff --git a/icons/files/unlock.png b/icons/files/unlock.png new file mode 100755 index 0000000000000000000000000000000000000000..ca13401c1e4bc067ad8fbfeb32aa45af14f5b7ca GIT binary patch literal 196 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ za0`PlBg3pY5 +``` + +#### Using Open Iconic's SVG Sprite + +Open Iconic also comes in a SVG sprite which allows you to display all the icons in the set with a single request. It's like an icon font, without being a hack. + +Adding an icon from an SVG sprite is a little different than what you're used to, but it's still a piece of cake. *Tip: To make your icons easily style able, we suggest adding a general class to the* `` *tag and a unique class name for each different icon in the* `` *tag.* + +``` + + + +``` + +Sizing icons only needs basic CSS. All the icons are in a square format, so just set the `` tag with equal width and height dimensions. + +``` +.icon { + width: 16px; + height: 16px; +} +``` + +Coloring icons is even easier. All you need to do is set the `fill` rule on the `` tag. + +``` +.icon-account-login { + fill: #f00; +} +``` + +To learn more about SVG Sprites, read [Chris Coyier's guide](http://css-tricks.com/svg-sprites-use-better-icon-fonts/). + +#### Using Open Iconic's Icon Font... + + +##### …with Bootstrap + +You can find our Bootstrap stylesheets in `font/css/open-iconic-bootstrap.{css, less, scss, styl}` + + +``` + +``` + + +``` + +``` + +##### …with Foundation + +You can find our Foundation stylesheets in `font/css/open-iconic-foundation.{css, less, scss, styl}` + +``` + +``` + + +``` + +``` + +##### …on its own + +You can find our default stylesheets in `font/css/open-iconic.{css, less, scss, styl}` + +``` + +``` + +``` + +``` + + +## License + +### Icons + +All code (including SVG markup) is under the [MIT License](http://opensource.org/licenses/MIT). + +### Fonts + +All fonts are under the [SIL Licensed](http://scripts.sil.org/cms/scripts/page.php?item_id=OFL_web). diff --git a/res/icons.png b/res/icons.png new file mode 100644 index 0000000000000000000000000000000000000000..e7c72951b449264a6b5a35aa4b87e7acdae2f9b9 GIT binary patch literal 2375 zcmeHI_ct4gA5GFEMnbKkLkU5Q)Si7$6T~=1i9K5DwY=K#Xuh>#hiZ$^Vbppksx=?2 z6|0mMrH!BuMQE!UE0qMz^ZtnMZ|`%?z4zR6?zunQUp|=*_Lf3|X9NKNfRMG7IsRBl z|APO-G4CzqasU93pM$M4?%4i!|1I$UTOg`UbNIM@><_%X6M%2|tvF?q`ACqb^lYO} zacYF5@nDw2oyk>B1b=vUuH&)X7LxzxA^AiGTbjO)D3=f}d)mv&gc=kd&8`0sTEH>} zFSwYAeBYB_fxlE6`v?Q3ei}NhJ72q2sGuVA>dbv@(AkM`NXhGyi&d&(4G+_AUeSpt zKoQP&-`2|u_=f*_x%$iJKV{MRP6KzMiG8jI&K~!?e6Lb5+s1xA6^*+)t@TBfqEBLO zSz7zk>>SnG|FR$b-|EHYCdpIJ19RfrF6kSlXoVUDzYzdNfY1N{WYpRm>r4c07I0$4 zani#zpxL$g^eMDZIaJWDi0&%*D?C3<60C@UoIx`r3JLDiY*o0-oad#ocsi3 zDGI@11`pWv#j|QfZ=vk8(~mQ{CMe&&>6K25ckK#0Dlp4M6|5If5AvDmX9nT){w_y{ z&)eA-q#gl*ypbohVG#GI{E_cYy~a6Fy=O za^YY%-%Tof&}-ukS=N-fcDn~MC+8G5MuO}Lsy`U$R;bL!yHIr-_ncVL{nIwrSM?^G zHDT$P*^m+%p&fLiRdp)#yBA#jXf?n-iB`CghH&5*u5p|_O`6hle1D2x=6>TBLKIaKZHq@d#K}XlNLg%+TQ+hnZztG+16b^pOyrx;|Q1=ZNPTU}4lHw&k zNvSmYv|>sS5ttl|yA*Lz&1y*wml_l_cDI*WJ^&50B2#m7k~kPEvGdms2lzI+WXw!m z`|Q&csfeTOUTTIak6%LH7ub!Y}=icyM8l{x z!pZkl@{$UIy>NO?YmRIx>LYtQ?%B4R0v_qR6(DLm!@(=_@Nd{x9BB@mU)uf9s#lCJ z6~Y}%5|gIcrVR1s>m;%W8P)LnxRrUH?F(2Ds08T%MeD@G`#55`9AS(3n?t(YG0b)&4b31qvyv# zb=cya4}FWKLd(UFCs>@Aw33wgBL0+|N1q2^N0Ga(B%u2sM}Mws&=CVunzZKz3D$uY zBc&#*vNmU)NiC;$zeV?VSd8cux3(Mc`SKD) zAox>QQnDuSx6ERU{ZgOA614j{*!>%8Z^$W7?-23}re9kr#c=@?kLiuZSGz<>l9jm` z)6M<|@P&Xf9CM;l18Jr%qx|9pb{AT;YR5{cPZX$;97KnKQs6f!`iE|4STn;d3?!Ct zAR`uf==UjhB66jLO+oi>L~rQ}hi|nY;X;uNikI}|5uXn4+7fwUvIZ|a`>fomMMf^0 zouN@$j5RspwSP41?SFI`gc3`#8&c7g&1khKrV3Yzk+XO&K~r|vq0$^4P|DkesH{u? Q{`(58arWlVOnsC80bjaIg#Z8m literal 0 HcmV?d00001 diff --git a/screenshot/dust3d_glw_preview_dark.png b/screenshot/dust3d_glw_preview_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..0a45768bdee7b710a010892dce1b7e0a4ddf72a1 GIT binary patch literal 177590 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ⅅcz#a*j4$LG- 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°PM+??*97_QdG{wjr$ZHTnBVX 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 literal 0 HcmV?d00001 diff --git a/src/editor.c b/src/editor.c index 589c5cfe..6edc194e 100644 --- a/src/editor.c +++ b/src/editor.c @@ -12,19 +12,20 @@ #include "draw.h" #include "skeleton.h" #include "bmesh.h" +#include "icons.h" #define GEN_ID __LINE__ #define ED_MODE_EDIT 0 #define ED_MODE_ANIMATION 1 -#define ED_BACKGROUND_COLOR 0x2b2b2b +#define ED_BACKGROUND_COLOR 0x141414 #define ED_SIDEBAR_WIDTH 400 #define ED_SPACING 10 #define ED_TOPBAR_HEIGHT 100 -#define ED_TOOLBAR_HEIGHT 50 +#define ED_TOOLBAR_HEIGHT (glwImLineHeight(win) * 1.2) #define ED_GL_BACKGROUND_COLOR GLW_BACKGROUND_COLOR @@ -69,6 +70,26 @@ static int drawBmeshBone(bmesh *bm, bmeshBone *bone) { return 0; } +#define ED_CANVAS_BORDER_COLOR 0 +#define ED_CANVAS_OUTER_COLOR 0 +#define ED_CANVAS_BACKGROUND_COLOR 0 + +static void drawCanvas(int x, int y, int width, int height) { + int left = x; + int top = y; + int right = x + width - 1; + int bottom = y + height - 1; + glColor3f(glwR(ED_CANVAS_BORDER_COLOR), + glwG(ED_CANVAS_BORDER_COLOR), + glwB(ED_CANVAS_BORDER_COLOR)); + glBegin(GL_QUADS); + glVertex2f(left, top); + glVertex2f(right, top); + glVertex2f(right, bottom); + glVertex2f(left, bottom); + glEnd(); +} + static void display(glwWin *win) { editor *ed = glwGetUserData(win); @@ -87,10 +108,11 @@ static void display(glwWin *win) { } { - char *titles[] = {"Library", "Property", 0}; + char *titles[] = {"Tool", 0}; + int icons[] = {ICON_TOOL, 0}; glwImTabBox(win, GEN_ID, ED_SPACING / 2, ED_TOPBAR_HEIGHT, ED_SIDEBAR_WIDTH, ed->height - ED_TOPBAR_HEIGHT - ED_SPACING / 2, - titles, 0); + titles, icons, 0); } { @@ -98,33 +120,34 @@ static void display(glwWin *win) { int y = ED_TOPBAR_HEIGHT; int width = ed->width - ED_SIDEBAR_WIDTH - ED_SPACING / 2 - ED_SPACING - ED_SPACING / 2; int height = ed->height - ED_TOPBAR_HEIGHT - ED_SPACING / 2; - char *titles[] = {"Edit View", "Animation View", 0}; + char *titles[] = {"Skeleton", "Animation", "Config", 0}; + int icons[] = {ICON_MONITOR, ICON_PENCIL, ICON_EYE, 0}; ed->mode = glwImTabBox(win, GEN_ID, x, y, width, height, - titles, ed->mode); + titles, icons, ed->mode); if (ED_MODE_EDIT == ed->mode) { - int glWinY = glwImNextY(win); - int bottomY = y + height - ED_TOOLBAR_HEIGHT; - glwImBottomBar(win, GEN_ID, x, bottomY, width, ED_TOOLBAR_HEIGHT); + int toolBarY = glwImNextY(win) - 1; + int glWinY = toolBarY + ED_TOOLBAR_HEIGHT; + glwImToolBar(win, GEN_ID, x, toolBarY, width, ED_TOOLBAR_HEIGHT); ed->showBallChecked = glwImCheck(win, GEN_ID, x + ED_SPACING + ED_SPACING, - bottomY + (ED_TOOLBAR_HEIGHT - glwImLineHeight(win)) / 2 + 2, + toolBarY + (ED_TOOLBAR_HEIGHT - glwImLineHeight(win)) / 2 + 2, "Ball", ed->showBallChecked); ed->showBoneChecked = glwImCheck(win, GEN_ID, glwImNextX(win) + ED_SPACING, - bottomY + (ED_TOOLBAR_HEIGHT - glwImLineHeight(win)) / 2 + 2, + toolBarY + (ED_TOOLBAR_HEIGHT - glwImLineHeight(win)) / 2 + 2, "Bone", ed->showBoneChecked); ed->showMeshChecked = glwImCheck(win, GEN_ID, glwImNextX(win) + ED_SPACING, - bottomY + (ED_TOOLBAR_HEIGHT - glwImLineHeight(win)) / 2 + 2, + toolBarY + (ED_TOOLBAR_HEIGHT - glwImLineHeight(win)) / 2 + 2, "Mesh", ed->showMeshChecked); ed->renderLeft = x + 1; ed->renderTop = glWinY; ed->renderWidth = width - 3; - ed->renderHeight = bottomY - glWinY; + ed->renderHeight = height - ED_TOOLBAR_HEIGHT; if (0 == ed->skl) { ed->skl = skeletonCreate(); @@ -157,15 +180,16 @@ static void display(glwWin *win) { } glEnable(GL_SCISSOR_TEST); - glScissor(ed->renderLeft, ED_SPACING / 2 + ED_TOOLBAR_HEIGHT + 1, + glScissor(ed->renderLeft, ED_SPACING / 2 + 1, ed->renderWidth, ed->renderHeight); glPushMatrix(); - glTranslatef(x + 1, glWinY, 0); + glTranslatef(ed->renderLeft, ed->renderTop, 0); + /* glColor3f(glwR(ED_GL_BACKGROUND_COLOR), glwG(ED_GL_BACKGROUND_COLOR), glwB(ED_GL_BACKGROUND_COLOR)); - glRecti(0, 0, ed->renderWidth, ed->renderHeight); + glRecti(0, 0, ed->renderWidth, ed->renderHeight);*/ glMatrixMode(GL_PROJECTION); glLoadIdentity(); @@ -279,7 +303,7 @@ int main(int argc, char *argv[]) { ed.cameraDistance = 14.4; ed.showMeshChecked = 1; - ed.win = glwCreateWindow(0, 0, 0, 0); + ed.win = glwCreateWindow(0, 0, 600, 480); glwSetUserData(ed.win, &ed); glwReshapeFunc(ed.win, reshape); glwDisplayFunc(ed.win, display); diff --git a/src/glw.c b/src/glw.c index 2bcf14d4..d12bf7b8 100644 --- a/src/glw.c +++ b/src/glw.c @@ -2,8 +2,11 @@ #include #include #include +#include #include "glw_internal.h" #include "glw_style.h" +#include "icons.h" +#include "lodepng.h" #ifndef M_PI #define M_PI 3.14159265 @@ -45,6 +48,44 @@ void glwDrawSystemText(glwWin *win, int x, int y, char *text, glDisable(GL_TEXTURE_2D); } +static int glwGetLineHeight(glwWin *win) { + glwSystemFontTexture *systemFontTexture = glwGetSystemFontTexture(win); + return systemFontTexture->originSize.height * (1 + GLW_VER_AUTO_MARGIN * 2); +} + +void glwDrawSystemIcon(glwWin *win, int x, int y, int icon, + unsigned int color) { + glwWinContext *ctx = glwGetWinContext(win); + float texLeft, texWidth, texTop, texHeight; + icon--; + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, ctx->iconTexId); + glColor3f(glwR(color), glwG(color), glwB(color)); + texLeft = (float)iconTable[icon][ICON_ITEM_LEFT] / ICON_IMAGE_WIDTH; + texTop = (float)iconTable[icon][ICON_ITEM_TOP] / ICON_IMAGE_WIDTH; + texWidth = (float)iconTable[icon][ICON_ITEM_WIDTH] / ICON_IMAGE_WIDTH; + texHeight = (float)iconTable[icon][ICON_ITEM_HEIGHT] / ICON_IMAGE_WIDTH; + x += iconTable[icon][ICON_ITEM_TRIM_OFFSET_LEFT]; + y += (iconTable[icon][ICON_ITEM_TRIM_OFFSET_TOP] + + (glwGetLineHeight(win) - iconTable[icon][ICON_ITEM_ORIGINAL_HEIGHT]) / 4); + glBegin(GL_QUADS); + glTexCoord2f(texLeft, texTop); + glVertex2i(x, y); + + glTexCoord2f(texLeft + texWidth, texTop); + glVertex2i(x + iconTable[icon][ICON_ITEM_WIDTH], y); + + glTexCoord2f(texLeft + texWidth, texTop + texHeight); + glVertex2i(x + iconTable[icon][ICON_ITEM_WIDTH], + y + iconTable[icon][ICON_ITEM_HEIGHT]); + + glTexCoord2f(texLeft, texTop + texHeight); + glVertex2i(x, + y + iconTable[icon][ICON_ITEM_HEIGHT]); + glEnd(); + glDisable(GL_TEXTURE_2D); +} + void glwMouseEvent(glwWin *win, int button, int state, int x, int y) { glwImGui *imGUI = glwGetImGUI(win); imGUI->mouseButton = button; @@ -131,6 +172,40 @@ void glwInitSystemFontTexture(glwWin *win) { glwDestroyFont(font); } +void glwInitSystemIconTexture(glwWin *win) { + glwWinContext *ctx = glwGetWinContext(win); + if (0 == ctx->iconTexId) { + char filename[1024]; + unsigned int err; + unsigned char *imageData = 0; + unsigned int width = 0; + unsigned int height = 0; + GLuint texture = 0; + snprintf(filename, sizeof(filename), "%s/icons.png", ctx->root); + err = lodepng_decode32_file(&imageData, &width, &height, + filename); + if (err) { + fprintf(stderr, "%s: lodepng_decode32_file error: %s\n", __FUNCTION__, + lodepng_error_text(err)); + return; + } + glEnable(GL_TEXTURE_2D); + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD); + glTexImage2D(GL_TEXTURE_2D, 0, 4, + (GLsizei)ICON_IMAGE_WIDTH, + (GLsizei)ICON_IMAGE_HEIGHT, 0, + GL_RGBA, GL_UNSIGNED_BYTE, imageData); + free(imageData); + ctx->iconTexId = (int)texture; + ctx->iconTexWidth = width; + ctx->iconTexHeight = height; + } +} + static glwVec2 glwRoundedCorners[GLW_SMALL_ROUNDED_CORNER_SLICES] = {{0}}; static void createRoundedCorners(glwVec2 *arr, int num) { @@ -512,15 +587,18 @@ int glwImCheck(glwWin *win, int id, int x, int y, char *text, int checked) { return (imGUI->activeId == id && oldActiveId != id) ? !checked : checked; } -static int glwCalcListMaxWidth(glwWin *win, char **list, int *height, - int *len) { +static int glwCalcListMaxWidth(glwWin *win, char **titles, int *icons, + int *height, int *len) { int i; int itemWidth = 0; int maxItemWidth = 0; - for (i = 0; list[i]; ++i) { - glwSize textSize = glwMeasureSystemText(win, list[i]); + for (i = 0; titles[i]; ++i) { + glwSize textSize = glwMeasureSystemText(win, titles[i]); itemWidth = textSize.width * (1 + GLW_HOR_AUTO_MARGIN * 2); + if (icons && icons[i]) { + itemWidth += iconTable[icons[i]][ICON_ITEM_ORIGINAL_WIDTH]; + } if (itemWidth > maxItemWidth) { maxItemWidth = itemWidth; } @@ -532,6 +610,10 @@ static int glwCalcListMaxWidth(glwWin *win, char **list, int *height, } } + if (maxItemWidth < GLW_MIN_TAB_WIDTH) { + maxItemWidth = GLW_MIN_TAB_WIDTH; + } + return maxItemWidth; } @@ -545,7 +627,7 @@ int glwImButtonGroup(glwWin *win, int id, int x, int y, int parentWidth, int listLen = 0; int offset; int maxItemWidth = 0; - maxItemWidth = glwCalcListMaxWidth(win, list, &height, &listLen); + maxItemWidth = glwCalcListMaxWidth(win, list, 0, &height, &listLen); width = maxItemWidth * listLen; left = listLen > 1 ? x + (parentWidth - width) / 2 : x + maxItemWidth * GLW_HOR_AUTO_MARGIN; @@ -600,7 +682,7 @@ int glwImButtonGroup(glwWin *win, int id, int x, int y, int parentWidth, } int glwImTabBox(glwWin *win, int id, int x, int y, int width, int height, - char **list, int sel) { + char **titles, int *icons, int sel) { glwImGui *imGUI = glwGetImGUI(win); int tabWidth = 0; int tabHeight = 0; @@ -609,14 +691,23 @@ int glwImTabBox(glwWin *win, int id, int x, int y, int width, int height, int listLen = 0; int offset; int maxItemWidth = 0; - maxItemWidth = glwCalcListMaxWidth(win, list, &tabHeight, &listLen); + maxItemWidth = glwCalcListMaxWidth(win, titles, icons, &tabHeight, &listLen); tabWidth = maxItemWidth * listLen; - left = x + maxItemWidth * GLW_HOR_AUTO_MARGIN / 2; + left = x; imGUI->nextX = x; imGUI->nextY = y + tabHeight; glwImGUIActiveIdCheck(imGUI, id, left, y, tabWidth, tabHeight); - for (i = 0, offset = left; list[i]; ++i) { - glwSize textSize = glwMeasureSystemText(win, list[i]); + glwDrawRectGradientFill(x + 1, y + tabHeight, + width - 2, height - tabHeight - 2, + GLW_TAB_FILL_GRADIENT_COLOR_2, GLW_TAB_FILL_GRADIENT_COLOR_2); + glwDrawHLine(x, y + tabHeight - 1, width, 1, GLW_BORDER_COLOR_1); + glwDrawHLine(x, y + height - 1, width, 1, GLW_BORDER_COLOR_1); + glwDrawVLine(x, y + tabHeight, 1, height - tabHeight, + GLW_BORDER_COLOR_1); + glwDrawVLine(x + width - 1, y + tabHeight, 1, height - tabHeight, + GLW_BORDER_COLOR_1); + for (i = 0, offset = left; titles[i]; ++i) { + glwSize textSize = glwMeasureSystemText(win, titles[i]); if (imGUI->activeId == id) { int hit = glwPointTest(imGUI->mouseX, imGUI->mouseY, offset, y, maxItemWidth, tabHeight, 0); @@ -625,27 +716,27 @@ int glwImTabBox(glwWin *win, int id, int x, int y, int width, int height, } } if (sel == i) { - glwDrawTopRoundedRectGradientFill(offset, y, - maxItemWidth, tabHeight, - GLW_BUTTON_CORNER_RADIUS, - GLW_TAB_FILL_GRADIENT_COLOR_1, GLW_TAB_FILL_GRADIENT_COLOR_2); glwDrawTopRoundedRectBorder(offset, y, maxItemWidth, tabHeight, GLW_BUTTON_CORNER_RADIUS, GLW_BORDER_COLOR_1); + glwDrawTopRoundedRectGradientFill(offset + 1, y + 1, + maxItemWidth - 2, tabHeight, + GLW_BUTTON_CORNER_RADIUS, + GLW_TAB_FILL_GRADIENT_COLOR_1, GLW_TAB_FILL_GRADIENT_COLOR_2); + } + if (icons && icons[i]) { + int iconIdx = icons[i] - 1; + glwDrawSystemIcon(win, offset + textSize.height / 2, + y + tabHeight * GLW_VER_AUTO_MARGIN, icons[i], GLW_SYSTEM_FONT_COLOR); + glwDrawSystemText(win, offset + textSize.height / 2 + + iconTable[iconIdx][ICON_ITEM_ORIGINAL_WIDTH] + textSize.height / 2, + y + tabHeight * GLW_VER_AUTO_MARGIN, titles[i], GLW_SYSTEM_FONT_COLOR); + } else { + glwDrawSystemText(win, offset + (maxItemWidth - textSize.width) / 2, + y + tabHeight * GLW_VER_AUTO_MARGIN, titles[i], GLW_SYSTEM_FONT_COLOR); } - glwDrawSystemText(win, offset + (maxItemWidth - textSize.width) / 2, - y + tabHeight * GLW_VER_AUTO_MARGIN, list[i], GLW_SYSTEM_FONT_COLOR); offset += maxItemWidth; } - glwDrawRectGradientFill(x + 1, y + tabHeight, - width - 2, height - tabHeight - 2, - GLW_BACKGROUND_COLOR, GLW_BACKGROUND_COLOR); - glwDrawHLine(x, y + tabHeight - 1, width, 1, GLW_BORDER_COLOR_1); - glwDrawHLine(x, y + height - 1, width, 1, GLW_BORDER_COLOR_1); - glwDrawVLine(x, y + tabHeight, 1, height - tabHeight, - GLW_BORDER_COLOR_1); - glwDrawVLine(x + width - 1, y + tabHeight, 1, height - tabHeight, - GLW_BORDER_COLOR_1); return sel; } @@ -688,8 +779,7 @@ int glwImNextY(glwWin *win) { } int glwImLineHeight(glwWin *win) { - glwSystemFontTexture *systemFontTexture = glwGetSystemFontTexture(win); - return systemFontTexture->originSize.height * (1 + GLW_VER_AUTO_MARGIN * 2); + return glwGetLineHeight(win); } void glwSetUserData(glwWin *win, void *userData) { @@ -745,3 +835,5 @@ int glwMouseY(glwWin *win) { glwWinContext *ctx = glwGetWinContext(win); return ctx->y; } + + diff --git a/src/glw.h b/src/glw.h index 6120e39b..52e2e829 100644 --- a/src/glw.h +++ b/src/glw.h @@ -55,7 +55,7 @@ int glwImButtonGroup(glwWin *win, int id, int x, int y, int parentWidth, char **list, int sel); int glwImPanel(glwWin *win, int id, int x, int y, int width, int height); int glwImTabBox(glwWin *win, int id, int x, int y, int width, int height, - char **list, int sel); + char **titles, int *icons, int sel); int glwImToolBar(glwWin *win, int id, int x, int y, int width, int height); int glwImBottomBar(glwWin *win, int id, int x, int y, int width, int height); int glwImNextX(glwWin *win); diff --git a/src/glw_internal.h b/src/glw_internal.h index 93a5be4e..56d454f3 100644 --- a/src/glw_internal.h +++ b/src/glw_internal.h @@ -30,6 +30,10 @@ typedef struct glwWinContext { void *userData; int x; int y; + int iconTexId; + int iconTexWidth; + int iconTexHeight; + char root[1024]; } glwWinContext; typedef struct glwSystemFontTexture { @@ -56,6 +60,8 @@ unsigned char *glwRenderTextToRGBA(char *text, glwFont *font, glwSize size, void glwDrawText(int x, int y, char *text, glwFont *font); void glwDrawSystemText(glwWin *win, int x, int y, char *text, unsigned int color); +void glwDrawSystemIcon(glwWin *win, int x, int y, int icon, + unsigned int color); glwSize glwMeasureSystemText(glwWin *win, char *text); void glwInitSystemFontTexture(glwWin *win); void glwInitPrimitives(void); @@ -68,5 +74,6 @@ void glwDrawButtonBackground(float x, float y, float width, float height, void glwMouseEvent(glwWin *win, int button, int state, int x, int y); glwImGui *glwGetImGUI(glwWin *win); glwWinContext *glwGetWinContext(glwWin *win); +void glwInitSystemIconTexture(glwWin *win); #endif diff --git a/src/glw_osx.m b/src/glw_osx.m index b702510b..a77067ec 100644 --- a/src/glw_osx.m +++ b/src/glw_osx.m @@ -80,6 +80,9 @@ glwWinContext *glwGetWinContext(glwWin *win) { if (self->pendingReshape) { if (self->context.onReshape) { self->pendingReshape = 0; + if (!self->context.iconTexId) { + glwInitSystemIconTexture((glwWin *)self.window); + } if (!self->systemFontTexture.texId) { glwInitSystemFontTexture((glwWin *)self.window); } @@ -225,10 +228,11 @@ glwImGui *glwGetImGUI(glwWin *win) { } glwFont *glwCreateFont(char *name, int weight, int size, int bold) { - NSString *fontFamily = [NSString stringWithCString:name + NSString *fontFamily = [NSString stringWithCString:name encoding:NSMacOSRomanStringEncoding]; NSFont *font = [[[NSFontManager sharedFontManager] fontWithFamily:fontFamily traits:(bold ? NSBoldFontMask : NSUnboldFontMask) weight:weight size:size] retain]; + //NSLog(@"%@",[[[NSFontManager sharedFontManager] availableFontFamilies] description]); return (glwFont *)font; } @@ -281,6 +285,13 @@ glwWin *glwCreateWindow(int x, int y, int width, int height) { view->context.scaleX = 1; view->context.scaleY = 1; + CFBundleRef mainBundle = CFBundleGetMainBundle(); + CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle); + CFURLGetFileSystemRepresentation(resourcesURL, TRUE, + (UInt8 *)view->context.root, + sizeof(view->context.root)); + CFRelease(resourcesURL); + [window setAcceptsMouseMovedEvents:YES]; [window setContentView:view]; [window setDelegate:view]; diff --git a/src/glw_style.h b/src/glw_style.h index 8974f20f..1242a1ba 100644 --- a/src/glw_style.h +++ b/src/glw_style.h @@ -1,15 +1,15 @@ #ifndef GLW_STYLE_H #define GLW_STYLE_H -#define GLW_SYSTEM_FONT_NAME "Helvetica" -#define GLW_SYSTEM_FONT_WEIGHT 5 -#define GLW_SYSTEM_FONT_SIZE 21 -#define GLW_SYSTEM_FONT_COLOR 0x8f8f8f +#define GLW_SYSTEM_FONT_NAME "PT Sans Narrow" //"Monaco" //"Helvetica" +#define GLW_SYSTEM_FONT_WEIGHT 10 +#define GLW_SYSTEM_FONT_SIZE 20 +#define GLW_SYSTEM_FONT_COLOR 0xb9b9b9 #define GLW_SMALL_ROUNDED_CORNER_SLICES 5 -#define GLW_BORDER_COLOR_1 0x161616 -#define GLW_BORDER_COLOR_2 0x161616 +#define GLW_BORDER_COLOR_1 0x000000 +#define GLW_BORDER_COLOR_2 0x000000 #define GLW_FILL_GRADIENT_COLOR_1 0x424242 #define GLW_FILL_GRADIENT_COLOR_2 0x242424 @@ -33,6 +33,8 @@ #define GLW_VER_AUTO_MARGIN 0.15 #define GLW_BACKGROUND_COLOR 0x373737 -#define GLW_TOOLBAR_BACKGROUND_COLOR 0x252525 +#define GLW_TOOLBAR_BACKGROUND_COLOR GLW_TAB_FILL_GRADIENT_COLOR_2 + +#define GLW_MIN_TAB_WIDTH 120 #endif diff --git a/src/icons.c b/src/icons.c new file mode 100644 index 00000000..49bda980 --- /dev/null +++ b/src/icons.c @@ -0,0 +1,28 @@ +//THIS FILE IS GENERATED AUTOMATICALLY BY https://github.com/huxingyi/squeezer, PLEASE DONT MODIFY IT MANUALLY. + +#include "icons.h" + +const int iconTable[][ICON_ITEM_MAX] = { + {12, 16, 0, 96, 2, 0, 16, 16} /*"unlock.png"*/, + {16, 16, 0, 32, 0, 0, 16, 16} /*"unlink.png"*/, + {16, 14, 8, 112, 0, 0, 16, 16} /*"undo.png"*/, + {14, 16, 0, 80, 0, 0, 16, 16} /*"trash.png"*/, + {16, 16, 0, 16, 0, 0, 16, 16} /*"tool.png"*/, + {12, 12, 28, 16, 2, 2, 16, 16} /*"stop.png"*/, + {16, 16, 112, 0, 0, 0, 16, 16} /*"reload.png"*/, + {16, 16, 96, 0, 0, 0, 16, 16} /*"plus.png"*/, + {12, 12, 16, 28, 2, 2, 16, 16} /*"play.png"*/, + {14, 16, 0, 64, 0, 0, 16, 16} /*"pin.png"*/, + {16, 16, 80, 0, 0, 0, 16, 16} /*"pencil.png"*/, + {12, 12, 16, 16, 2, 2, 16, 16} /*"pause.png"*/, + {16, 16, 64, 0, 0, 0, 16, 16} /*"monitor.png"*/, + {16, 4, 16, 40, 0, 6, 16, 16} /*"minus.png"*/, + {12, 14, 12, 96, 2, 0, 16, 16} /*"lock.png"*/, + {16, 16, 48, 0, 0, 0, 16, 16} /*"link.png"*/, + {8, 16, 0, 112, 4, 0, 16, 16} /*"info.png"*/, + {16, 16, 32, 0, 0, 0, 16, 16} /*"image.png"*/, + {16, 16, 16, 0, 0, 0, 16, 16} /*"folder.png"*/, + {14, 16, 0, 48, 0, 0, 16, 16} /*"file.png"*/, + {16, 16, 0, 0, 0, 0, 16, 16} /*"eyedropper.png"*/, + {16, 12, 14, 48, 0, 2, 16, 16} /*"eye.png"*/ +}; diff --git a/src/icons.h b/src/icons.h new file mode 100644 index 00000000..3dec6bb4 --- /dev/null +++ b/src/icons.h @@ -0,0 +1,48 @@ +#ifndef ICONS_H +#define ICONS_H + +typedef enum { + ICON_ITEM_WIDTH, + ICON_ITEM_HEIGHT, + ICON_ITEM_LEFT, + ICON_ITEM_TOP, + ICON_ITEM_TRIM_OFFSET_LEFT, + ICON_ITEM_TRIM_OFFSET_TOP, + ICON_ITEM_ORIGINAL_WIDTH, + ICON_ITEM_ORIGINAL_HEIGHT, + ICON_ITEM_MAX +} iconItem; + +#define ICON_IMAGE_WIDTH 128 +#define ICON_IMAGE_HEIGHT 128 + +typedef enum { + ICON_UNKNOWN, + ICON_UNLOCK, + ICON_UNLINK, + ICON_UNDO, + ICON_TRASH, + ICON_TOOL, + ICON_STOP, + ICON_RELOAD, + ICON_PLUS, + ICON_PLAY, + ICON_PIN, + ICON_PENCIL, + ICON_PAUSE, + ICON_MONITOR, + ICON_MINUS, + ICON_LOCK, + ICON_LINK, + ICON_INFO, + ICON_IMAGE, + ICON_FOLDER, + ICON_FILE, + ICON_EYEDROPPER, + ICON_EYE, + ICON_MAX +} iconId; + +const int iconTable[ICON_MAX][ICON_ITEM_MAX]; + +#endif diff --git a/src/lodepng.c b/src/lodepng.c new file mode 100755 index 00000000..8c78758f --- /dev/null +++ b/src/lodepng.c @@ -0,0 +1,6224 @@ +/* +LodePNG version 20160501 + +Copyright (c) 2005-2016 Lode Vandevenne + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +/* +The manual and changelog are in the header file "lodepng.h" +Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for C. +*/ + +#include "lodepng.h" + +#include +#include +#include + +#if defined(_MSC_VER) && (_MSC_VER >= 1310) /*Visual Studio: A few warning types are not desired here.*/ +#pragma warning( disable : 4244 ) /*implicit conversions: not warned by gcc -Wall -Wextra and requires too much casts*/ +#pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/ +#endif /*_MSC_VER */ + +const char* LODEPNG_VERSION_STRING = "20160501"; + +/* +This source file is built up in the following large parts. The code sections +with the "LODEPNG_COMPILE_" #defines divide this up further in an intermixed way. +-Tools for C and common code for PNG and Zlib +-C Code for Zlib (huffman, deflate, ...) +-C Code for PNG (file format chunks, adam7, PNG filters, color conversions, ...) +-The C++ wrapper around all of the above +*/ + +/*The malloc, realloc and free functions defined here with "lodepng_" in front +of the name, so that you can easily change them to others related to your +platform if needed. Everything else in the code calls these. Pass +-DLODEPNG_NO_COMPILE_ALLOCATORS to the compiler, or comment out +#define LODEPNG_COMPILE_ALLOCATORS in the header, to disable the ones here and +define them in your own project's source files without needing to change +lodepng source code. Don't forget to remove "static" if you copypaste them +from here.*/ + +#ifdef LODEPNG_COMPILE_ALLOCATORS +static void* lodepng_malloc(size_t size) +{ + return malloc(size); +} + +static void* lodepng_realloc(void* ptr, size_t new_size) +{ + return realloc(ptr, new_size); +} + +static void lodepng_free(void* ptr) +{ + free(ptr); +} +#else /*LODEPNG_COMPILE_ALLOCATORS*/ +void* lodepng_malloc(size_t size); +void* lodepng_realloc(void* ptr, size_t new_size); +void lodepng_free(void* ptr); +#endif /*LODEPNG_COMPILE_ALLOCATORS*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // Tools for C, and common code for PNG and Zlib. // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/* +Often in case of an error a value is assigned to a variable and then it breaks +out of a loop (to go to the cleanup phase of a function). This macro does that. +It makes the error handling code shorter and more readable. + +Example: if(!uivector_resizev(&frequencies_ll, 286, 0)) ERROR_BREAK(83); +*/ +#define CERROR_BREAK(errorvar, code)\ +{\ + errorvar = code;\ + break;\ +} + +/*version of CERROR_BREAK that assumes the common case where the error variable is named "error"*/ +#define ERROR_BREAK(code) CERROR_BREAK(error, code) + +/*Set error var to the error code, and return it.*/ +#define CERROR_RETURN_ERROR(errorvar, code)\ +{\ + errorvar = code;\ + return code;\ +} + +/*Try the code, if it returns error, also return the error.*/ +#define CERROR_TRY_RETURN(call)\ +{\ + unsigned error = call;\ + if(error) return error;\ +} + +/*Set error var to the error code, and return from the void function.*/ +#define CERROR_RETURN(errorvar, code)\ +{\ + errorvar = code;\ + return;\ +} + +/* +About uivector, ucvector and string: +-All of them wrap dynamic arrays or text strings in a similar way. +-LodePNG was originally written in C++. The vectors replace the std::vectors that were used in the C++ version. +-The string tools are made to avoid problems with compilers that declare things like strncat as deprecated. +-They're not used in the interface, only internally in this file as static functions. +-As with many other structs in this file, the init and cleanup functions serve as ctor and dtor. +*/ + +#ifdef LODEPNG_COMPILE_ZLIB +/*dynamic vector of unsigned ints*/ +typedef struct uivector +{ + unsigned* data; + size_t size; /*size in number of unsigned longs*/ + size_t allocsize; /*allocated size in bytes*/ +} uivector; + +static void uivector_cleanup(void* p) +{ + ((uivector*)p)->size = ((uivector*)p)->allocsize = 0; + lodepng_free(((uivector*)p)->data); + ((uivector*)p)->data = NULL; +} + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned uivector_reserve(uivector* p, size_t allocsize) +{ + if(allocsize > p->allocsize) + { + size_t newsize = (allocsize > p->allocsize * 2) ? allocsize : (allocsize * 3 / 2); + void* data = lodepng_realloc(p->data, newsize); + if(data) + { + p->allocsize = newsize; + p->data = (unsigned*)data; + } + else return 0; /*error: not enough memory*/ + } + return 1; +} + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned uivector_resize(uivector* p, size_t size) +{ + if(!uivector_reserve(p, size * sizeof(unsigned))) return 0; + p->size = size; + return 1; /*success*/ +} + +/*resize and give all new elements the value*/ +static unsigned uivector_resizev(uivector* p, size_t size, unsigned value) +{ + size_t oldsize = p->size, i; + if(!uivector_resize(p, size)) return 0; + for(i = oldsize; i < size; ++i) p->data[i] = value; + return 1; +} + +static void uivector_init(uivector* p) +{ + p->data = NULL; + p->size = p->allocsize = 0; +} + +#ifdef LODEPNG_COMPILE_ENCODER +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned uivector_push_back(uivector* p, unsigned c) +{ + if(!uivector_resize(p, p->size + 1)) return 0; + p->data[p->size - 1] = c; + return 1; +} +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_ZLIB*/ + +/* /////////////////////////////////////////////////////////////////////////// */ + +/*dynamic vector of unsigned chars*/ +typedef struct ucvector +{ + unsigned char* data; + size_t size; /*used size*/ + size_t allocsize; /*allocated size*/ +} ucvector; + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned ucvector_reserve(ucvector* p, size_t allocsize) +{ + if(allocsize > p->allocsize) + { + size_t newsize = (allocsize > p->allocsize * 2) ? allocsize : (allocsize * 3 / 2); + void* data = lodepng_realloc(p->data, newsize); + if(data) + { + p->allocsize = newsize; + p->data = (unsigned char*)data; + } + else return 0; /*error: not enough memory*/ + } + return 1; +} + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned ucvector_resize(ucvector* p, size_t size) +{ + if(!ucvector_reserve(p, size * sizeof(unsigned char))) return 0; + p->size = size; + return 1; /*success*/ +} + +#ifdef LODEPNG_COMPILE_PNG + +static void ucvector_cleanup(void* p) +{ + ((ucvector*)p)->size = ((ucvector*)p)->allocsize = 0; + lodepng_free(((ucvector*)p)->data); + ((ucvector*)p)->data = NULL; +} + +static void ucvector_init(ucvector* p) +{ + p->data = NULL; + p->size = p->allocsize = 0; +} +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ZLIB +/*you can both convert from vector to buffer&size and vica versa. If you use +init_buffer to take over a buffer and size, it is not needed to use cleanup*/ +static void ucvector_init_buffer(ucvector* p, unsigned char* buffer, size_t size) +{ + p->data = buffer; + p->allocsize = p->size = size; +} +#endif /*LODEPNG_COMPILE_ZLIB*/ + +#if (defined(LODEPNG_COMPILE_PNG) && defined(LODEPNG_COMPILE_ANCILLARY_CHUNKS)) || defined(LODEPNG_COMPILE_ENCODER) +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned ucvector_push_back(ucvector* p, unsigned char c) +{ + if(!ucvector_resize(p, p->size + 1)) return 0; + p->data[p->size - 1] = c; + return 1; +} +#endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/ + + +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_PNG +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned string_resize(char** out, size_t size) +{ + char* data = (char*)lodepng_realloc(*out, size + 1); + if(data) + { + data[size] = 0; /*null termination char*/ + *out = data; + } + return data != 0; +} + +/*init a {char*, size_t} pair for use as string*/ +static void string_init(char** out) +{ + *out = NULL; + string_resize(out, 0); +} + +/*free the above pair again*/ +static void string_cleanup(char** out) +{ + lodepng_free(*out); + *out = NULL; +} + +static void string_set(char** out, const char* in) +{ + size_t insize = strlen(in), i; + if(string_resize(out, insize)) + { + for(i = 0; i != insize; ++i) + { + (*out)[i] = in[i]; + } + } +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +/* ////////////////////////////////////////////////////////////////////////// */ + +unsigned lodepng_read32bitInt(const unsigned char* buffer) +{ + return (unsigned)((buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]); +} + +#if defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER) +/*buffer must have at least 4 allocated bytes available*/ +static void lodepng_set32bitInt(unsigned char* buffer, unsigned value) +{ + buffer[0] = (unsigned char)((value >> 24) & 0xff); + buffer[1] = (unsigned char)((value >> 16) & 0xff); + buffer[2] = (unsigned char)((value >> 8) & 0xff); + buffer[3] = (unsigned char)((value ) & 0xff); +} +#endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/ + +#ifdef LODEPNG_COMPILE_ENCODER +static void lodepng_add32bitInt(ucvector* buffer, unsigned value) +{ + ucvector_resize(buffer, buffer->size + 4); /*todo: give error if resize failed*/ + lodepng_set32bitInt(&buffer->data[buffer->size - 4], value); +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / File IO / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_DISK + +/* returns negative value on error. This should be pure C compatible, so no fstat. */ +static long lodepng_filesize(const char* filename) +{ + FILE* file; + long size; + file = fopen(filename, "rb"); + if(!file) return -1; + + if(fseek(file, 0, SEEK_END) != 0) + { + fclose(file); + return -1; + } + + size = ftell(file); + /* It may give LONG_MAX as directory size, this is invalid for us. */ + if(size == LONG_MAX) size = -1; + + fclose(file); + return size; +} + +/* load file into buffer that already has the correct allocated size. Returns error code.*/ +static unsigned lodepng_buffer_file(unsigned char* out, size_t size, const char* filename) +{ + FILE* file; + size_t readsize; + file = fopen(filename, "rb"); + if(!file) return 78; + + readsize = fread(out, 1, size, file); + fclose(file); + + if (readsize != size) return 78; + return 0; +} + +unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename) +{ + long size = lodepng_filesize(filename); + if (size < 0) return 78; + *outsize = (size_t)size; + + *out = (unsigned char*)lodepng_malloc((size_t)size); + if(!(*out) && size > 0) return 83; /*the above malloc failed*/ + + return lodepng_buffer_file(*out, (size_t)size, filename); +} + +/*write given buffer to the file, overwriting the file, it doesn't append to it.*/ +unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename) +{ + FILE* file; + file = fopen(filename, "wb" ); + if(!file) return 79; + fwrite((char*)buffer , 1 , buffersize, file); + fclose(file); + return 0; +} + +#endif /*LODEPNG_COMPILE_DISK*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // End of common code and tools. Begin of Zlib related code. // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_ZLIB +#ifdef LODEPNG_COMPILE_ENCODER +/*TODO: this ignores potential out of memory errors*/ +#define addBitToStream(/*size_t**/ bitpointer, /*ucvector**/ bitstream, /*unsigned char*/ bit)\ +{\ + /*add a new byte at the end*/\ + if(((*bitpointer) & 7) == 0) ucvector_push_back(bitstream, (unsigned char)0);\ + /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/\ + (bitstream->data[bitstream->size - 1]) |= (bit << ((*bitpointer) & 0x7));\ + ++(*bitpointer);\ +} + +static void addBitsToStream(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits) +{ + size_t i; + for(i = 0; i != nbits; ++i) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> i) & 1)); +} + +static void addBitsToStreamReversed(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits) +{ + size_t i; + for(i = 0; i != nbits; ++i) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> (nbits - 1 - i)) & 1)); +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_DECODER + +#define READBIT(bitpointer, bitstream) ((bitstream[bitpointer >> 3] >> (bitpointer & 0x7)) & (unsigned char)1) + +static unsigned char readBitFromStream(size_t* bitpointer, const unsigned char* bitstream) +{ + unsigned char result = (unsigned char)(READBIT(*bitpointer, bitstream)); + ++(*bitpointer); + return result; +} + +static unsigned readBitsFromStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits) +{ + unsigned result = 0, i; + for(i = 0; i != nbits; ++i) + { + result += ((unsigned)READBIT(*bitpointer, bitstream)) << i; + ++(*bitpointer); + } + return result; +} +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Deflate - Huffman / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#define FIRST_LENGTH_CODE_INDEX 257 +#define LAST_LENGTH_CODE_INDEX 285 +/*256 literals, the end code, some length codes, and 2 unused codes*/ +#define NUM_DEFLATE_CODE_SYMBOLS 288 +/*the distance codes have their own symbols, 30 used, 2 unused*/ +#define NUM_DISTANCE_SYMBOLS 32 +/*the code length codes. 0-15: code lengths, 16: copy previous 3-6 times, 17: 3-10 zeros, 18: 11-138 zeros*/ +#define NUM_CODE_LENGTH_CODES 19 + +/*the base lengths represented by codes 257-285*/ +static const unsigned LENGTHBASE[29] + = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, + 67, 83, 99, 115, 131, 163, 195, 227, 258}; + +/*the extra bits used by codes 257-285 (added to base length)*/ +static const unsigned LENGTHEXTRA[29] + = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 5, 5, 5, 5, 0}; + +/*the base backwards distances (the bits of distance codes appear after length codes and use their own huffman tree)*/ +static const unsigned DISTANCEBASE[30] + = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, + 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; + +/*the extra bits of backwards distances (added to base)*/ +static const unsigned DISTANCEEXTRA[30] + = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; + +/*the order in which "code length alphabet code lengths" are stored, out of this +the huffman tree of the dynamic huffman tree lengths is generated*/ +static const unsigned CLCL_ORDER[NUM_CODE_LENGTH_CODES] + = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* ////////////////////////////////////////////////////////////////////////// */ + +/* +Huffman tree struct, containing multiple representations of the tree +*/ +typedef struct HuffmanTree +{ + unsigned* tree2d; + unsigned* tree1d; + unsigned* lengths; /*the lengths of the codes of the 1d-tree*/ + unsigned maxbitlen; /*maximum number of bits a single code can get*/ + unsigned numcodes; /*number of symbols in the alphabet = number of codes*/ +} HuffmanTree; + +/*function used for debug purposes to draw the tree in ascii art with C++*/ +/* +static void HuffmanTree_draw(HuffmanTree* tree) +{ + std::cout << "tree. length: " << tree->numcodes << " maxbitlen: " << tree->maxbitlen << std::endl; + for(size_t i = 0; i != tree->tree1d.size; ++i) + { + if(tree->lengths.data[i]) + std::cout << i << " " << tree->tree1d.data[i] << " " << tree->lengths.data[i] << std::endl; + } + std::cout << std::endl; +}*/ + +static void HuffmanTree_init(HuffmanTree* tree) +{ + tree->tree2d = 0; + tree->tree1d = 0; + tree->lengths = 0; +} + +static void HuffmanTree_cleanup(HuffmanTree* tree) +{ + lodepng_free(tree->tree2d); + lodepng_free(tree->tree1d); + lodepng_free(tree->lengths); +} + +/*the tree representation used by the decoder. return value is error*/ +static unsigned HuffmanTree_make2DTree(HuffmanTree* tree) +{ + unsigned nodefilled = 0; /*up to which node it is filled*/ + unsigned treepos = 0; /*position in the tree (1 of the numcodes columns)*/ + unsigned n, i; + + tree->tree2d = (unsigned*)lodepng_malloc(tree->numcodes * 2 * sizeof(unsigned)); + if(!tree->tree2d) return 83; /*alloc fail*/ + + /* + convert tree1d[] to tree2d[][]. In the 2D array, a value of 32767 means + uninited, a value >= numcodes is an address to another bit, a value < numcodes + is a code. The 2 rows are the 2 possible bit values (0 or 1), there are as + many columns as codes - 1. + A good huffman tree has N * 2 - 1 nodes, of which N - 1 are internal nodes. + Here, the internal nodes are stored (what their 0 and 1 option point to). + There is only memory for such good tree currently, if there are more nodes + (due to too long length codes), error 55 will happen + */ + for(n = 0; n < tree->numcodes * 2; ++n) + { + tree->tree2d[n] = 32767; /*32767 here means the tree2d isn't filled there yet*/ + } + + for(n = 0; n < tree->numcodes; ++n) /*the codes*/ + { + for(i = 0; i != tree->lengths[n]; ++i) /*the bits for this code*/ + { + unsigned char bit = (unsigned char)((tree->tree1d[n] >> (tree->lengths[n] - i - 1)) & 1); + /*oversubscribed, see comment in lodepng_error_text*/ + if(treepos > 2147483647 || treepos + 2 > tree->numcodes) return 55; + if(tree->tree2d[2 * treepos + bit] == 32767) /*not yet filled in*/ + { + if(i + 1 == tree->lengths[n]) /*last bit*/ + { + tree->tree2d[2 * treepos + bit] = n; /*put the current code in it*/ + treepos = 0; + } + else + { + /*put address of the next step in here, first that address has to be found of course + (it's just nodefilled + 1)...*/ + ++nodefilled; + /*addresses encoded with numcodes added to it*/ + tree->tree2d[2 * treepos + bit] = nodefilled + tree->numcodes; + treepos = nodefilled; + } + } + else treepos = tree->tree2d[2 * treepos + bit] - tree->numcodes; + } + } + + for(n = 0; n < tree->numcodes * 2; ++n) + { + if(tree->tree2d[n] == 32767) tree->tree2d[n] = 0; /*remove possible remaining 32767's*/ + } + + return 0; +} + +/* +Second step for the ...makeFromLengths and ...makeFromFrequencies functions. +numcodes, lengths and maxbitlen must already be filled in correctly. return +value is error. +*/ +static unsigned HuffmanTree_makeFromLengths2(HuffmanTree* tree) +{ + uivector blcount; + uivector nextcode; + unsigned error = 0; + unsigned bits, n; + + uivector_init(&blcount); + uivector_init(&nextcode); + + tree->tree1d = (unsigned*)lodepng_malloc(tree->numcodes * sizeof(unsigned)); + if(!tree->tree1d) error = 83; /*alloc fail*/ + + if(!uivector_resizev(&blcount, tree->maxbitlen + 1, 0) + || !uivector_resizev(&nextcode, tree->maxbitlen + 1, 0)) + error = 83; /*alloc fail*/ + + if(!error) + { + /*step 1: count number of instances of each code length*/ + for(bits = 0; bits != tree->numcodes; ++bits) ++blcount.data[tree->lengths[bits]]; + /*step 2: generate the nextcode values*/ + for(bits = 1; bits <= tree->maxbitlen; ++bits) + { + nextcode.data[bits] = (nextcode.data[bits - 1] + blcount.data[bits - 1]) << 1; + } + /*step 3: generate all the codes*/ + for(n = 0; n != tree->numcodes; ++n) + { + if(tree->lengths[n] != 0) tree->tree1d[n] = nextcode.data[tree->lengths[n]]++; + } + } + + uivector_cleanup(&blcount); + uivector_cleanup(&nextcode); + + if(!error) return HuffmanTree_make2DTree(tree); + else return error; +} + +/* +given the code lengths (as stored in the PNG file), generate the tree as defined +by Deflate. maxbitlen is the maximum bits that a code in the tree can have. +return value is error. +*/ +static unsigned HuffmanTree_makeFromLengths(HuffmanTree* tree, const unsigned* bitlen, + size_t numcodes, unsigned maxbitlen) +{ + unsigned i; + tree->lengths = (unsigned*)lodepng_malloc(numcodes * sizeof(unsigned)); + if(!tree->lengths) return 83; /*alloc fail*/ + for(i = 0; i != numcodes; ++i) tree->lengths[i] = bitlen[i]; + tree->numcodes = (unsigned)numcodes; /*number of symbols*/ + tree->maxbitlen = maxbitlen; + return HuffmanTree_makeFromLengths2(tree); +} + +#ifdef LODEPNG_COMPILE_ENCODER + +/*BPM: Boundary Package Merge, see "A Fast and Space-Economical Algorithm for Length-Limited Coding", +Jyrki Katajainen, Alistair Moffat, Andrew Turpin, 1995.*/ + +/*chain node for boundary package merge*/ +typedef struct BPMNode +{ + int weight; /*the sum of all weights in this chain*/ + unsigned index; /*index of this leaf node (called "count" in the paper)*/ + struct BPMNode* tail; /*the next nodes in this chain (null if last)*/ + int in_use; +} BPMNode; + +/*lists of chains*/ +typedef struct BPMLists +{ + /*memory pool*/ + unsigned memsize; + BPMNode* memory; + unsigned numfree; + unsigned nextfree; + BPMNode** freelist; + /*two heads of lookahead chains per list*/ + unsigned listsize; + BPMNode** chains0; + BPMNode** chains1; +} BPMLists; + +/*creates a new chain node with the given parameters, from the memory in the lists */ +static BPMNode* bpmnode_create(BPMLists* lists, int weight, unsigned index, BPMNode* tail) +{ + unsigned i; + BPMNode* result; + + /*memory full, so garbage collect*/ + if(lists->nextfree >= lists->numfree) + { + /*mark only those that are in use*/ + for(i = 0; i != lists->memsize; ++i) lists->memory[i].in_use = 0; + for(i = 0; i != lists->listsize; ++i) + { + BPMNode* node; + for(node = lists->chains0[i]; node != 0; node = node->tail) node->in_use = 1; + for(node = lists->chains1[i]; node != 0; node = node->tail) node->in_use = 1; + } + /*collect those that are free*/ + lists->numfree = 0; + for(i = 0; i != lists->memsize; ++i) + { + if(!lists->memory[i].in_use) lists->freelist[lists->numfree++] = &lists->memory[i]; + } + lists->nextfree = 0; + } + + result = lists->freelist[lists->nextfree++]; + result->weight = weight; + result->index = index; + result->tail = tail; + return result; +} + +/*sort the leaves with stable mergesort*/ +static void bpmnode_sort(BPMNode* leaves, size_t num) +{ + BPMNode* mem = (BPMNode*)lodepng_malloc(sizeof(*leaves) * num); + size_t width, counter = 0; + for(width = 1; width < num; width *= 2) + { + BPMNode* a = (counter & 1) ? mem : leaves; + BPMNode* b = (counter & 1) ? leaves : mem; + size_t p; + for(p = 0; p < num; p += 2 * width) + { + size_t q = (p + width > num) ? num : (p + width); + size_t r = (p + 2 * width > num) ? num : (p + 2 * width); + size_t i = p, j = q, k; + for(k = p; k < r; k++) + { + if(i < q && (j >= r || a[i].weight <= a[j].weight)) b[k] = a[i++]; + else b[k] = a[j++]; + } + } + counter++; + } + if(counter & 1) memcpy(leaves, mem, sizeof(*leaves) * num); + lodepng_free(mem); +} + +/*Boundary Package Merge step, numpresent is the amount of leaves, and c is the current chain.*/ +static void boundaryPM(BPMLists* lists, BPMNode* leaves, size_t numpresent, int c, int num) +{ + unsigned lastindex = lists->chains1[c]->index; + + if(c == 0) + { + if(lastindex >= numpresent) return; + lists->chains0[c] = lists->chains1[c]; + lists->chains1[c] = bpmnode_create(lists, leaves[lastindex].weight, lastindex + 1, 0); + } + else + { + /*sum of the weights of the head nodes of the previous lookahead chains.*/ + int sum = lists->chains0[c - 1]->weight + lists->chains1[c - 1]->weight; + lists->chains0[c] = lists->chains1[c]; + if(lastindex < numpresent && sum > leaves[lastindex].weight) + { + lists->chains1[c] = bpmnode_create(lists, leaves[lastindex].weight, lastindex + 1, lists->chains1[c]->tail); + return; + } + lists->chains1[c] = bpmnode_create(lists, sum, lastindex, lists->chains1[c - 1]); + /*in the end we are only interested in the chain of the last list, so no + need to recurse if we're at the last one (this gives measurable speedup)*/ + if(num + 1 < (int)(2 * numpresent - 2)) + { + boundaryPM(lists, leaves, numpresent, c - 1, num); + boundaryPM(lists, leaves, numpresent, c - 1, num); + } + } +} + +unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, + size_t numcodes, unsigned maxbitlen) +{ + unsigned error = 0; + unsigned i; + size_t numpresent = 0; /*number of symbols with non-zero frequency*/ + BPMNode* leaves; /*the symbols, only those with > 0 frequency*/ + + if(numcodes == 0) return 80; /*error: a tree of 0 symbols is not supposed to be made*/ + if((1u << maxbitlen) < numcodes) return 80; /*error: represent all symbols*/ + + leaves = (BPMNode*)lodepng_malloc(numcodes * sizeof(*leaves)); + if(!leaves) return 83; /*alloc fail*/ + + for(i = 0; i != numcodes; ++i) + { + if(frequencies[i] > 0) + { + leaves[numpresent].weight = (int)frequencies[i]; + leaves[numpresent].index = i; + ++numpresent; + } + } + + for(i = 0; i != numcodes; ++i) lengths[i] = 0; + + /*ensure at least two present symbols. There should be at least one symbol + according to RFC 1951 section 3.2.7. Some decoders incorrectly require two. To + make these work as well ensure there are at least two symbols. The + Package-Merge code below also doesn't work correctly if there's only one + symbol, it'd give it the theoritical 0 bits but in practice zlib wants 1 bit*/ + if(numpresent == 0) + { + lengths[0] = lengths[1] = 1; /*note that for RFC 1951 section 3.2.7, only lengths[0] = 1 is needed*/ + } + else if(numpresent == 1) + { + lengths[leaves[0].index] = 1; + lengths[leaves[0].index == 0 ? 1 : 0] = 1; + } + else + { + BPMLists lists; + BPMNode* node; + + bpmnode_sort(leaves, numpresent); + + lists.listsize = maxbitlen; + lists.memsize = 2 * maxbitlen * (maxbitlen + 1); + lists.nextfree = 0; + lists.numfree = lists.memsize; + lists.memory = (BPMNode*)lodepng_malloc(lists.memsize * sizeof(*lists.memory)); + lists.freelist = (BPMNode**)lodepng_malloc(lists.memsize * sizeof(BPMNode*)); + lists.chains0 = (BPMNode**)lodepng_malloc(lists.listsize * sizeof(BPMNode*)); + lists.chains1 = (BPMNode**)lodepng_malloc(lists.listsize * sizeof(BPMNode*)); + if(!lists.memory || !lists.freelist || !lists.chains0 || !lists.chains1) error = 83; /*alloc fail*/ + + if(!error) + { + for(i = 0; i != lists.memsize; ++i) lists.freelist[i] = &lists.memory[i]; + + bpmnode_create(&lists, leaves[0].weight, 1, 0); + bpmnode_create(&lists, leaves[1].weight, 2, 0); + + for(i = 0; i != lists.listsize; ++i) + { + lists.chains0[i] = &lists.memory[0]; + lists.chains1[i] = &lists.memory[1]; + } + + /*each boundaryPM call adds one chain to the last list, and we need 2 * numpresent - 2 chains.*/ + for(i = 2; i != 2 * numpresent - 2; ++i) boundaryPM(&lists, leaves, numpresent, (int)maxbitlen - 1, (int)i); + + for(node = lists.chains1[maxbitlen - 1]; node; node = node->tail) + { + for(i = 0; i != node->index; ++i) ++lengths[leaves[i].index]; + } + } + + lodepng_free(lists.memory); + lodepng_free(lists.freelist); + lodepng_free(lists.chains0); + lodepng_free(lists.chains1); + } + + lodepng_free(leaves); + return error; +} + +/*Create the Huffman tree given the symbol frequencies*/ +static unsigned HuffmanTree_makeFromFrequencies(HuffmanTree* tree, const unsigned* frequencies, + size_t mincodes, size_t numcodes, unsigned maxbitlen) +{ + unsigned error = 0; + while(!frequencies[numcodes - 1] && numcodes > mincodes) --numcodes; /*trim zeroes*/ + tree->maxbitlen = maxbitlen; + tree->numcodes = (unsigned)numcodes; /*number of symbols*/ + tree->lengths = (unsigned*)lodepng_realloc(tree->lengths, numcodes * sizeof(unsigned)); + if(!tree->lengths) return 83; /*alloc fail*/ + /*initialize all lengths to 0*/ + memset(tree->lengths, 0, numcodes * sizeof(unsigned)); + + error = lodepng_huffman_code_lengths(tree->lengths, frequencies, numcodes, maxbitlen); + if(!error) error = HuffmanTree_makeFromLengths2(tree); + return error; +} + +static unsigned HuffmanTree_getCode(const HuffmanTree* tree, unsigned index) +{ + return tree->tree1d[index]; +} + +static unsigned HuffmanTree_getLength(const HuffmanTree* tree, unsigned index) +{ + return tree->lengths[index]; +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/*get the literal and length code tree of a deflated block with fixed tree, as per the deflate specification*/ +static unsigned generateFixedLitLenTree(HuffmanTree* tree) +{ + unsigned i, error = 0; + unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned)); + if(!bitlen) return 83; /*alloc fail*/ + + /*288 possible codes: 0-255=literals, 256=endcode, 257-285=lengthcodes, 286-287=unused*/ + for(i = 0; i <= 143; ++i) bitlen[i] = 8; + for(i = 144; i <= 255; ++i) bitlen[i] = 9; + for(i = 256; i <= 279; ++i) bitlen[i] = 7; + for(i = 280; i <= 287; ++i) bitlen[i] = 8; + + error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DEFLATE_CODE_SYMBOLS, 15); + + lodepng_free(bitlen); + return error; +} + +/*get the distance code tree of a deflated block with fixed tree, as specified in the deflate specification*/ +static unsigned generateFixedDistanceTree(HuffmanTree* tree) +{ + unsigned i, error = 0; + unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned)); + if(!bitlen) return 83; /*alloc fail*/ + + /*there are 32 distance codes, but 30-31 are unused*/ + for(i = 0; i != NUM_DISTANCE_SYMBOLS; ++i) bitlen[i] = 5; + error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DISTANCE_SYMBOLS, 15); + + lodepng_free(bitlen); + return error; +} + +#ifdef LODEPNG_COMPILE_DECODER + +/* +returns the code, or (unsigned)(-1) if error happened +inbitlength is the length of the complete buffer, in bits (so its byte length times 8) +*/ +static unsigned huffmanDecodeSymbol(const unsigned char* in, size_t* bp, + const HuffmanTree* codetree, size_t inbitlength) +{ + unsigned treepos = 0, ct; + for(;;) + { + if(*bp >= inbitlength) return (unsigned)(-1); /*error: end of input memory reached without endcode*/ + /* + decode the symbol from the tree. The "readBitFromStream" code is inlined in + the expression below because this is the biggest bottleneck while decoding + */ + ct = codetree->tree2d[(treepos << 1) + READBIT(*bp, in)]; + ++(*bp); + if(ct < codetree->numcodes) return ct; /*the symbol is decoded, return it*/ + else treepos = ct - codetree->numcodes; /*symbol not yet decoded, instead move tree position*/ + + if(treepos >= codetree->numcodes) return (unsigned)(-1); /*error: it appeared outside the codetree*/ + } +} +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_DECODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Inflator (Decompressor) / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*get the tree of a deflated block with fixed tree, as specified in the deflate specification*/ +static void getTreeInflateFixed(HuffmanTree* tree_ll, HuffmanTree* tree_d) +{ + /*TODO: check for out of memory errors*/ + generateFixedLitLenTree(tree_ll); + generateFixedDistanceTree(tree_d); +} + +/*get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree*/ +static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d, + const unsigned char* in, size_t* bp, size_t inlength) +{ + /*make sure that length values that aren't filled in will be 0, or a wrong tree will be generated*/ + unsigned error = 0; + unsigned n, HLIT, HDIST, HCLEN, i; + size_t inbitlength = inlength * 8; + + /*see comments in deflateDynamic for explanation of the context and these variables, it is analogous*/ + unsigned* bitlen_ll = 0; /*lit,len code lengths*/ + unsigned* bitlen_d = 0; /*dist code lengths*/ + /*code length code lengths ("clcl"), the bit lengths of the huffman tree used to compress bitlen_ll and bitlen_d*/ + unsigned* bitlen_cl = 0; + HuffmanTree tree_cl; /*the code tree for code length codes (the huffman tree for compressed huffman trees)*/ + + if((*bp) + 14 > (inlength << 3)) return 49; /*error: the bit pointer is or will go past the memory*/ + + /*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already*/ + HLIT = readBitsFromStream(bp, in, 5) + 257; + /*number of distance codes. Unlike the spec, the value 1 is added to it here already*/ + HDIST = readBitsFromStream(bp, in, 5) + 1; + /*number of code length codes. Unlike the spec, the value 4 is added to it here already*/ + HCLEN = readBitsFromStream(bp, in, 4) + 4; + + if((*bp) + HCLEN * 3 > (inlength << 3)) return 50; /*error: the bit pointer is or will go past the memory*/ + + HuffmanTree_init(&tree_cl); + + while(!error) + { + /*read the code length codes out of 3 * (amount of code length codes) bits*/ + + bitlen_cl = (unsigned*)lodepng_malloc(NUM_CODE_LENGTH_CODES * sizeof(unsigned)); + if(!bitlen_cl) ERROR_BREAK(83 /*alloc fail*/); + + for(i = 0; i != NUM_CODE_LENGTH_CODES; ++i) + { + if(i < HCLEN) bitlen_cl[CLCL_ORDER[i]] = readBitsFromStream(bp, in, 3); + else bitlen_cl[CLCL_ORDER[i]] = 0; /*if not, it must stay 0*/ + } + + error = HuffmanTree_makeFromLengths(&tree_cl, bitlen_cl, NUM_CODE_LENGTH_CODES, 7); + if(error) break; + + /*now we can use this tree to read the lengths for the tree that this function will return*/ + bitlen_ll = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned)); + bitlen_d = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned)); + if(!bitlen_ll || !bitlen_d) ERROR_BREAK(83 /*alloc fail*/); + for(i = 0; i != NUM_DEFLATE_CODE_SYMBOLS; ++i) bitlen_ll[i] = 0; + for(i = 0; i != NUM_DISTANCE_SYMBOLS; ++i) bitlen_d[i] = 0; + + /*i is the current symbol we're reading in the part that contains the code lengths of lit/len and dist codes*/ + i = 0; + while(i < HLIT + HDIST) + { + unsigned code = huffmanDecodeSymbol(in, bp, &tree_cl, inbitlength); + if(code <= 15) /*a length code*/ + { + if(i < HLIT) bitlen_ll[i] = code; + else bitlen_d[i - HLIT] = code; + ++i; + } + else if(code == 16) /*repeat previous*/ + { + unsigned replength = 3; /*read in the 2 bits that indicate repeat length (3-6)*/ + unsigned value; /*set value to the previous code*/ + + if(i == 0) ERROR_BREAK(54); /*can't repeat previous if i is 0*/ + + if((*bp + 2) > inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ + replength += readBitsFromStream(bp, in, 2); + + if(i < HLIT + 1) value = bitlen_ll[i - 1]; + else value = bitlen_d[i - HLIT - 1]; + /*repeat this value in the next lengths*/ + for(n = 0; n < replength; ++n) + { + if(i >= HLIT + HDIST) ERROR_BREAK(13); /*error: i is larger than the amount of codes*/ + if(i < HLIT) bitlen_ll[i] = value; + else bitlen_d[i - HLIT] = value; + ++i; + } + } + else if(code == 17) /*repeat "0" 3-10 times*/ + { + unsigned replength = 3; /*read in the bits that indicate repeat length*/ + if((*bp + 3) > inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ + replength += readBitsFromStream(bp, in, 3); + + /*repeat this value in the next lengths*/ + for(n = 0; n < replength; ++n) + { + if(i >= HLIT + HDIST) ERROR_BREAK(14); /*error: i is larger than the amount of codes*/ + + if(i < HLIT) bitlen_ll[i] = 0; + else bitlen_d[i - HLIT] = 0; + ++i; + } + } + else if(code == 18) /*repeat "0" 11-138 times*/ + { + unsigned replength = 11; /*read in the bits that indicate repeat length*/ + if((*bp + 7) > inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ + replength += readBitsFromStream(bp, in, 7); + + /*repeat this value in the next lengths*/ + for(n = 0; n < replength; ++n) + { + if(i >= HLIT + HDIST) ERROR_BREAK(15); /*error: i is larger than the amount of codes*/ + + if(i < HLIT) bitlen_ll[i] = 0; + else bitlen_d[i - HLIT] = 0; + ++i; + } + } + else /*if(code == (unsigned)(-1))*/ /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ + { + if(code == (unsigned)(-1)) + { + /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol + (10=no endcode, 11=wrong jump outside of tree)*/ + error = (*bp) > inbitlength ? 10 : 11; + } + else error = 16; /*unexisting code, this can never happen*/ + break; + } + } + if(error) break; + + if(bitlen_ll[256] == 0) ERROR_BREAK(64); /*the length of the end code 256 must be larger than 0*/ + + /*now we've finally got HLIT and HDIST, so generate the code trees, and the function is done*/ + error = HuffmanTree_makeFromLengths(tree_ll, bitlen_ll, NUM_DEFLATE_CODE_SYMBOLS, 15); + if(error) break; + error = HuffmanTree_makeFromLengths(tree_d, bitlen_d, NUM_DISTANCE_SYMBOLS, 15); + + break; /*end of error-while*/ + } + + lodepng_free(bitlen_cl); + lodepng_free(bitlen_ll); + lodepng_free(bitlen_d); + HuffmanTree_cleanup(&tree_cl); + + return error; +} + +/*inflate a block with dynamic of fixed Huffman tree*/ +static unsigned inflateHuffmanBlock(ucvector* out, const unsigned char* in, size_t* bp, + size_t* pos, size_t inlength, unsigned btype) +{ + unsigned error = 0; + HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/ + HuffmanTree tree_d; /*the huffman tree for distance codes*/ + size_t inbitlength = inlength * 8; + + HuffmanTree_init(&tree_ll); + HuffmanTree_init(&tree_d); + + if(btype == 1) getTreeInflateFixed(&tree_ll, &tree_d); + else if(btype == 2) error = getTreeInflateDynamic(&tree_ll, &tree_d, in, bp, inlength); + + while(!error) /*decode all symbols until end reached, breaks at end code*/ + { + /*code_ll is literal, length or end code*/ + unsigned code_ll = huffmanDecodeSymbol(in, bp, &tree_ll, inbitlength); + if(code_ll <= 255) /*literal symbol*/ + { + /*ucvector_push_back would do the same, but for some reason the two lines below run 10% faster*/ + if(!ucvector_resize(out, (*pos) + 1)) ERROR_BREAK(83 /*alloc fail*/); + out->data[*pos] = (unsigned char)code_ll; + ++(*pos); + } + else if(code_ll >= FIRST_LENGTH_CODE_INDEX && code_ll <= LAST_LENGTH_CODE_INDEX) /*length code*/ + { + unsigned code_d, distance; + unsigned numextrabits_l, numextrabits_d; /*extra bits for length and distance*/ + size_t start, forward, backward, length; + + /*part 1: get length base*/ + length = LENGTHBASE[code_ll - FIRST_LENGTH_CODE_INDEX]; + + /*part 2: get extra bits and add the value of that to length*/ + numextrabits_l = LENGTHEXTRA[code_ll - FIRST_LENGTH_CODE_INDEX]; + if((*bp + numextrabits_l) > inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/ + length += readBitsFromStream(bp, in, numextrabits_l); + + /*part 3: get distance code*/ + code_d = huffmanDecodeSymbol(in, bp, &tree_d, inbitlength); + if(code_d > 29) + { + if(code_ll == (unsigned)(-1)) /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ + { + /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol + (10=no endcode, 11=wrong jump outside of tree)*/ + error = (*bp) > inlength * 8 ? 10 : 11; + } + else error = 18; /*error: invalid distance code (30-31 are never used)*/ + break; + } + distance = DISTANCEBASE[code_d]; + + /*part 4: get extra bits from distance*/ + numextrabits_d = DISTANCEEXTRA[code_d]; + if((*bp + numextrabits_d) > inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/ + distance += readBitsFromStream(bp, in, numextrabits_d); + + /*part 5: fill in all the out[n] values based on the length and dist*/ + start = (*pos); + if(distance > start) ERROR_BREAK(52); /*too long backward distance*/ + backward = start - distance; + + if(!ucvector_resize(out, (*pos) + length)) ERROR_BREAK(83 /*alloc fail*/); + if (distance < length) { + for(forward = 0; forward < length; ++forward) + { + out->data[(*pos)++] = out->data[backward++]; + } + } else { + memcpy(out->data + *pos, out->data + backward, length); + *pos += length; + } + } + else if(code_ll == 256) + { + break; /*end code, break the loop*/ + } + else /*if(code == (unsigned)(-1))*/ /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ + { + /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol + (10=no endcode, 11=wrong jump outside of tree)*/ + error = ((*bp) > inlength * 8) ? 10 : 11; + break; + } + } + + HuffmanTree_cleanup(&tree_ll); + HuffmanTree_cleanup(&tree_d); + + return error; +} + +static unsigned inflateNoCompression(ucvector* out, const unsigned char* in, size_t* bp, size_t* pos, size_t inlength) +{ + size_t p; + unsigned LEN, NLEN, n, error = 0; + + /*go to first boundary of byte*/ + while(((*bp) & 0x7) != 0) ++(*bp); + p = (*bp) / 8; /*byte position*/ + + /*read LEN (2 bytes) and NLEN (2 bytes)*/ + if(p + 4 >= inlength) return 52; /*error, bit pointer will jump past memory*/ + LEN = in[p] + 256u * in[p + 1]; p += 2; + NLEN = in[p] + 256u * in[p + 1]; p += 2; + + /*check if 16-bit NLEN is really the one's complement of LEN*/ + if(LEN + NLEN != 65535) return 21; /*error: NLEN is not one's complement of LEN*/ + + if(!ucvector_resize(out, (*pos) + LEN)) return 83; /*alloc fail*/ + + /*read the literal data: LEN bytes are now stored in the out buffer*/ + if(p + LEN > inlength) return 23; /*error: reading outside of in buffer*/ + for(n = 0; n < LEN; ++n) out->data[(*pos)++] = in[p++]; + + (*bp) = p * 8; + + return error; +} + +static unsigned lodepng_inflatev(ucvector* out, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings) +{ + /*bit pointer in the "in" data, current byte is bp >> 3, current bit is bp & 0x7 (from lsb to msb of the byte)*/ + size_t bp = 0; + unsigned BFINAL = 0; + size_t pos = 0; /*byte position in the out buffer*/ + unsigned error = 0; + + (void)settings; + + while(!BFINAL) + { + unsigned BTYPE; + if(bp + 2 >= insize * 8) return 52; /*error, bit pointer will jump past memory*/ + BFINAL = readBitFromStream(&bp, in); + BTYPE = 1u * readBitFromStream(&bp, in); + BTYPE += 2u * readBitFromStream(&bp, in); + + if(BTYPE == 3) return 20; /*error: invalid BTYPE*/ + else if(BTYPE == 0) error = inflateNoCompression(out, in, &bp, &pos, insize); /*no compression*/ + else error = inflateHuffmanBlock(out, in, &bp, &pos, insize, BTYPE); /*compression, BTYPE 01 or 10*/ + + if(error) return error; + } + + return error; +} + +unsigned lodepng_inflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings) +{ + unsigned error; + ucvector v; + ucvector_init_buffer(&v, *out, *outsize); + error = lodepng_inflatev(&v, in, insize, settings); + *out = v.data; + *outsize = v.size; + return error; +} + +static unsigned inflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings) +{ + if(settings->custom_inflate) + { + return settings->custom_inflate(out, outsize, in, insize, settings); + } + else + { + return lodepng_inflate(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Deflator (Compressor) / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +static const size_t MAX_SUPPORTED_DEFLATE_LENGTH = 258; + +/*bitlen is the size in bits of the code*/ +static void addHuffmanSymbol(size_t* bp, ucvector* compressed, unsigned code, unsigned bitlen) +{ + addBitsToStreamReversed(bp, compressed, code, bitlen); +} + +/*search the index in the array, that has the largest value smaller than or equal to the given value, +given array must be sorted (if no value is smaller, it returns the size of the given array)*/ +static size_t searchCodeIndex(const unsigned* array, size_t array_size, size_t value) +{ + /*binary search (only small gain over linear). TODO: use CPU log2 instruction for getting symbols instead*/ + size_t left = 1; + size_t right = array_size - 1; + + while(left <= right) { + size_t mid = (left + right) >> 1; + if (array[mid] >= value) right = mid - 1; + else left = mid + 1; + } + if(left >= array_size || array[left] > value) left--; + return left; +} + +static void addLengthDistance(uivector* values, size_t length, size_t distance) +{ + /*values in encoded vector are those used by deflate: + 0-255: literal bytes + 256: end + 257-285: length/distance pair (length code, followed by extra length bits, distance code, extra distance bits) + 286-287: invalid*/ + + unsigned length_code = (unsigned)searchCodeIndex(LENGTHBASE, 29, length); + unsigned extra_length = (unsigned)(length - LENGTHBASE[length_code]); + unsigned dist_code = (unsigned)searchCodeIndex(DISTANCEBASE, 30, distance); + unsigned extra_distance = (unsigned)(distance - DISTANCEBASE[dist_code]); + + uivector_push_back(values, length_code + FIRST_LENGTH_CODE_INDEX); + uivector_push_back(values, extra_length); + uivector_push_back(values, dist_code); + uivector_push_back(values, extra_distance); +} + +/*3 bytes of data get encoded into two bytes. The hash cannot use more than 3 +bytes as input because 3 is the minimum match length for deflate*/ +static const unsigned HASH_NUM_VALUES = 65536; +static const unsigned HASH_BIT_MASK = 65535; /*HASH_NUM_VALUES - 1, but C90 does not like that as initializer*/ + +typedef struct Hash +{ + int* head; /*hash value to head circular pos - can be outdated if went around window*/ + /*circular pos to prev circular pos*/ + unsigned short* chain; + int* val; /*circular pos to hash value*/ + + /*TODO: do this not only for zeros but for any repeated byte. However for PNG + it's always going to be the zeros that dominate, so not important for PNG*/ + int* headz; /*similar to head, but for chainz*/ + unsigned short* chainz; /*those with same amount of zeros*/ + unsigned short* zeros; /*length of zeros streak, used as a second hash chain*/ +} Hash; + +static unsigned hash_init(Hash* hash, unsigned windowsize) +{ + unsigned i; + hash->head = (int*)lodepng_malloc(sizeof(int) * HASH_NUM_VALUES); + hash->val = (int*)lodepng_malloc(sizeof(int) * windowsize); + hash->chain = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); + + hash->zeros = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); + hash->headz = (int*)lodepng_malloc(sizeof(int) * (MAX_SUPPORTED_DEFLATE_LENGTH + 1)); + hash->chainz = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); + + if(!hash->head || !hash->chain || !hash->val || !hash->headz|| !hash->chainz || !hash->zeros) + { + return 83; /*alloc fail*/ + } + + /*initialize hash table*/ + for(i = 0; i != HASH_NUM_VALUES; ++i) hash->head[i] = -1; + for(i = 0; i != windowsize; ++i) hash->val[i] = -1; + for(i = 0; i != windowsize; ++i) hash->chain[i] = i; /*same value as index indicates uninitialized*/ + + for(i = 0; i <= MAX_SUPPORTED_DEFLATE_LENGTH; ++i) hash->headz[i] = -1; + for(i = 0; i != windowsize; ++i) hash->chainz[i] = i; /*same value as index indicates uninitialized*/ + + return 0; +} + +static void hash_cleanup(Hash* hash) +{ + lodepng_free(hash->head); + lodepng_free(hash->val); + lodepng_free(hash->chain); + + lodepng_free(hash->zeros); + lodepng_free(hash->headz); + lodepng_free(hash->chainz); +} + + + +static unsigned getHash(const unsigned char* data, size_t size, size_t pos) +{ + unsigned result = 0; + if(pos + 2 < size) + { + /*A simple shift and xor hash is used. Since the data of PNGs is dominated + by zeroes due to the filters, a better hash does not have a significant + effect on speed in traversing the chain, and causes more time spend on + calculating the hash.*/ + result ^= (unsigned)(data[pos + 0] << 0u); + result ^= (unsigned)(data[pos + 1] << 4u); + result ^= (unsigned)(data[pos + 2] << 8u); + } else { + size_t amount, i; + if(pos >= size) return 0; + amount = size - pos; + for(i = 0; i != amount; ++i) result ^= (unsigned)(data[pos + i] << (i * 8u)); + } + return result & HASH_BIT_MASK; +} + +static unsigned countZeros(const unsigned char* data, size_t size, size_t pos) +{ + const unsigned char* start = data + pos; + const unsigned char* end = start + MAX_SUPPORTED_DEFLATE_LENGTH; + if(end > data + size) end = data + size; + data = start; + while(data != end && *data == 0) ++data; + /*subtracting two addresses returned as 32-bit number (max value is MAX_SUPPORTED_DEFLATE_LENGTH)*/ + return (unsigned)(data - start); +} + +/*wpos = pos & (windowsize - 1)*/ +static void updateHashChain(Hash* hash, size_t wpos, unsigned hashval, unsigned short numzeros) +{ + hash->val[wpos] = (int)hashval; + if(hash->head[hashval] != -1) hash->chain[wpos] = hash->head[hashval]; + hash->head[hashval] = wpos; + + hash->zeros[wpos] = numzeros; + if(hash->headz[numzeros] != -1) hash->chainz[wpos] = hash->headz[numzeros]; + hash->headz[numzeros] = wpos; +} + +/* +LZ77-encode the data. Return value is error code. The input are raw bytes, the output +is in the form of unsigned integers with codes representing for example literal bytes, or +length/distance pairs. +It uses a hash table technique to let it encode faster. When doing LZ77 encoding, a +sliding window (of windowsize) is used, and all past bytes in that window can be used as +the "dictionary". A brute force search through all possible distances would be slow, and +this hash technique is one out of several ways to speed this up. +*/ +static unsigned encodeLZ77(uivector* out, Hash* hash, + const unsigned char* in, size_t inpos, size_t insize, unsigned windowsize, + unsigned minmatch, unsigned nicematch, unsigned lazymatching) +{ + size_t pos; + unsigned i, error = 0; + /*for large window lengths, assume the user wants no compression loss. Otherwise, max hash chain length speedup.*/ + unsigned maxchainlength = windowsize >= 8192 ? windowsize : windowsize / 8; + unsigned maxlazymatch = windowsize >= 8192 ? MAX_SUPPORTED_DEFLATE_LENGTH : 64; + + unsigned usezeros = 1; /*not sure if setting it to false for windowsize < 8192 is better or worse*/ + unsigned numzeros = 0; + + unsigned offset; /*the offset represents the distance in LZ77 terminology*/ + unsigned length; + unsigned lazy = 0; + unsigned lazylength = 0, lazyoffset = 0; + unsigned hashval; + unsigned current_offset, current_length; + unsigned prev_offset; + const unsigned char *lastptr, *foreptr, *backptr; + unsigned hashpos; + + if(windowsize == 0 || windowsize > 32768) return 60; /*error: windowsize smaller/larger than allowed*/ + if((windowsize & (windowsize - 1)) != 0) return 90; /*error: must be power of two*/ + + if(nicematch > MAX_SUPPORTED_DEFLATE_LENGTH) nicematch = MAX_SUPPORTED_DEFLATE_LENGTH; + + for(pos = inpos; pos < insize; ++pos) + { + size_t wpos = pos & (windowsize - 1); /*position for in 'circular' hash buffers*/ + unsigned chainlength = 0; + + hashval = getHash(in, insize, pos); + + if(usezeros && hashval == 0) + { + if(numzeros == 0) numzeros = countZeros(in, insize, pos); + else if(pos + numzeros > insize || in[pos + numzeros - 1] != 0) --numzeros; + } + else + { + numzeros = 0; + } + + updateHashChain(hash, wpos, hashval, numzeros); + + /*the length and offset found for the current position*/ + length = 0; + offset = 0; + + hashpos = hash->chain[wpos]; + + lastptr = &in[insize < pos + MAX_SUPPORTED_DEFLATE_LENGTH ? insize : pos + MAX_SUPPORTED_DEFLATE_LENGTH]; + + /*search for the longest string*/ + prev_offset = 0; + for(;;) + { + if(chainlength++ >= maxchainlength) break; + current_offset = hashpos <= wpos ? wpos - hashpos : wpos - hashpos + windowsize; + + if(current_offset < prev_offset) break; /*stop when went completely around the circular buffer*/ + prev_offset = current_offset; + if(current_offset > 0) + { + /*test the next characters*/ + foreptr = &in[pos]; + backptr = &in[pos - current_offset]; + + /*common case in PNGs is lots of zeros. Quickly skip over them as a speedup*/ + if(numzeros >= 3) + { + unsigned skip = hash->zeros[hashpos]; + if(skip > numzeros) skip = numzeros; + backptr += skip; + foreptr += skip; + } + + while(foreptr != lastptr && *backptr == *foreptr) /*maximum supported length by deflate is max length*/ + { + ++backptr; + ++foreptr; + } + current_length = (unsigned)(foreptr - &in[pos]); + + if(current_length > length) + { + length = current_length; /*the longest length*/ + offset = current_offset; /*the offset that is related to this longest length*/ + /*jump out once a length of max length is found (speed gain). This also jumps + out if length is MAX_SUPPORTED_DEFLATE_LENGTH*/ + if(current_length >= nicematch) break; + } + } + + if(hashpos == hash->chain[hashpos]) break; + + if(numzeros >= 3 && length > numzeros) + { + hashpos = hash->chainz[hashpos]; + if(hash->zeros[hashpos] != numzeros) break; + } + else + { + hashpos = hash->chain[hashpos]; + /*outdated hash value, happens if particular value was not encountered in whole last window*/ + if(hash->val[hashpos] != (int)hashval) break; + } + } + + if(lazymatching) + { + if(!lazy && length >= 3 && length <= maxlazymatch && length < MAX_SUPPORTED_DEFLATE_LENGTH) + { + lazy = 1; + lazylength = length; + lazyoffset = offset; + continue; /*try the next byte*/ + } + if(lazy) + { + lazy = 0; + if(pos == 0) ERROR_BREAK(81); + if(length > lazylength + 1) + { + /*push the previous character as literal*/ + if(!uivector_push_back(out, in[pos - 1])) ERROR_BREAK(83 /*alloc fail*/); + } + else + { + length = lazylength; + offset = lazyoffset; + hash->head[hashval] = -1; /*the same hashchain update will be done, this ensures no wrong alteration*/ + hash->headz[numzeros] = -1; /*idem*/ + --pos; + } + } + } + if(length >= 3 && offset > windowsize) ERROR_BREAK(86 /*too big (or overflown negative) offset*/); + + /*encode it as length/distance pair or literal value*/ + if(length < 3) /*only lengths of 3 or higher are supported as length/distance pair*/ + { + if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/); + } + else if(length < minmatch || (length == 3 && offset > 4096)) + { + /*compensate for the fact that longer offsets have more extra bits, a + length of only 3 may be not worth it then*/ + if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/); + } + else + { + addLengthDistance(out, length, offset); + for(i = 1; i < length; ++i) + { + ++pos; + wpos = pos & (windowsize - 1); + hashval = getHash(in, insize, pos); + if(usezeros && hashval == 0) + { + if(numzeros == 0) numzeros = countZeros(in, insize, pos); + else if(pos + numzeros > insize || in[pos + numzeros - 1] != 0) --numzeros; + } + else + { + numzeros = 0; + } + updateHashChain(hash, wpos, hashval, numzeros); + } + } + } /*end of the loop through each character of input*/ + + return error; +} + +/* /////////////////////////////////////////////////////////////////////////// */ + +static unsigned deflateNoCompression(ucvector* out, const unsigned char* data, size_t datasize) +{ + /*non compressed deflate block data: 1 bit BFINAL,2 bits BTYPE,(5 bits): it jumps to start of next byte, + 2 bytes LEN, 2 bytes NLEN, LEN bytes literal DATA*/ + + size_t i, j, numdeflateblocks = (datasize + 65534) / 65535; + unsigned datapos = 0; + for(i = 0; i != numdeflateblocks; ++i) + { + unsigned BFINAL, BTYPE, LEN, NLEN; + unsigned char firstbyte; + + BFINAL = (i == numdeflateblocks - 1); + BTYPE = 0; + + firstbyte = (unsigned char)(BFINAL + ((BTYPE & 1) << 1) + ((BTYPE & 2) << 1)); + ucvector_push_back(out, firstbyte); + + LEN = 65535; + if(datasize - datapos < 65535) LEN = (unsigned)datasize - datapos; + NLEN = 65535 - LEN; + + ucvector_push_back(out, (unsigned char)(LEN & 255)); + ucvector_push_back(out, (unsigned char)(LEN >> 8)); + ucvector_push_back(out, (unsigned char)(NLEN & 255)); + ucvector_push_back(out, (unsigned char)(NLEN >> 8)); + + /*Decompressed data*/ + for(j = 0; j < 65535 && datapos < datasize; ++j) + { + ucvector_push_back(out, data[datapos++]); + } + } + + return 0; +} + +/* +write the lz77-encoded data, which has lit, len and dist codes, to compressed stream using huffman trees. +tree_ll: the tree for lit and len codes. +tree_d: the tree for distance codes. +*/ +static void writeLZ77data(size_t* bp, ucvector* out, const uivector* lz77_encoded, + const HuffmanTree* tree_ll, const HuffmanTree* tree_d) +{ + size_t i = 0; + for(i = 0; i != lz77_encoded->size; ++i) + { + unsigned val = lz77_encoded->data[i]; + addHuffmanSymbol(bp, out, HuffmanTree_getCode(tree_ll, val), HuffmanTree_getLength(tree_ll, val)); + if(val > 256) /*for a length code, 3 more things have to be added*/ + { + unsigned length_index = val - FIRST_LENGTH_CODE_INDEX; + unsigned n_length_extra_bits = LENGTHEXTRA[length_index]; + unsigned length_extra_bits = lz77_encoded->data[++i]; + + unsigned distance_code = lz77_encoded->data[++i]; + + unsigned distance_index = distance_code; + unsigned n_distance_extra_bits = DISTANCEEXTRA[distance_index]; + unsigned distance_extra_bits = lz77_encoded->data[++i]; + + addBitsToStream(bp, out, length_extra_bits, n_length_extra_bits); + addHuffmanSymbol(bp, out, HuffmanTree_getCode(tree_d, distance_code), + HuffmanTree_getLength(tree_d, distance_code)); + addBitsToStream(bp, out, distance_extra_bits, n_distance_extra_bits); + } + } +} + +/*Deflate for a block of type "dynamic", that is, with freely, optimally, created huffman trees*/ +static unsigned deflateDynamic(ucvector* out, size_t* bp, Hash* hash, + const unsigned char* data, size_t datapos, size_t dataend, + const LodePNGCompressSettings* settings, unsigned final) +{ + unsigned error = 0; + + /* + A block is compressed as follows: The PNG data is lz77 encoded, resulting in + literal bytes and length/distance pairs. This is then huffman compressed with + two huffman trees. One huffman tree is used for the lit and len values ("ll"), + another huffman tree is used for the dist values ("d"). These two trees are + stored using their code lengths, and to compress even more these code lengths + are also run-length encoded and huffman compressed. This gives a huffman tree + of code lengths "cl". The code lenghts used to describe this third tree are + the code length code lengths ("clcl"). + */ + + /*The lz77 encoded data, represented with integers since there will also be length and distance codes in it*/ + uivector lz77_encoded; + HuffmanTree tree_ll; /*tree for lit,len values*/ + HuffmanTree tree_d; /*tree for distance codes*/ + HuffmanTree tree_cl; /*tree for encoding the code lengths representing tree_ll and tree_d*/ + uivector frequencies_ll; /*frequency of lit,len codes*/ + uivector frequencies_d; /*frequency of dist codes*/ + uivector frequencies_cl; /*frequency of code length codes*/ + uivector bitlen_lld; /*lit,len,dist code lenghts (int bits), literally (without repeat codes).*/ + uivector bitlen_lld_e; /*bitlen_lld encoded with repeat codes (this is a rudemtary run length compression)*/ + /*bitlen_cl is the code length code lengths ("clcl"). The bit lengths of codes to represent tree_cl + (these are written as is in the file, it would be crazy to compress these using yet another huffman + tree that needs to be represented by yet another set of code lengths)*/ + uivector bitlen_cl; + size_t datasize = dataend - datapos; + + /* + Due to the huffman compression of huffman tree representations ("two levels"), there are some anologies: + bitlen_lld is to tree_cl what data is to tree_ll and tree_d. + bitlen_lld_e is to bitlen_lld what lz77_encoded is to data. + bitlen_cl is to bitlen_lld_e what bitlen_lld is to lz77_encoded. + */ + + unsigned BFINAL = final; + size_t numcodes_ll, numcodes_d, i; + unsigned HLIT, HDIST, HCLEN; + + uivector_init(&lz77_encoded); + HuffmanTree_init(&tree_ll); + HuffmanTree_init(&tree_d); + HuffmanTree_init(&tree_cl); + uivector_init(&frequencies_ll); + uivector_init(&frequencies_d); + uivector_init(&frequencies_cl); + uivector_init(&bitlen_lld); + uivector_init(&bitlen_lld_e); + uivector_init(&bitlen_cl); + + /*This while loop never loops due to a break at the end, it is here to + allow breaking out of it to the cleanup phase on error conditions.*/ + while(!error) + { + if(settings->use_lz77) + { + error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize, + settings->minmatch, settings->nicematch, settings->lazymatching); + if(error) break; + } + else + { + if(!uivector_resize(&lz77_encoded, datasize)) ERROR_BREAK(83 /*alloc fail*/); + for(i = datapos; i < dataend; ++i) lz77_encoded.data[i - datapos] = data[i]; /*no LZ77, but still will be Huffman compressed*/ + } + + if(!uivector_resizev(&frequencies_ll, 286, 0)) ERROR_BREAK(83 /*alloc fail*/); + if(!uivector_resizev(&frequencies_d, 30, 0)) ERROR_BREAK(83 /*alloc fail*/); + + /*Count the frequencies of lit, len and dist codes*/ + for(i = 0; i != lz77_encoded.size; ++i) + { + unsigned symbol = lz77_encoded.data[i]; + ++frequencies_ll.data[symbol]; + if(symbol > 256) + { + unsigned dist = lz77_encoded.data[i + 2]; + ++frequencies_d.data[dist]; + i += 3; + } + } + frequencies_ll.data[256] = 1; /*there will be exactly 1 end code, at the end of the block*/ + + /*Make both huffman trees, one for the lit and len codes, one for the dist codes*/ + error = HuffmanTree_makeFromFrequencies(&tree_ll, frequencies_ll.data, 257, frequencies_ll.size, 15); + if(error) break; + /*2, not 1, is chosen for mincodes: some buggy PNG decoders require at least 2 symbols in the dist tree*/ + error = HuffmanTree_makeFromFrequencies(&tree_d, frequencies_d.data, 2, frequencies_d.size, 15); + if(error) break; + + numcodes_ll = tree_ll.numcodes; if(numcodes_ll > 286) numcodes_ll = 286; + numcodes_d = tree_d.numcodes; if(numcodes_d > 30) numcodes_d = 30; + /*store the code lengths of both generated trees in bitlen_lld*/ + for(i = 0; i != numcodes_ll; ++i) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_ll, (unsigned)i)); + for(i = 0; i != numcodes_d; ++i) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_d, (unsigned)i)); + + /*run-length compress bitlen_ldd into bitlen_lld_e by using repeat codes 16 (copy length 3-6 times), + 17 (3-10 zeroes), 18 (11-138 zeroes)*/ + for(i = 0; i != (unsigned)bitlen_lld.size; ++i) + { + unsigned j = 0; /*amount of repititions*/ + while(i + j + 1 < (unsigned)bitlen_lld.size && bitlen_lld.data[i + j + 1] == bitlen_lld.data[i]) ++j; + + if(bitlen_lld.data[i] == 0 && j >= 2) /*repeat code for zeroes*/ + { + ++j; /*include the first zero*/ + if(j <= 10) /*repeat code 17 supports max 10 zeroes*/ + { + uivector_push_back(&bitlen_lld_e, 17); + uivector_push_back(&bitlen_lld_e, j - 3); + } + else /*repeat code 18 supports max 138 zeroes*/ + { + if(j > 138) j = 138; + uivector_push_back(&bitlen_lld_e, 18); + uivector_push_back(&bitlen_lld_e, j - 11); + } + i += (j - 1); + } + else if(j >= 3) /*repeat code for value other than zero*/ + { + size_t k; + unsigned num = j / 6, rest = j % 6; + uivector_push_back(&bitlen_lld_e, bitlen_lld.data[i]); + for(k = 0; k < num; ++k) + { + uivector_push_back(&bitlen_lld_e, 16); + uivector_push_back(&bitlen_lld_e, 6 - 3); + } + if(rest >= 3) + { + uivector_push_back(&bitlen_lld_e, 16); + uivector_push_back(&bitlen_lld_e, rest - 3); + } + else j -= rest; + i += j; + } + else /*too short to benefit from repeat code*/ + { + uivector_push_back(&bitlen_lld_e, bitlen_lld.data[i]); + } + } + + /*generate tree_cl, the huffmantree of huffmantrees*/ + + if(!uivector_resizev(&frequencies_cl, NUM_CODE_LENGTH_CODES, 0)) ERROR_BREAK(83 /*alloc fail*/); + for(i = 0; i != bitlen_lld_e.size; ++i) + { + ++frequencies_cl.data[bitlen_lld_e.data[i]]; + /*after a repeat code come the bits that specify the number of repetitions, + those don't need to be in the frequencies_cl calculation*/ + if(bitlen_lld_e.data[i] >= 16) ++i; + } + + error = HuffmanTree_makeFromFrequencies(&tree_cl, frequencies_cl.data, + frequencies_cl.size, frequencies_cl.size, 7); + if(error) break; + + if(!uivector_resize(&bitlen_cl, tree_cl.numcodes)) ERROR_BREAK(83 /*alloc fail*/); + for(i = 0; i != tree_cl.numcodes; ++i) + { + /*lenghts of code length tree is in the order as specified by deflate*/ + bitlen_cl.data[i] = HuffmanTree_getLength(&tree_cl, CLCL_ORDER[i]); + } + while(bitlen_cl.data[bitlen_cl.size - 1] == 0 && bitlen_cl.size > 4) + { + /*remove zeros at the end, but minimum size must be 4*/ + if(!uivector_resize(&bitlen_cl, bitlen_cl.size - 1)) ERROR_BREAK(83 /*alloc fail*/); + } + if(error) break; + + /* + Write everything into the output + + After the BFINAL and BTYPE, the dynamic block consists out of the following: + - 5 bits HLIT, 5 bits HDIST, 4 bits HCLEN + - (HCLEN+4)*3 bits code lengths of code length alphabet + - HLIT + 257 code lenghts of lit/length alphabet (encoded using the code length + alphabet, + possible repetition codes 16, 17, 18) + - HDIST + 1 code lengths of distance alphabet (encoded using the code length + alphabet, + possible repetition codes 16, 17, 18) + - compressed data + - 256 (end code) + */ + + /*Write block type*/ + addBitToStream(bp, out, BFINAL); + addBitToStream(bp, out, 0); /*first bit of BTYPE "dynamic"*/ + addBitToStream(bp, out, 1); /*second bit of BTYPE "dynamic"*/ + + /*write the HLIT, HDIST and HCLEN values*/ + HLIT = (unsigned)(numcodes_ll - 257); + HDIST = (unsigned)(numcodes_d - 1); + HCLEN = (unsigned)bitlen_cl.size - 4; + /*trim zeroes for HCLEN. HLIT and HDIST were already trimmed at tree creation*/ + while(!bitlen_cl.data[HCLEN + 4 - 1] && HCLEN > 0) --HCLEN; + addBitsToStream(bp, out, HLIT, 5); + addBitsToStream(bp, out, HDIST, 5); + addBitsToStream(bp, out, HCLEN, 4); + + /*write the code lenghts of the code length alphabet*/ + for(i = 0; i != HCLEN + 4; ++i) addBitsToStream(bp, out, bitlen_cl.data[i], 3); + + /*write the lenghts of the lit/len AND the dist alphabet*/ + for(i = 0; i != bitlen_lld_e.size; ++i) + { + addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_cl, bitlen_lld_e.data[i]), + HuffmanTree_getLength(&tree_cl, bitlen_lld_e.data[i])); + /*extra bits of repeat codes*/ + if(bitlen_lld_e.data[i] == 16) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 2); + else if(bitlen_lld_e.data[i] == 17) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 3); + else if(bitlen_lld_e.data[i] == 18) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 7); + } + + /*write the compressed data symbols*/ + writeLZ77data(bp, out, &lz77_encoded, &tree_ll, &tree_d); + /*error: the length of the end code 256 must be larger than 0*/ + if(HuffmanTree_getLength(&tree_ll, 256) == 0) ERROR_BREAK(64); + + /*write the end code*/ + addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, 256), HuffmanTree_getLength(&tree_ll, 256)); + + break; /*end of error-while*/ + } + + /*cleanup*/ + uivector_cleanup(&lz77_encoded); + HuffmanTree_cleanup(&tree_ll); + HuffmanTree_cleanup(&tree_d); + HuffmanTree_cleanup(&tree_cl); + uivector_cleanup(&frequencies_ll); + uivector_cleanup(&frequencies_d); + uivector_cleanup(&frequencies_cl); + uivector_cleanup(&bitlen_lld_e); + uivector_cleanup(&bitlen_lld); + uivector_cleanup(&bitlen_cl); + + return error; +} + +static unsigned deflateFixed(ucvector* out, size_t* bp, Hash* hash, + const unsigned char* data, + size_t datapos, size_t dataend, + const LodePNGCompressSettings* settings, unsigned final) +{ + HuffmanTree tree_ll; /*tree for literal values and length codes*/ + HuffmanTree tree_d; /*tree for distance codes*/ + + unsigned BFINAL = final; + unsigned error = 0; + size_t i; + + HuffmanTree_init(&tree_ll); + HuffmanTree_init(&tree_d); + + generateFixedLitLenTree(&tree_ll); + generateFixedDistanceTree(&tree_d); + + addBitToStream(bp, out, BFINAL); + addBitToStream(bp, out, 1); /*first bit of BTYPE*/ + addBitToStream(bp, out, 0); /*second bit of BTYPE*/ + + if(settings->use_lz77) /*LZ77 encoded*/ + { + uivector lz77_encoded; + uivector_init(&lz77_encoded); + error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize, + settings->minmatch, settings->nicematch, settings->lazymatching); + if(!error) writeLZ77data(bp, out, &lz77_encoded, &tree_ll, &tree_d); + uivector_cleanup(&lz77_encoded); + } + else /*no LZ77, but still will be Huffman compressed*/ + { + for(i = datapos; i < dataend; ++i) + { + addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, data[i]), HuffmanTree_getLength(&tree_ll, data[i])); + } + } + /*add END code*/ + if(!error) addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, 256), HuffmanTree_getLength(&tree_ll, 256)); + + /*cleanup*/ + HuffmanTree_cleanup(&tree_ll); + HuffmanTree_cleanup(&tree_d); + + return error; +} + +static unsigned lodepng_deflatev(ucvector* out, const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings) +{ + unsigned error = 0; + size_t i, blocksize, numdeflateblocks; + size_t bp = 0; /*the bit pointer*/ + Hash hash; + + if(settings->btype > 2) return 61; + else if(settings->btype == 0) return deflateNoCompression(out, in, insize); + else if(settings->btype == 1) blocksize = insize; + else /*if(settings->btype == 2)*/ + { + /*on PNGs, deflate blocks of 65-262k seem to give most dense encoding*/ + blocksize = insize / 8 + 8; + if(blocksize < 65536) blocksize = 65536; + if(blocksize > 262144) blocksize = 262144; + } + + numdeflateblocks = (insize + blocksize - 1) / blocksize; + if(numdeflateblocks == 0) numdeflateblocks = 1; + + error = hash_init(&hash, settings->windowsize); + if(error) return error; + + for(i = 0; i != numdeflateblocks && !error; ++i) + { + unsigned final = (i == numdeflateblocks - 1); + size_t start = i * blocksize; + size_t end = start + blocksize; + if(end > insize) end = insize; + + if(settings->btype == 1) error = deflateFixed(out, &bp, &hash, in, start, end, settings, final); + else if(settings->btype == 2) error = deflateDynamic(out, &bp, &hash, in, start, end, settings, final); + } + + hash_cleanup(&hash); + + return error; +} + +unsigned lodepng_deflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings) +{ + unsigned error; + ucvector v; + ucvector_init_buffer(&v, *out, *outsize); + error = lodepng_deflatev(&v, in, insize, settings); + *out = v.data; + *outsize = v.size; + return error; +} + +static unsigned deflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings) +{ + if(settings->custom_deflate) + { + return settings->custom_deflate(out, outsize, in, insize, settings); + } + else + { + return lodepng_deflate(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Adler32 */ +/* ////////////////////////////////////////////////////////////////////////// */ + +static unsigned update_adler32(unsigned adler, const unsigned char* data, unsigned len) +{ + unsigned s1 = adler & 0xffff; + unsigned s2 = (adler >> 16) & 0xffff; + + while(len > 0) + { + /*at least 5550 sums can be done before the sums overflow, saving a lot of module divisions*/ + unsigned amount = len > 5550 ? 5550 : len; + len -= amount; + while(amount > 0) + { + s1 += (*data++); + s2 += s1; + --amount; + } + s1 %= 65521; + s2 %= 65521; + } + + return (s2 << 16) | s1; +} + +/*Return the adler32 of the bytes data[0..len-1]*/ +static unsigned adler32(const unsigned char* data, unsigned len) +{ + return update_adler32(1L, data, len); +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Zlib / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_DECODER + +unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGDecompressSettings* settings) +{ + unsigned error = 0; + unsigned CM, CINFO, FDICT; + + if(insize < 2) return 53; /*error, size of zlib data too small*/ + /*read information from zlib header*/ + if((in[0] * 256 + in[1]) % 31 != 0) + { + /*error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way*/ + return 24; + } + + CM = in[0] & 15; + CINFO = (in[0] >> 4) & 15; + /*FCHECK = in[1] & 31;*/ /*FCHECK is already tested above*/ + FDICT = (in[1] >> 5) & 1; + /*FLEVEL = (in[1] >> 6) & 3;*/ /*FLEVEL is not used here*/ + + if(CM != 8 || CINFO > 7) + { + /*error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec*/ + return 25; + } + if(FDICT != 0) + { + /*error: the specification of PNG says about the zlib stream: + "The additional flags shall not specify a preset dictionary."*/ + return 26; + } + + error = inflate(out, outsize, in + 2, insize - 2, settings); + if(error) return error; + + if(!settings->ignore_adler32) + { + unsigned ADLER32 = lodepng_read32bitInt(&in[insize - 4]); + unsigned checksum = adler32(*out, (unsigned)(*outsize)); + if(checksum != ADLER32) return 58; /*error, adler checksum not correct, data must be corrupted*/ + } + + return 0; /*no error*/ +} + +static unsigned zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGDecompressSettings* settings) +{ + if(settings->custom_zlib) + { + return settings->custom_zlib(out, outsize, in, insize, settings); + } + else + { + return lodepng_zlib_decompress(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER + +unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGCompressSettings* settings) +{ + /*initially, *out must be NULL and outsize 0, if you just give some random *out + that's pointing to a non allocated buffer, this'll crash*/ + ucvector outv; + size_t i; + unsigned error; + unsigned char* deflatedata = 0; + size_t deflatesize = 0; + + /*zlib data: 1 byte CMF (CM+CINFO), 1 byte FLG, deflate data, 4 byte ADLER32 checksum of the Decompressed data*/ + unsigned CMF = 120; /*0b01111000: CM 8, CINFO 7. With CINFO 7, any window size up to 32768 can be used.*/ + unsigned FLEVEL = 0; + unsigned FDICT = 0; + unsigned CMFFLG = 256 * CMF + FDICT * 32 + FLEVEL * 64; + unsigned FCHECK = 31 - CMFFLG % 31; + CMFFLG += FCHECK; + + /*ucvector-controlled version of the output buffer, for dynamic array*/ + ucvector_init_buffer(&outv, *out, *outsize); + + ucvector_push_back(&outv, (unsigned char)(CMFFLG >> 8)); + ucvector_push_back(&outv, (unsigned char)(CMFFLG & 255)); + + error = deflate(&deflatedata, &deflatesize, in, insize, settings); + + if(!error) + { + unsigned ADLER32 = adler32(in, (unsigned)insize); + for(i = 0; i != deflatesize; ++i) ucvector_push_back(&outv, deflatedata[i]); + lodepng_free(deflatedata); + lodepng_add32bitInt(&outv, ADLER32); + } + + *out = outv.data; + *outsize = outv.size; + + return error; +} + +/* compress using the default or custom zlib function */ +static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGCompressSettings* settings) +{ + if(settings->custom_zlib) + { + return settings->custom_zlib(out, outsize, in, insize, settings); + } + else + { + return lodepng_zlib_compress(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#else /*no LODEPNG_COMPILE_ZLIB*/ + +#ifdef LODEPNG_COMPILE_DECODER +static unsigned zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGDecompressSettings* settings) +{ + if(!settings->custom_zlib) return 87; /*no custom zlib function provided */ + return settings->custom_zlib(out, outsize, in, insize, settings); +} +#endif /*LODEPNG_COMPILE_DECODER*/ +#ifdef LODEPNG_COMPILE_ENCODER +static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGCompressSettings* settings) +{ + if(!settings->custom_zlib) return 87; /*no custom zlib function provided */ + return settings->custom_zlib(out, outsize, in, insize, settings); +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#endif /*LODEPNG_COMPILE_ZLIB*/ + +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_ENCODER + +/*this is a good tradeoff between speed and compression ratio*/ +#define DEFAULT_WINDOWSIZE 2048 + +void lodepng_compress_settings_init(LodePNGCompressSettings* settings) +{ + /*compress with dynamic huffman tree (not in the mathematical sense, just not the predefined one)*/ + settings->btype = 2; + settings->use_lz77 = 1; + settings->windowsize = DEFAULT_WINDOWSIZE; + settings->minmatch = 3; + settings->nicematch = 128; + settings->lazymatching = 1; + + settings->custom_zlib = 0; + settings->custom_deflate = 0; + settings->custom_context = 0; +} + +const LodePNGCompressSettings lodepng_default_compress_settings = {2, 1, DEFAULT_WINDOWSIZE, 3, 128, 1, 0, 0, 0}; + + +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_DECODER + +void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings) +{ + settings->ignore_adler32 = 0; + + settings->custom_zlib = 0; + settings->custom_inflate = 0; + settings->custom_context = 0; +} + +const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0, 0}; + +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // End of Zlib related code. Begin of PNG related code. // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_PNG + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / CRC32 / */ +/* ////////////////////////////////////////////////////////////////////////// */ + + +#ifndef LODEPNG_NO_COMPILE_CRC +/* CRC polynomial: 0xedb88320 */ +static unsigned lodepng_crc32_table[256] = { + 0u, 1996959894u, 3993919788u, 2567524794u, 124634137u, 1886057615u, 3915621685u, 2657392035u, + 249268274u, 2044508324u, 3772115230u, 2547177864u, 162941995u, 2125561021u, 3887607047u, 2428444049u, + 498536548u, 1789927666u, 4089016648u, 2227061214u, 450548861u, 1843258603u, 4107580753u, 2211677639u, + 325883990u, 1684777152u, 4251122042u, 2321926636u, 335633487u, 1661365465u, 4195302755u, 2366115317u, + 997073096u, 1281953886u, 3579855332u, 2724688242u, 1006888145u, 1258607687u, 3524101629u, 2768942443u, + 901097722u, 1119000684u, 3686517206u, 2898065728u, 853044451u, 1172266101u, 3705015759u, 2882616665u, + 651767980u, 1373503546u, 3369554304u, 3218104598u, 565507253u, 1454621731u, 3485111705u, 3099436303u, + 671266974u, 1594198024u, 3322730930u, 2970347812u, 795835527u, 1483230225u, 3244367275u, 3060149565u, + 1994146192u, 31158534u, 2563907772u, 4023717930u, 1907459465u, 112637215u, 2680153253u, 3904427059u, + 2013776290u, 251722036u, 2517215374u, 3775830040u, 2137656763u, 141376813u, 2439277719u, 3865271297u, + 1802195444u, 476864866u, 2238001368u, 4066508878u, 1812370925u, 453092731u, 2181625025u, 4111451223u, + 1706088902u, 314042704u, 2344532202u, 4240017532u, 1658658271u, 366619977u, 2362670323u, 4224994405u, + 1303535960u, 984961486u, 2747007092u, 3569037538u, 1256170817u, 1037604311u, 2765210733u, 3554079995u, + 1131014506u, 879679996u, 2909243462u, 3663771856u, 1141124467u, 855842277u, 2852801631u, 3708648649u, + 1342533948u, 654459306u, 3188396048u, 3373015174u, 1466479909u, 544179635u, 3110523913u, 3462522015u, + 1591671054u, 702138776u, 2966460450u, 3352799412u, 1504918807u, 783551873u, 3082640443u, 3233442989u, + 3988292384u, 2596254646u, 62317068u, 1957810842u, 3939845945u, 2647816111u, 81470997u, 1943803523u, + 3814918930u, 2489596804u, 225274430u, 2053790376u, 3826175755u, 2466906013u, 167816743u, 2097651377u, + 4027552580u, 2265490386u, 503444072u, 1762050814u, 4150417245u, 2154129355u, 426522225u, 1852507879u, + 4275313526u, 2312317920u, 282753626u, 1742555852u, 4189708143u, 2394877945u, 397917763u, 1622183637u, + 3604390888u, 2714866558u, 953729732u, 1340076626u, 3518719985u, 2797360999u, 1068828381u, 1219638859u, + 3624741850u, 2936675148u, 906185462u, 1090812512u, 3747672003u, 2825379669u, 829329135u, 1181335161u, + 3412177804u, 3160834842u, 628085408u, 1382605366u, 3423369109u, 3138078467u, 570562233u, 1426400815u, + 3317316542u, 2998733608u, 733239954u, 1555261956u, 3268935591u, 3050360625u, 752459403u, 1541320221u, + 2607071920u, 3965973030u, 1969922972u, 40735498u, 2617837225u, 3943577151u, 1913087877u, 83908371u, + 2512341634u, 3803740692u, 2075208622u, 213261112u, 2463272603u, 3855990285u, 2094854071u, 198958881u, + 2262029012u, 4057260610u, 1759359992u, 534414190u, 2176718541u, 4139329115u, 1873836001u, 414664567u, + 2282248934u, 4279200368u, 1711684554u, 285281116u, 2405801727u, 4167216745u, 1634467795u, 376229701u, + 2685067896u, 3608007406u, 1308918612u, 956543938u, 2808555105u, 3495958263u, 1231636301u, 1047427035u, + 2932959818u, 3654703836u, 1088359270u, 936918000u, 2847714899u, 3736837829u, 1202900863u, 817233897u, + 3183342108u, 3401237130u, 1404277552u, 615818150u, 3134207493u, 3453421203u, 1423857449u, 601450431u, + 3009837614u, 3294710456u, 1567103746u, 711928724u, 3020668471u, 3272380065u, 1510334235u, 755167117u +}; + +/*Return the CRC of the bytes buf[0..len-1].*/ +unsigned lodepng_crc32(const unsigned char* data, size_t length) +{ + unsigned r = 0xffffffffu; + size_t i; + for(i = 0; i < length; ++i) + { + r = lodepng_crc32_table[(r ^ data[i]) & 0xff] ^ (r >> 8); + } + return r ^ 0xffffffffu; +} +#else /* !LODEPNG_NO_COMPILE_CRC */ +unsigned lodepng_crc32(const unsigned char* data, size_t length); +#endif /* !LODEPNG_NO_COMPILE_CRC */ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Reading and writing single bits and bytes from/to stream for LodePNG / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +static unsigned char readBitFromReversedStream(size_t* bitpointer, const unsigned char* bitstream) +{ + unsigned char result = (unsigned char)((bitstream[(*bitpointer) >> 3] >> (7 - ((*bitpointer) & 0x7))) & 1); + ++(*bitpointer); + return result; +} + +static unsigned readBitsFromReversedStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits) +{ + unsigned result = 0; + size_t i; + for(i = 0 ; i < nbits; ++i) + { + result <<= 1; + result |= (unsigned)readBitFromReversedStream(bitpointer, bitstream); + } + return result; +} + +#ifdef LODEPNG_COMPILE_DECODER +static void setBitOfReversedStream0(size_t* bitpointer, unsigned char* bitstream, unsigned char bit) +{ + /*the current bit in bitstream must be 0 for this to work*/ + if(bit) + { + /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/ + bitstream[(*bitpointer) >> 3] |= (bit << (7 - ((*bitpointer) & 0x7))); + } + ++(*bitpointer); +} +#endif /*LODEPNG_COMPILE_DECODER*/ + +static void setBitOfReversedStream(size_t* bitpointer, unsigned char* bitstream, unsigned char bit) +{ + /*the current bit in bitstream may be 0 or 1 for this to work*/ + if(bit == 0) bitstream[(*bitpointer) >> 3] &= (unsigned char)(~(1 << (7 - ((*bitpointer) & 0x7)))); + else bitstream[(*bitpointer) >> 3] |= (1 << (7 - ((*bitpointer) & 0x7))); + ++(*bitpointer); +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / PNG chunks / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +unsigned lodepng_chunk_length(const unsigned char* chunk) +{ + return lodepng_read32bitInt(&chunk[0]); +} + +void lodepng_chunk_type(char type[5], const unsigned char* chunk) +{ + unsigned i; + for(i = 0; i != 4; ++i) type[i] = (char)chunk[4 + i]; + type[4] = 0; /*null termination char*/ +} + +unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type) +{ + if(strlen(type) != 4) return 0; + return (chunk[4] == type[0] && chunk[5] == type[1] && chunk[6] == type[2] && chunk[7] == type[3]); +} + +unsigned char lodepng_chunk_ancillary(const unsigned char* chunk) +{ + return((chunk[4] & 32) != 0); +} + +unsigned char lodepng_chunk_private(const unsigned char* chunk) +{ + return((chunk[6] & 32) != 0); +} + +unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk) +{ + return((chunk[7] & 32) != 0); +} + +unsigned char* lodepng_chunk_data(unsigned char* chunk) +{ + return &chunk[8]; +} + +const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk) +{ + return &chunk[8]; +} + +unsigned lodepng_chunk_check_crc(const unsigned char* chunk) +{ + unsigned length = lodepng_chunk_length(chunk); + unsigned CRC = lodepng_read32bitInt(&chunk[length + 8]); + /*the CRC is taken of the data and the 4 chunk type letters, not the length*/ + unsigned checksum = lodepng_crc32(&chunk[4], length + 4); + if(CRC != checksum) return 1; + else return 0; +} + +void lodepng_chunk_generate_crc(unsigned char* chunk) +{ + unsigned length = lodepng_chunk_length(chunk); + unsigned CRC = lodepng_crc32(&chunk[4], length + 4); + lodepng_set32bitInt(chunk + 8 + length, CRC); +} + +unsigned char* lodepng_chunk_next(unsigned char* chunk) +{ + unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12; + return &chunk[total_chunk_length]; +} + +const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk) +{ + unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12; + return &chunk[total_chunk_length]; +} + +unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk) +{ + unsigned i; + unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12; + unsigned char *chunk_start, *new_buffer; + size_t new_length = (*outlength) + total_chunk_length; + if(new_length < total_chunk_length || new_length < (*outlength)) return 77; /*integer overflow happened*/ + + new_buffer = (unsigned char*)lodepng_realloc(*out, new_length); + if(!new_buffer) return 83; /*alloc fail*/ + (*out) = new_buffer; + (*outlength) = new_length; + chunk_start = &(*out)[new_length - total_chunk_length]; + + for(i = 0; i != total_chunk_length; ++i) chunk_start[i] = chunk[i]; + + return 0; +} + +unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, + const char* type, const unsigned char* data) +{ + unsigned i; + unsigned char *chunk, *new_buffer; + size_t new_length = (*outlength) + length + 12; + if(new_length < length + 12 || new_length < (*outlength)) return 77; /*integer overflow happened*/ + new_buffer = (unsigned char*)lodepng_realloc(*out, new_length); + if(!new_buffer) return 83; /*alloc fail*/ + (*out) = new_buffer; + (*outlength) = new_length; + chunk = &(*out)[(*outlength) - length - 12]; + + /*1: length*/ + lodepng_set32bitInt(chunk, (unsigned)length); + + /*2: chunk name (4 letters)*/ + chunk[4] = (unsigned char)type[0]; + chunk[5] = (unsigned char)type[1]; + chunk[6] = (unsigned char)type[2]; + chunk[7] = (unsigned char)type[3]; + + /*3: the data*/ + for(i = 0; i != length; ++i) chunk[8 + i] = data[i]; + + /*4: CRC (of the chunkname characters and the data)*/ + lodepng_chunk_generate_crc(chunk); + + return 0; +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Color types and such / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*return type is a LodePNG error code*/ +static unsigned checkColorValidity(LodePNGColorType colortype, unsigned bd) /*bd = bitdepth*/ +{ + switch(colortype) + { + case 0: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) return 37; break; /*grey*/ + case 2: if(!( bd == 8 || bd == 16)) return 37; break; /*RGB*/ + case 3: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 )) return 37; break; /*palette*/ + case 4: if(!( bd == 8 || bd == 16)) return 37; break; /*grey + alpha*/ + case 6: if(!( bd == 8 || bd == 16)) return 37; break; /*RGBA*/ + default: return 31; + } + return 0; /*allowed color type / bits combination*/ +} + +static unsigned getNumColorChannels(LodePNGColorType colortype) +{ + switch(colortype) + { + case 0: return 1; /*grey*/ + case 2: return 3; /*RGB*/ + case 3: return 1; /*palette*/ + case 4: return 2; /*grey + alpha*/ + case 6: return 4; /*RGBA*/ + } + return 0; /*unexisting color type*/ +} + +static unsigned lodepng_get_bpp_lct(LodePNGColorType colortype, unsigned bitdepth) +{ + /*bits per pixel is amount of channels * bits per channel*/ + return getNumColorChannels(colortype) * bitdepth; +} + +/* ////////////////////////////////////////////////////////////////////////// */ + +void lodepng_color_mode_init(LodePNGColorMode* info) +{ + info->key_defined = 0; + info->key_r = info->key_g = info->key_b = 0; + info->colortype = LCT_RGBA; + info->bitdepth = 8; + info->palette = 0; + info->palettesize = 0; +} + +void lodepng_color_mode_cleanup(LodePNGColorMode* info) +{ + lodepng_palette_clear(info); +} + +unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source) +{ + size_t i; + lodepng_color_mode_cleanup(dest); + *dest = *source; + if(source->palette) + { + dest->palette = (unsigned char*)lodepng_malloc(1024); + if(!dest->palette && source->palettesize) return 83; /*alloc fail*/ + for(i = 0; i != source->palettesize * 4; ++i) dest->palette[i] = source->palette[i]; + } + return 0; +} + +static int lodepng_color_mode_equal(const LodePNGColorMode* a, const LodePNGColorMode* b) +{ + size_t i; + if(a->colortype != b->colortype) return 0; + if(a->bitdepth != b->bitdepth) return 0; + if(a->key_defined != b->key_defined) return 0; + if(a->key_defined) + { + if(a->key_r != b->key_r) return 0; + if(a->key_g != b->key_g) return 0; + if(a->key_b != b->key_b) return 0; + } + /*if one of the palette sizes is 0, then we consider it to be the same as the + other: it means that e.g. the palette was not given by the user and should be + considered the same as the palette inside the PNG.*/ + if(1/*a->palettesize != 0 && b->palettesize != 0*/) { + if(a->palettesize != b->palettesize) return 0; + for(i = 0; i != a->palettesize * 4; ++i) + { + if(a->palette[i] != b->palette[i]) return 0; + } + } + return 1; +} + +void lodepng_palette_clear(LodePNGColorMode* info) +{ + if(info->palette) lodepng_free(info->palette); + info->palette = 0; + info->palettesize = 0; +} + +unsigned lodepng_palette_add(LodePNGColorMode* info, + unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + unsigned char* data; + /*the same resize technique as C++ std::vectors is used, and here it's made so that for a palette with + the max of 256 colors, it'll have the exact alloc size*/ + if(!info->palette) /*allocate palette if empty*/ + { + /*room for 256 colors with 4 bytes each*/ + data = (unsigned char*)lodepng_realloc(info->palette, 1024); + if(!data) return 83; /*alloc fail*/ + else info->palette = data; + } + info->palette[4 * info->palettesize + 0] = r; + info->palette[4 * info->palettesize + 1] = g; + info->palette[4 * info->palettesize + 2] = b; + info->palette[4 * info->palettesize + 3] = a; + ++info->palettesize; + return 0; +} + +unsigned lodepng_get_bpp(const LodePNGColorMode* info) +{ + /*calculate bits per pixel out of colortype and bitdepth*/ + return lodepng_get_bpp_lct(info->colortype, info->bitdepth); +} + +unsigned lodepng_get_channels(const LodePNGColorMode* info) +{ + return getNumColorChannels(info->colortype); +} + +unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info) +{ + return info->colortype == LCT_GREY || info->colortype == LCT_GREY_ALPHA; +} + +unsigned lodepng_is_alpha_type(const LodePNGColorMode* info) +{ + return (info->colortype & 4) != 0; /*4 or 6*/ +} + +unsigned lodepng_is_palette_type(const LodePNGColorMode* info) +{ + return info->colortype == LCT_PALETTE; +} + +unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info) +{ + size_t i; + for(i = 0; i != info->palettesize; ++i) + { + if(info->palette[i * 4 + 3] < 255) return 1; + } + return 0; +} + +unsigned lodepng_can_have_alpha(const LodePNGColorMode* info) +{ + return info->key_defined + || lodepng_is_alpha_type(info) + || lodepng_has_palette_alpha(info); +} + +size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color) +{ + /*will not overflow for any color type if roughly w * h < 268435455*/ + size_t bpp = lodepng_get_bpp(color); + size_t n = w * h; + return ((n / 8) * bpp) + ((n & 7) * bpp + 7) / 8; +} + +size_t lodepng_get_raw_size_lct(unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) +{ + /*will not overflow for any color type if roughly w * h < 268435455*/ + size_t bpp = lodepng_get_bpp_lct(colortype, bitdepth); + size_t n = w * h; + return ((n / 8) * bpp) + ((n & 7) * bpp + 7) / 8; +} + + +#ifdef LODEPNG_COMPILE_PNG +#ifdef LODEPNG_COMPILE_DECODER +/*in an idat chunk, each scanline is a multiple of 8 bits, unlike the lodepng output buffer*/ +static size_t lodepng_get_raw_size_idat(unsigned w, unsigned h, const LodePNGColorMode* color) +{ + /*will not overflow for any color type if roughly w * h < 268435455*/ + size_t bpp = lodepng_get_bpp(color); + size_t line = ((w / 8) * bpp) + ((w & 7) * bpp + 7) / 8; + return h * line; +} +#endif /*LODEPNG_COMPILE_DECODER*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + +static void LodePNGUnknownChunks_init(LodePNGInfo* info) +{ + unsigned i; + for(i = 0; i != 3; ++i) info->unknown_chunks_data[i] = 0; + for(i = 0; i != 3; ++i) info->unknown_chunks_size[i] = 0; +} + +static void LodePNGUnknownChunks_cleanup(LodePNGInfo* info) +{ + unsigned i; + for(i = 0; i != 3; ++i) lodepng_free(info->unknown_chunks_data[i]); +} + +static unsigned LodePNGUnknownChunks_copy(LodePNGInfo* dest, const LodePNGInfo* src) +{ + unsigned i; + + LodePNGUnknownChunks_cleanup(dest); + + for(i = 0; i != 3; ++i) + { + size_t j; + dest->unknown_chunks_size[i] = src->unknown_chunks_size[i]; + dest->unknown_chunks_data[i] = (unsigned char*)lodepng_malloc(src->unknown_chunks_size[i]); + if(!dest->unknown_chunks_data[i] && dest->unknown_chunks_size[i]) return 83; /*alloc fail*/ + for(j = 0; j < src->unknown_chunks_size[i]; ++j) + { + dest->unknown_chunks_data[i][j] = src->unknown_chunks_data[i][j]; + } + } + + return 0; +} + +/******************************************************************************/ + +static void LodePNGText_init(LodePNGInfo* info) +{ + info->text_num = 0; + info->text_keys = NULL; + info->text_strings = NULL; +} + +static void LodePNGText_cleanup(LodePNGInfo* info) +{ + size_t i; + for(i = 0; i != info->text_num; ++i) + { + string_cleanup(&info->text_keys[i]); + string_cleanup(&info->text_strings[i]); + } + lodepng_free(info->text_keys); + lodepng_free(info->text_strings); +} + +static unsigned LodePNGText_copy(LodePNGInfo* dest, const LodePNGInfo* source) +{ + size_t i = 0; + dest->text_keys = 0; + dest->text_strings = 0; + dest->text_num = 0; + for(i = 0; i != source->text_num; ++i) + { + CERROR_TRY_RETURN(lodepng_add_text(dest, source->text_keys[i], source->text_strings[i])); + } + return 0; +} + +void lodepng_clear_text(LodePNGInfo* info) +{ + LodePNGText_cleanup(info); +} + +unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str) +{ + char** new_keys = (char**)(lodepng_realloc(info->text_keys, sizeof(char*) * (info->text_num + 1))); + char** new_strings = (char**)(lodepng_realloc(info->text_strings, sizeof(char*) * (info->text_num + 1))); + if(!new_keys || !new_strings) + { + lodepng_free(new_keys); + lodepng_free(new_strings); + return 83; /*alloc fail*/ + } + + ++info->text_num; + info->text_keys = new_keys; + info->text_strings = new_strings; + + string_init(&info->text_keys[info->text_num - 1]); + string_set(&info->text_keys[info->text_num - 1], key); + + string_init(&info->text_strings[info->text_num - 1]); + string_set(&info->text_strings[info->text_num - 1], str); + + return 0; +} + +/******************************************************************************/ + +static void LodePNGIText_init(LodePNGInfo* info) +{ + info->itext_num = 0; + info->itext_keys = NULL; + info->itext_langtags = NULL; + info->itext_transkeys = NULL; + info->itext_strings = NULL; +} + +static void LodePNGIText_cleanup(LodePNGInfo* info) +{ + size_t i; + for(i = 0; i != info->itext_num; ++i) + { + string_cleanup(&info->itext_keys[i]); + string_cleanup(&info->itext_langtags[i]); + string_cleanup(&info->itext_transkeys[i]); + string_cleanup(&info->itext_strings[i]); + } + lodepng_free(info->itext_keys); + lodepng_free(info->itext_langtags); + lodepng_free(info->itext_transkeys); + lodepng_free(info->itext_strings); +} + +static unsigned LodePNGIText_copy(LodePNGInfo* dest, const LodePNGInfo* source) +{ + size_t i = 0; + dest->itext_keys = 0; + dest->itext_langtags = 0; + dest->itext_transkeys = 0; + dest->itext_strings = 0; + dest->itext_num = 0; + for(i = 0; i != source->itext_num; ++i) + { + CERROR_TRY_RETURN(lodepng_add_itext(dest, source->itext_keys[i], source->itext_langtags[i], + source->itext_transkeys[i], source->itext_strings[i])); + } + return 0; +} + +void lodepng_clear_itext(LodePNGInfo* info) +{ + LodePNGIText_cleanup(info); +} + +unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, + const char* transkey, const char* str) +{ + char** new_keys = (char**)(lodepng_realloc(info->itext_keys, sizeof(char*) * (info->itext_num + 1))); + char** new_langtags = (char**)(lodepng_realloc(info->itext_langtags, sizeof(char*) * (info->itext_num + 1))); + char** new_transkeys = (char**)(lodepng_realloc(info->itext_transkeys, sizeof(char*) * (info->itext_num + 1))); + char** new_strings = (char**)(lodepng_realloc(info->itext_strings, sizeof(char*) * (info->itext_num + 1))); + if(!new_keys || !new_langtags || !new_transkeys || !new_strings) + { + lodepng_free(new_keys); + lodepng_free(new_langtags); + lodepng_free(new_transkeys); + lodepng_free(new_strings); + return 83; /*alloc fail*/ + } + + ++info->itext_num; + info->itext_keys = new_keys; + info->itext_langtags = new_langtags; + info->itext_transkeys = new_transkeys; + info->itext_strings = new_strings; + + string_init(&info->itext_keys[info->itext_num - 1]); + string_set(&info->itext_keys[info->itext_num - 1], key); + + string_init(&info->itext_langtags[info->itext_num - 1]); + string_set(&info->itext_langtags[info->itext_num - 1], langtag); + + string_init(&info->itext_transkeys[info->itext_num - 1]); + string_set(&info->itext_transkeys[info->itext_num - 1], transkey); + + string_init(&info->itext_strings[info->itext_num - 1]); + string_set(&info->itext_strings[info->itext_num - 1], str); + + return 0; +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +void lodepng_info_init(LodePNGInfo* info) +{ + lodepng_color_mode_init(&info->color); + info->interlace_method = 0; + info->compression_method = 0; + info->filter_method = 0; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + info->background_defined = 0; + info->background_r = info->background_g = info->background_b = 0; + + LodePNGText_init(info); + LodePNGIText_init(info); + + info->time_defined = 0; + info->phys_defined = 0; + + LodePNGUnknownChunks_init(info); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} + +void lodepng_info_cleanup(LodePNGInfo* info) +{ + lodepng_color_mode_cleanup(&info->color); +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + LodePNGText_cleanup(info); + LodePNGIText_cleanup(info); + + LodePNGUnknownChunks_cleanup(info); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} + +unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source) +{ + lodepng_info_cleanup(dest); + *dest = *source; + lodepng_color_mode_init(&dest->color); + CERROR_TRY_RETURN(lodepng_color_mode_copy(&dest->color, &source->color)); + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + CERROR_TRY_RETURN(LodePNGText_copy(dest, source)); + CERROR_TRY_RETURN(LodePNGIText_copy(dest, source)); + + LodePNGUnknownChunks_init(dest); + CERROR_TRY_RETURN(LodePNGUnknownChunks_copy(dest, source)); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + return 0; +} + +void lodepng_info_swap(LodePNGInfo* a, LodePNGInfo* b) +{ + LodePNGInfo temp = *a; + *a = *b; + *b = temp; +} + +/* ////////////////////////////////////////////////////////////////////////// */ + +/*index: bitgroup index, bits: bitgroup size(1, 2 or 4), in: bitgroup value, out: octet array to add bits to*/ +static void addColorBits(unsigned char* out, size_t index, unsigned bits, unsigned in) +{ + unsigned m = bits == 1 ? 7 : bits == 2 ? 3 : 1; /*8 / bits - 1*/ + /*p = the partial index in the byte, e.g. with 4 palettebits it is 0 for first half or 1 for second half*/ + unsigned p = index & m; + in &= (1u << bits) - 1u; /*filter out any other bits of the input value*/ + in = in << (bits * (m - p)); + if(p == 0) out[index * bits / 8] = in; + else out[index * bits / 8] |= in; +} + +typedef struct ColorTree ColorTree; + +/* +One node of a color tree +This is the data structure used to count the number of unique colors and to get a palette +index for a color. It's like an octree, but because the alpha channel is used too, each +node has 16 instead of 8 children. +*/ +struct ColorTree +{ + ColorTree* children[16]; /*up to 16 pointers to ColorTree of next level*/ + int index; /*the payload. Only has a meaningful value if this is in the last level*/ +}; + +static void color_tree_init(ColorTree* tree) +{ + int i; + for(i = 0; i != 16; ++i) tree->children[i] = 0; + tree->index = -1; +} + +static void color_tree_cleanup(ColorTree* tree) +{ + int i; + for(i = 0; i != 16; ++i) + { + if(tree->children[i]) + { + color_tree_cleanup(tree->children[i]); + lodepng_free(tree->children[i]); + } + } +} + +/*returns -1 if color not present, its index otherwise*/ +static int color_tree_get(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + int bit = 0; + for(bit = 0; bit < 8; ++bit) + { + int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1); + if(!tree->children[i]) return -1; + else tree = tree->children[i]; + } + return tree ? tree->index : -1; +} + +#ifdef LODEPNG_COMPILE_ENCODER +static int color_tree_has(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + return color_tree_get(tree, r, g, b, a) >= 0; +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/*color is not allowed to already exist. +Index should be >= 0 (it's signed to be compatible with using -1 for "doesn't exist")*/ +static void color_tree_add(ColorTree* tree, + unsigned char r, unsigned char g, unsigned char b, unsigned char a, unsigned index) +{ + int bit; + for(bit = 0; bit < 8; ++bit) + { + int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1); + if(!tree->children[i]) + { + tree->children[i] = (ColorTree*)lodepng_malloc(sizeof(ColorTree)); + color_tree_init(tree->children[i]); + } + tree = tree->children[i]; + } + tree->index = (int)index; +} + +/*put a pixel, given its RGBA color, into image of any color type*/ +static unsigned rgba8ToPixel(unsigned char* out, size_t i, + const LodePNGColorMode* mode, ColorTree* tree /*for palette*/, + unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + if(mode->colortype == LCT_GREY) + { + unsigned char grey = r; /*((unsigned short)r + g + b) / 3*/; + if(mode->bitdepth == 8) out[i] = grey; + else if(mode->bitdepth == 16) out[i * 2 + 0] = out[i * 2 + 1] = grey; + else + { + /*take the most significant bits of grey*/ + grey = (grey >> (8 - mode->bitdepth)) & ((1 << mode->bitdepth) - 1); + addColorBits(out, i, mode->bitdepth, grey); + } + } + else if(mode->colortype == LCT_RGB) + { + if(mode->bitdepth == 8) + { + out[i * 3 + 0] = r; + out[i * 3 + 1] = g; + out[i * 3 + 2] = b; + } + else + { + out[i * 6 + 0] = out[i * 6 + 1] = r; + out[i * 6 + 2] = out[i * 6 + 3] = g; + out[i * 6 + 4] = out[i * 6 + 5] = b; + } + } + else if(mode->colortype == LCT_PALETTE) + { + int index = color_tree_get(tree, r, g, b, a); + if(index < 0) return 82; /*color not in palette*/ + if(mode->bitdepth == 8) out[i] = index; + else addColorBits(out, i, mode->bitdepth, (unsigned)index); + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + unsigned char grey = r; /*((unsigned short)r + g + b) / 3*/; + if(mode->bitdepth == 8) + { + out[i * 2 + 0] = grey; + out[i * 2 + 1] = a; + } + else if(mode->bitdepth == 16) + { + out[i * 4 + 0] = out[i * 4 + 1] = grey; + out[i * 4 + 2] = out[i * 4 + 3] = a; + } + } + else if(mode->colortype == LCT_RGBA) + { + if(mode->bitdepth == 8) + { + out[i * 4 + 0] = r; + out[i * 4 + 1] = g; + out[i * 4 + 2] = b; + out[i * 4 + 3] = a; + } + else + { + out[i * 8 + 0] = out[i * 8 + 1] = r; + out[i * 8 + 2] = out[i * 8 + 3] = g; + out[i * 8 + 4] = out[i * 8 + 5] = b; + out[i * 8 + 6] = out[i * 8 + 7] = a; + } + } + + return 0; /*no error*/ +} + +/*put a pixel, given its RGBA16 color, into image of any color 16-bitdepth type*/ +static void rgba16ToPixel(unsigned char* out, size_t i, + const LodePNGColorMode* mode, + unsigned short r, unsigned short g, unsigned short b, unsigned short a) +{ + if(mode->colortype == LCT_GREY) + { + unsigned short grey = r; /*((unsigned)r + g + b) / 3*/; + out[i * 2 + 0] = (grey >> 8) & 255; + out[i * 2 + 1] = grey & 255; + } + else if(mode->colortype == LCT_RGB) + { + out[i * 6 + 0] = (r >> 8) & 255; + out[i * 6 + 1] = r & 255; + out[i * 6 + 2] = (g >> 8) & 255; + out[i * 6 + 3] = g & 255; + out[i * 6 + 4] = (b >> 8) & 255; + out[i * 6 + 5] = b & 255; + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + unsigned short grey = r; /*((unsigned)r + g + b) / 3*/; + out[i * 4 + 0] = (grey >> 8) & 255; + out[i * 4 + 1] = grey & 255; + out[i * 4 + 2] = (a >> 8) & 255; + out[i * 4 + 3] = a & 255; + } + else if(mode->colortype == LCT_RGBA) + { + out[i * 8 + 0] = (r >> 8) & 255; + out[i * 8 + 1] = r & 255; + out[i * 8 + 2] = (g >> 8) & 255; + out[i * 8 + 3] = g & 255; + out[i * 8 + 4] = (b >> 8) & 255; + out[i * 8 + 5] = b & 255; + out[i * 8 + 6] = (a >> 8) & 255; + out[i * 8 + 7] = a & 255; + } +} + +/*Get RGBA8 color of pixel with index i (y * width + x) from the raw image with given color type.*/ +static void getPixelColorRGBA8(unsigned char* r, unsigned char* g, + unsigned char* b, unsigned char* a, + const unsigned char* in, size_t i, + const LodePNGColorMode* mode) +{ + if(mode->colortype == LCT_GREY) + { + if(mode->bitdepth == 8) + { + *r = *g = *b = in[i]; + if(mode->key_defined && *r == mode->key_r) *a = 0; + else *a = 255; + } + else if(mode->bitdepth == 16) + { + *r = *g = *b = in[i * 2 + 0]; + if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0; + else *a = 255; + } + else + { + unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ + size_t j = i * mode->bitdepth; + unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); + *r = *g = *b = (value * 255) / highest; + if(mode->key_defined && value == mode->key_r) *a = 0; + else *a = 255; + } + } + else if(mode->colortype == LCT_RGB) + { + if(mode->bitdepth == 8) + { + *r = in[i * 3 + 0]; *g = in[i * 3 + 1]; *b = in[i * 3 + 2]; + if(mode->key_defined && *r == mode->key_r && *g == mode->key_g && *b == mode->key_b) *a = 0; + else *a = 255; + } + else + { + *r = in[i * 6 + 0]; + *g = in[i * 6 + 2]; + *b = in[i * 6 + 4]; + if(mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r + && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g + && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0; + else *a = 255; + } + } + else if(mode->colortype == LCT_PALETTE) + { + unsigned index; + if(mode->bitdepth == 8) index = in[i]; + else + { + size_t j = i * mode->bitdepth; + index = readBitsFromReversedStream(&j, in, mode->bitdepth); + } + + if(index >= mode->palettesize) + { + /*This is an error according to the PNG spec, but common PNG decoders make it black instead. + Done here too, slightly faster due to no error handling needed.*/ + *r = *g = *b = 0; + *a = 255; + } + else + { + *r = mode->palette[index * 4 + 0]; + *g = mode->palette[index * 4 + 1]; + *b = mode->palette[index * 4 + 2]; + *a = mode->palette[index * 4 + 3]; + } + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + if(mode->bitdepth == 8) + { + *r = *g = *b = in[i * 2 + 0]; + *a = in[i * 2 + 1]; + } + else + { + *r = *g = *b = in[i * 4 + 0]; + *a = in[i * 4 + 2]; + } + } + else if(mode->colortype == LCT_RGBA) + { + if(mode->bitdepth == 8) + { + *r = in[i * 4 + 0]; + *g = in[i * 4 + 1]; + *b = in[i * 4 + 2]; + *a = in[i * 4 + 3]; + } + else + { + *r = in[i * 8 + 0]; + *g = in[i * 8 + 2]; + *b = in[i * 8 + 4]; + *a = in[i * 8 + 6]; + } + } +} + +/*Similar to getPixelColorRGBA8, but with all the for loops inside of the color +mode test cases, optimized to convert the colors much faster, when converting +to RGBA or RGB with 8 bit per cannel. buffer must be RGBA or RGB output with +enough memory, if has_alpha is true the output is RGBA. mode has the color mode +of the input buffer.*/ +static void getPixelColorsRGBA8(unsigned char* buffer, size_t numpixels, + unsigned has_alpha, const unsigned char* in, + const LodePNGColorMode* mode) +{ + unsigned num_channels = has_alpha ? 4 : 3; + size_t i; + if(mode->colortype == LCT_GREY) + { + if(mode->bitdepth == 8) + { + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + buffer[0] = buffer[1] = buffer[2] = in[i]; + if(has_alpha) buffer[3] = mode->key_defined && in[i] == mode->key_r ? 0 : 255; + } + } + else if(mode->bitdepth == 16) + { + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + buffer[0] = buffer[1] = buffer[2] = in[i * 2]; + if(has_alpha) buffer[3] = mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r ? 0 : 255; + } + } + else + { + unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ + size_t j = 0; + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); + buffer[0] = buffer[1] = buffer[2] = (value * 255) / highest; + if(has_alpha) buffer[3] = mode->key_defined && value == mode->key_r ? 0 : 255; + } + } + } + else if(mode->colortype == LCT_RGB) + { + if(mode->bitdepth == 8) + { + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + buffer[0] = in[i * 3 + 0]; + buffer[1] = in[i * 3 + 1]; + buffer[2] = in[i * 3 + 2]; + if(has_alpha) buffer[3] = mode->key_defined && buffer[0] == mode->key_r + && buffer[1]== mode->key_g && buffer[2] == mode->key_b ? 0 : 255; + } + } + else + { + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + buffer[0] = in[i * 6 + 0]; + buffer[1] = in[i * 6 + 2]; + buffer[2] = in[i * 6 + 4]; + if(has_alpha) buffer[3] = mode->key_defined + && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r + && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g + && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b ? 0 : 255; + } + } + } + else if(mode->colortype == LCT_PALETTE) + { + unsigned index; + size_t j = 0; + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + if(mode->bitdepth == 8) index = in[i]; + else index = readBitsFromReversedStream(&j, in, mode->bitdepth); + + if(index >= mode->palettesize) + { + /*This is an error according to the PNG spec, but most PNG decoders make it black instead. + Done here too, slightly faster due to no error handling needed.*/ + buffer[0] = buffer[1] = buffer[2] = 0; + if(has_alpha) buffer[3] = 255; + } + else + { + buffer[0] = mode->palette[index * 4 + 0]; + buffer[1] = mode->palette[index * 4 + 1]; + buffer[2] = mode->palette[index * 4 + 2]; + if(has_alpha) buffer[3] = mode->palette[index * 4 + 3]; + } + } + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + if(mode->bitdepth == 8) + { + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + buffer[0] = buffer[1] = buffer[2] = in[i * 2 + 0]; + if(has_alpha) buffer[3] = in[i * 2 + 1]; + } + } + else + { + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + buffer[0] = buffer[1] = buffer[2] = in[i * 4 + 0]; + if(has_alpha) buffer[3] = in[i * 4 + 2]; + } + } + } + else if(mode->colortype == LCT_RGBA) + { + if(mode->bitdepth == 8) + { + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + buffer[0] = in[i * 4 + 0]; + buffer[1] = in[i * 4 + 1]; + buffer[2] = in[i * 4 + 2]; + if(has_alpha) buffer[3] = in[i * 4 + 3]; + } + } + else + { + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + buffer[0] = in[i * 8 + 0]; + buffer[1] = in[i * 8 + 2]; + buffer[2] = in[i * 8 + 4]; + if(has_alpha) buffer[3] = in[i * 8 + 6]; + } + } + } +} + +/*Get RGBA16 color of pixel with index i (y * width + x) from the raw image with +given color type, but the given color type must be 16-bit itself.*/ +static void getPixelColorRGBA16(unsigned short* r, unsigned short* g, unsigned short* b, unsigned short* a, + const unsigned char* in, size_t i, const LodePNGColorMode* mode) +{ + if(mode->colortype == LCT_GREY) + { + *r = *g = *b = 256 * in[i * 2 + 0] + in[i * 2 + 1]; + if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0; + else *a = 65535; + } + else if(mode->colortype == LCT_RGB) + { + *r = 256u * in[i * 6 + 0] + in[i * 6 + 1]; + *g = 256u * in[i * 6 + 2] + in[i * 6 + 3]; + *b = 256u * in[i * 6 + 4] + in[i * 6 + 5]; + if(mode->key_defined + && 256u * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r + && 256u * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g + && 256u * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0; + else *a = 65535; + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + *r = *g = *b = 256u * in[i * 4 + 0] + in[i * 4 + 1]; + *a = 256u * in[i * 4 + 2] + in[i * 4 + 3]; + } + else if(mode->colortype == LCT_RGBA) + { + *r = 256u * in[i * 8 + 0] + in[i * 8 + 1]; + *g = 256u * in[i * 8 + 2] + in[i * 8 + 3]; + *b = 256u * in[i * 8 + 4] + in[i * 8 + 5]; + *a = 256u * in[i * 8 + 6] + in[i * 8 + 7]; + } +} + +unsigned lodepng_convert(unsigned char* out, const unsigned char* in, + const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, + unsigned w, unsigned h) +{ + size_t i; + ColorTree tree; + size_t numpixels = w * h; + + if(lodepng_color_mode_equal(mode_out, mode_in)) + { + size_t numbytes = lodepng_get_raw_size(w, h, mode_in); + for(i = 0; i != numbytes; ++i) out[i] = in[i]; + return 0; + } + + if(mode_out->colortype == LCT_PALETTE) + { + size_t palettesize = mode_out->palettesize; + const unsigned char* palette = mode_out->palette; + size_t palsize = 1u << mode_out->bitdepth; + /*if the user specified output palette but did not give the values, assume + they want the values of the input color type (assuming that one is palette). + Note that we never create a new palette ourselves.*/ + if(palettesize == 0) + { + palettesize = mode_in->palettesize; + palette = mode_in->palette; + } + if(palettesize < palsize) palsize = palettesize; + color_tree_init(&tree); + for(i = 0; i != palsize; ++i) + { + const unsigned char* p = &palette[i * 4]; + color_tree_add(&tree, p[0], p[1], p[2], p[3], i); + } + } + + if(mode_in->bitdepth == 16 && mode_out->bitdepth == 16) + { + for(i = 0; i != numpixels; ++i) + { + unsigned short r = 0, g = 0, b = 0, a = 0; + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in); + rgba16ToPixel(out, i, mode_out, r, g, b, a); + } + } + else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGBA) + { + getPixelColorsRGBA8(out, numpixels, 1, in, mode_in); + } + else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGB) + { + getPixelColorsRGBA8(out, numpixels, 0, in, mode_in); + } + else + { + unsigned char r = 0, g = 0, b = 0, a = 0; + for(i = 0; i != numpixels; ++i) + { + getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in); + CERROR_TRY_RETURN(rgba8ToPixel(out, i, mode_out, &tree, r, g, b, a)); + } + } + + if(mode_out->colortype == LCT_PALETTE) + { + color_tree_cleanup(&tree); + } + + return 0; /*no error*/ +} + +#ifdef LODEPNG_COMPILE_ENCODER + +void lodepng_color_profile_init(LodePNGColorProfile* profile) +{ + profile->colored = 0; + profile->key = 0; + profile->alpha = 0; + profile->key_r = profile->key_g = profile->key_b = 0; + profile->numcolors = 0; + profile->bits = 1; +} + +/*function used for debug purposes with C++*/ +/*void printColorProfile(LodePNGColorProfile* p) +{ + std::cout << "colored: " << (int)p->colored << ", "; + std::cout << "key: " << (int)p->key << ", "; + std::cout << "key_r: " << (int)p->key_r << ", "; + std::cout << "key_g: " << (int)p->key_g << ", "; + std::cout << "key_b: " << (int)p->key_b << ", "; + std::cout << "alpha: " << (int)p->alpha << ", "; + std::cout << "numcolors: " << (int)p->numcolors << ", "; + std::cout << "bits: " << (int)p->bits << std::endl; +}*/ + +/*Returns how many bits needed to represent given value (max 8 bit)*/ +static unsigned getValueRequiredBits(unsigned char value) +{ + if(value == 0 || value == 255) return 1; + /*The scaling of 2-bit and 4-bit values uses multiples of 85 and 17*/ + if(value % 17 == 0) return value % 85 == 0 ? 2 : 4; + return 8; +} + +/*profile must already have been inited with mode. +It's ok to set some parameters of profile to done already.*/ +unsigned lodepng_get_color_profile(LodePNGColorProfile* profile, + const unsigned char* in, unsigned w, unsigned h, + const LodePNGColorMode* mode) +{ + unsigned error = 0; + size_t i; + ColorTree tree; + size_t numpixels = w * h; + + unsigned colored_done = lodepng_is_greyscale_type(mode) ? 1 : 0; + unsigned alpha_done = lodepng_can_have_alpha(mode) ? 0 : 1; + unsigned numcolors_done = 0; + unsigned bpp = lodepng_get_bpp(mode); + unsigned bits_done = bpp == 1 ? 1 : 0; + unsigned maxnumcolors = 257; + unsigned sixteen = 0; + if(bpp <= 8) maxnumcolors = bpp == 1 ? 2 : (bpp == 2 ? 4 : (bpp == 4 ? 16 : 256)); + + color_tree_init(&tree); + + /*Check if the 16-bit input is truly 16-bit*/ + if(mode->bitdepth == 16) + { + unsigned short r, g, b, a; + for(i = 0; i != numpixels; ++i) + { + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode); + if((r & 255) != ((r >> 8) & 255) || (g & 255) != ((g >> 8) & 255) || + (b & 255) != ((b >> 8) & 255) || (a & 255) != ((a >> 8) & 255)) /*first and second byte differ*/ + { + sixteen = 1; + break; + } + } + } + + if(sixteen) + { + unsigned short r = 0, g = 0, b = 0, a = 0; + profile->bits = 16; + bits_done = numcolors_done = 1; /*counting colors no longer useful, palette doesn't support 16-bit*/ + + for(i = 0; i != numpixels; ++i) + { + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode); + + if(!colored_done && (r != g || r != b)) + { + profile->colored = 1; + colored_done = 1; + } + + if(!alpha_done) + { + unsigned matchkey = (r == profile->key_r && g == profile->key_g && b == profile->key_b); + if(a != 65535 && (a != 0 || (profile->key && !matchkey))) + { + profile->alpha = 1; + alpha_done = 1; + if(profile->bits < 8) profile->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + } + else if(a == 0 && !profile->alpha && !profile->key) + { + profile->key = 1; + profile->key_r = r; + profile->key_g = g; + profile->key_b = b; + } + else if(a == 65535 && profile->key && matchkey) + { + /* Color key cannot be used if an opaque pixel also has that RGB color. */ + profile->alpha = 1; + alpha_done = 1; + } + } + if(alpha_done && numcolors_done && colored_done && bits_done) break; + } + + if(profile->key && !profile->alpha) + { + for(i = 0; i != numpixels; ++i) + { + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode); + if(a != 0 && r == profile->key_r && g == profile->key_g && b == profile->key_b) + { + /* Color key cannot be used if an opaque pixel also has that RGB color. */ + profile->alpha = 1; + alpha_done = 1; + } + } + } + } + else /* < 16-bit */ + { + unsigned char r = 0, g = 0, b = 0, a = 0; + for(i = 0; i != numpixels; ++i) + { + getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode); + + if(!bits_done && profile->bits < 8) + { + /*only r is checked, < 8 bits is only relevant for greyscale*/ + unsigned bits = getValueRequiredBits(r); + if(bits > profile->bits) profile->bits = bits; + } + bits_done = (profile->bits >= bpp); + + if(!colored_done && (r != g || r != b)) + { + profile->colored = 1; + colored_done = 1; + if(profile->bits < 8) profile->bits = 8; /*PNG has no colored modes with less than 8-bit per channel*/ + } + + if(!alpha_done) + { + unsigned matchkey = (r == profile->key_r && g == profile->key_g && b == profile->key_b); + if(a != 255 && (a != 0 || (profile->key && !matchkey))) + { + profile->alpha = 1; + alpha_done = 1; + if(profile->bits < 8) profile->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + } + else if(a == 0 && !profile->alpha && !profile->key) + { + profile->key = 1; + profile->key_r = r; + profile->key_g = g; + profile->key_b = b; + } + else if(a == 255 && profile->key && matchkey) + { + /* Color key cannot be used if an opaque pixel also has that RGB color. */ + profile->alpha = 1; + alpha_done = 1; + if(profile->bits < 8) profile->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + } + } + + if(!numcolors_done) + { + if(!color_tree_has(&tree, r, g, b, a)) + { + color_tree_add(&tree, r, g, b, a, profile->numcolors); + if(profile->numcolors < 256) + { + unsigned char* p = profile->palette; + unsigned n = profile->numcolors; + p[n * 4 + 0] = r; + p[n * 4 + 1] = g; + p[n * 4 + 2] = b; + p[n * 4 + 3] = a; + } + ++profile->numcolors; + numcolors_done = profile->numcolors >= maxnumcolors; + } + } + + if(alpha_done && numcolors_done && colored_done && bits_done) break; + } + + if(profile->key && !profile->alpha) + { + for(i = 0; i != numpixels; ++i) + { + getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode); + if(a != 0 && r == profile->key_r && g == profile->key_g && b == profile->key_b) + { + /* Color key cannot be used if an opaque pixel also has that RGB color. */ + profile->alpha = 1; + alpha_done = 1; + } + } + } + + /*make the profile's key always 16-bit for consistency - repeat each byte twice*/ + profile->key_r += (profile->key_r << 8); + profile->key_g += (profile->key_g << 8); + profile->key_b += (profile->key_b << 8); + } + + color_tree_cleanup(&tree); + return error; +} + +/*Automatically chooses color type that gives smallest amount of bits in the +output image, e.g. grey if there are only greyscale pixels, palette if there +are less than 256 colors, ... +Updates values of mode with a potentially smaller color model. mode_out should +contain the user chosen color model, but will be overwritten with the new chosen one.*/ +unsigned lodepng_auto_choose_color(LodePNGColorMode* mode_out, + const unsigned char* image, unsigned w, unsigned h, + const LodePNGColorMode* mode_in) +{ + LodePNGColorProfile prof; + unsigned error = 0; + unsigned i, n, palettebits, grey_ok, palette_ok; + + lodepng_color_profile_init(&prof); + error = lodepng_get_color_profile(&prof, image, w, h, mode_in); + if(error) return error; + mode_out->key_defined = 0; + + if(prof.key && w * h <= 16) + { + prof.alpha = 1; /*too few pixels to justify tRNS chunk overhead*/ + if(prof.bits < 8) prof.bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + } + grey_ok = !prof.colored && !prof.alpha; /*grey without alpha, with potentially low bits*/ + n = prof.numcolors; + palettebits = n <= 2 ? 1 : (n <= 4 ? 2 : (n <= 16 ? 4 : 8)); + palette_ok = n <= 256 && (n * 2 < w * h) && prof.bits <= 8; + if(w * h < n * 2) palette_ok = 0; /*don't add palette overhead if image has only a few pixels*/ + if(grey_ok && prof.bits <= palettebits) palette_ok = 0; /*grey is less overhead*/ + + if(palette_ok) + { + unsigned char* p = prof.palette; + lodepng_palette_clear(mode_out); /*remove potential earlier palette*/ + for(i = 0; i != prof.numcolors; ++i) + { + error = lodepng_palette_add(mode_out, p[i * 4 + 0], p[i * 4 + 1], p[i * 4 + 2], p[i * 4 + 3]); + if(error) break; + } + + mode_out->colortype = LCT_PALETTE; + mode_out->bitdepth = palettebits; + + if(mode_in->colortype == LCT_PALETTE && mode_in->palettesize >= mode_out->palettesize + && mode_in->bitdepth == mode_out->bitdepth) + { + /*If input should have same palette colors, keep original to preserve its order and prevent conversion*/ + lodepng_color_mode_cleanup(mode_out); + lodepng_color_mode_copy(mode_out, mode_in); + } + } + else /*8-bit or 16-bit per channel*/ + { + mode_out->bitdepth = prof.bits; + mode_out->colortype = prof.alpha ? (prof.colored ? LCT_RGBA : LCT_GREY_ALPHA) + : (prof.colored ? LCT_RGB : LCT_GREY); + + if(prof.key && !prof.alpha) + { + unsigned mask = (1u << mode_out->bitdepth) - 1u; /*profile always uses 16-bit, mask converts it*/ + mode_out->key_r = prof.key_r & mask; + mode_out->key_g = prof.key_g & mask; + mode_out->key_b = prof.key_b & mask; + mode_out->key_defined = 1; + } + } + + return error; +} + +#endif /* #ifdef LODEPNG_COMPILE_ENCODER */ + +/* +Paeth predicter, used by PNG filter type 4 +The parameters are of type short, but should come from unsigned chars, the shorts +are only needed to make the paeth calculation correct. +*/ +static unsigned char paethPredictor(short a, short b, short c) +{ + short pa = abs(b - c); + short pb = abs(a - c); + short pc = abs(a + b - c - c); + + if(pc < pa && pc < pb) return (unsigned char)c; + else if(pb < pa) return (unsigned char)b; + else return (unsigned char)a; +} + +/*shared values used by multiple Adam7 related functions*/ + +static const unsigned ADAM7_IX[7] = { 0, 4, 0, 2, 0, 1, 0 }; /*x start values*/ +static const unsigned ADAM7_IY[7] = { 0, 0, 4, 0, 2, 0, 1 }; /*y start values*/ +static const unsigned ADAM7_DX[7] = { 8, 8, 4, 4, 2, 2, 1 }; /*x delta values*/ +static const unsigned ADAM7_DY[7] = { 8, 8, 8, 4, 4, 2, 2 }; /*y delta values*/ + +/* +Outputs various dimensions and positions in the image related to the Adam7 reduced images. +passw: output containing the width of the 7 passes +passh: output containing the height of the 7 passes +filter_passstart: output containing the index of the start and end of each + reduced image with filter bytes +padded_passstart output containing the index of the start and end of each + reduced image when without filter bytes but with padded scanlines +passstart: output containing the index of the start and end of each reduced + image without padding between scanlines, but still padding between the images +w, h: width and height of non-interlaced image +bpp: bits per pixel +"padded" is only relevant if bpp is less than 8 and a scanline or image does not + end at a full byte +*/ +static void Adam7_getpassvalues(unsigned passw[7], unsigned passh[7], size_t filter_passstart[8], + size_t padded_passstart[8], size_t passstart[8], unsigned w, unsigned h, unsigned bpp) +{ + /*the passstart values have 8 values: the 8th one indicates the byte after the end of the 7th (= last) pass*/ + unsigned i; + + /*calculate width and height in pixels of each pass*/ + for(i = 0; i != 7; ++i) + { + passw[i] = (w + ADAM7_DX[i] - ADAM7_IX[i] - 1) / ADAM7_DX[i]; + passh[i] = (h + ADAM7_DY[i] - ADAM7_IY[i] - 1) / ADAM7_DY[i]; + if(passw[i] == 0) passh[i] = 0; + if(passh[i] == 0) passw[i] = 0; + } + + filter_passstart[0] = padded_passstart[0] = passstart[0] = 0; + for(i = 0; i != 7; ++i) + { + /*if passw[i] is 0, it's 0 bytes, not 1 (no filtertype-byte)*/ + filter_passstart[i + 1] = filter_passstart[i] + + ((passw[i] && passh[i]) ? passh[i] * (1 + (passw[i] * bpp + 7) / 8) : 0); + /*bits padded if needed to fill full byte at end of each scanline*/ + padded_passstart[i + 1] = padded_passstart[i] + passh[i] * ((passw[i] * bpp + 7) / 8); + /*only padded at end of reduced image*/ + passstart[i + 1] = passstart[i] + (passh[i] * passw[i] * bpp + 7) / 8; + } +} + +#ifdef LODEPNG_COMPILE_DECODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / PNG Decoder / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*read the information from the header and store it in the LodePNGInfo. return value is error*/ +unsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state, + const unsigned char* in, size_t insize) +{ + LodePNGInfo* info = &state->info_png; + if(insize == 0 || in == 0) + { + CERROR_RETURN_ERROR(state->error, 48); /*error: the given data is empty*/ + } + if(insize < 33) + { + CERROR_RETURN_ERROR(state->error, 27); /*error: the data length is smaller than the length of a PNG header*/ + } + + /*when decoding a new PNG image, make sure all parameters created after previous decoding are reset*/ + lodepng_info_cleanup(info); + lodepng_info_init(info); + + if(in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71 + || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) + { + CERROR_RETURN_ERROR(state->error, 28); /*error: the first 8 bytes are not the correct PNG signature*/ + } + if(lodepng_chunk_length(in + 8) != 13) + { + CERROR_RETURN_ERROR(state->error, 94); /*error: header size must be 13 bytes*/ + } + if(!lodepng_chunk_type_equals(in + 8, "IHDR")) + { + CERROR_RETURN_ERROR(state->error, 29); /*error: it doesn't start with a IHDR chunk!*/ + } + + /*read the values given in the header*/ + *w = lodepng_read32bitInt(&in[16]); + *h = lodepng_read32bitInt(&in[20]); + info->color.bitdepth = in[24]; + info->color.colortype = (LodePNGColorType)in[25]; + info->compression_method = in[26]; + info->filter_method = in[27]; + info->interlace_method = in[28]; + + if(*w == 0 || *h == 0) + { + CERROR_RETURN_ERROR(state->error, 93); + } + + if(!state->decoder.ignore_crc) + { + unsigned CRC = lodepng_read32bitInt(&in[29]); + unsigned checksum = lodepng_crc32(&in[12], 17); + if(CRC != checksum) + { + CERROR_RETURN_ERROR(state->error, 57); /*invalid CRC*/ + } + } + + /*error: only compression method 0 is allowed in the specification*/ + if(info->compression_method != 0) CERROR_RETURN_ERROR(state->error, 32); + /*error: only filter method 0 is allowed in the specification*/ + if(info->filter_method != 0) CERROR_RETURN_ERROR(state->error, 33); + /*error: only interlace methods 0 and 1 exist in the specification*/ + if(info->interlace_method > 1) CERROR_RETURN_ERROR(state->error, 34); + + state->error = checkColorValidity(info->color.colortype, info->color.bitdepth); + return state->error; +} + +static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon, + size_t bytewidth, unsigned char filterType, size_t length) +{ + /* + For PNG filter method 0 + unfilter a PNG image scanline by scanline. when the pixels are smaller than 1 byte, + the filter works byte per byte (bytewidth = 1) + precon is the previous unfiltered scanline, recon the result, scanline the current one + the incoming scanlines do NOT include the filtertype byte, that one is given in the parameter filterType instead + recon and scanline MAY be the same memory address! precon must be disjoint. + */ + + size_t i; + switch(filterType) + { + case 0: + for(i = 0; i != length; ++i) recon[i] = scanline[i]; + break; + case 1: + for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i]; + for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + recon[i - bytewidth]; + break; + case 2: + if(precon) + { + for(i = 0; i != length; ++i) recon[i] = scanline[i] + precon[i]; + } + else + { + for(i = 0; i != length; ++i) recon[i] = scanline[i]; + } + break; + case 3: + if(precon) + { + for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i] + (precon[i] >> 1); + for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) >> 1); + } + else + { + for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i]; + for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + (recon[i - bytewidth] >> 1); + } + break; + case 4: + if(precon) + { + for(i = 0; i != bytewidth; ++i) + { + recon[i] = (scanline[i] + precon[i]); /*paethPredictor(0, precon[i], 0) is always precon[i]*/ + } + for(i = bytewidth; i < length; ++i) + { + recon[i] = (scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth])); + } + } + else + { + for(i = 0; i != bytewidth; ++i) + { + recon[i] = scanline[i]; + } + for(i = bytewidth; i < length; ++i) + { + /*paethPredictor(recon[i - bytewidth], 0, 0) is always recon[i - bytewidth]*/ + recon[i] = (scanline[i] + recon[i - bytewidth]); + } + } + break; + default: return 36; /*error: unexisting filter type given*/ + } + return 0; +} + +static unsigned unfilter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) +{ + /* + For PNG filter method 0 + this function unfilters a single image (e.g. without interlacing this is called once, with Adam7 seven times) + out must have enough bytes allocated already, in must have the scanlines + 1 filtertype byte per scanline + w and h are image dimensions or dimensions of reduced image, bpp is bits per pixel + in and out are allowed to be the same memory address (but aren't the same size since in has the extra filter bytes) + */ + + unsigned y; + unsigned char* prevline = 0; + + /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ + size_t bytewidth = (bpp + 7) / 8; + size_t linebytes = (w * bpp + 7) / 8; + + for(y = 0; y < h; ++y) + { + size_t outindex = linebytes * y; + size_t inindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + unsigned char filterType = in[inindex]; + + CERROR_TRY_RETURN(unfilterScanline(&out[outindex], &in[inindex + 1], prevline, bytewidth, filterType, linebytes)); + + prevline = &out[outindex]; + } + + return 0; +} + +/* +in: Adam7 interlaced image, with no padding bits between scanlines, but between + reduced images so that each reduced image starts at a byte. +out: the same pixels, but re-ordered so that they're now a non-interlaced image with size w*h +bpp: bits per pixel +out has the following size in bits: w * h * bpp. +in is possibly bigger due to padding bits between reduced images. +out must be big enough AND must be 0 everywhere if bpp < 8 in the current implementation +(because that's likely a little bit faster) +NOTE: comments about padding bits are only relevant if bpp < 8 +*/ +static void Adam7_deinterlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) +{ + unsigned passw[7], passh[7]; + size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + if(bpp >= 8) + { + for(i = 0; i != 7; ++i) + { + unsigned x, y, b; + size_t bytewidth = bpp / 8; + for(y = 0; y < passh[i]; ++y) + for(x = 0; x < passw[i]; ++x) + { + size_t pixelinstart = passstart[i] + (y * passw[i] + x) * bytewidth; + size_t pixeloutstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth; + for(b = 0; b < bytewidth; ++b) + { + out[pixeloutstart + b] = in[pixelinstart + b]; + } + } + } + } + else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ + { + for(i = 0; i != 7; ++i) + { + unsigned x, y, b; + unsigned ilinebits = bpp * passw[i]; + unsigned olinebits = bpp * w; + size_t obp, ibp; /*bit pointers (for out and in buffer)*/ + for(y = 0; y < passh[i]; ++y) + for(x = 0; x < passw[i]; ++x) + { + ibp = (8 * passstart[i]) + (y * ilinebits + x * bpp); + obp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp; + for(b = 0; b < bpp; ++b) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + /*note that this function assumes the out buffer is completely 0, use setBitOfReversedStream otherwise*/ + setBitOfReversedStream0(&obp, out, bit); + } + } + } + } +} + +static void removePaddingBits(unsigned char* out, const unsigned char* in, + size_t olinebits, size_t ilinebits, unsigned h) +{ + /* + After filtering there are still padding bits if scanlines have non multiple of 8 bit amounts. They need + to be removed (except at last scanline of (Adam7-reduced) image) before working with pure image buffers + for the Adam7 code, the color convert code and the output to the user. + in and out are allowed to be the same buffer, in may also be higher but still overlapping; in must + have >= ilinebits*h bits, out must have >= olinebits*h bits, olinebits must be <= ilinebits + also used to move bits after earlier such operations happened, e.g. in a sequence of reduced images from Adam7 + only useful if (ilinebits - olinebits) is a value in the range 1..7 + */ + unsigned y; + size_t diff = ilinebits - olinebits; + size_t ibp = 0, obp = 0; /*input and output bit pointers*/ + for(y = 0; y < h; ++y) + { + size_t x; + for(x = 0; x < olinebits; ++x) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + ibp += diff; + } +} + +/*out must be buffer big enough to contain full image, and in must contain the full decompressed data from +the IDAT chunks (with filter index bytes and possible padding bits) +return value is error*/ +static unsigned postProcessScanlines(unsigned char* out, unsigned char* in, + unsigned w, unsigned h, const LodePNGInfo* info_png) +{ + /* + This function converts the filtered-padded-interlaced data into pure 2D image buffer with the PNG's colortype. + Steps: + *) if no Adam7: 1) unfilter 2) remove padding bits (= posible extra bits per scanline if bpp < 8) + *) if adam7: 1) 7x unfilter 2) 7x remove padding bits 3) Adam7_deinterlace + NOTE: the in buffer will be overwritten with intermediate data! + */ + unsigned bpp = lodepng_get_bpp(&info_png->color); + if(bpp == 0) return 31; /*error: invalid colortype*/ + + if(info_png->interlace_method == 0) + { + if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8) + { + CERROR_TRY_RETURN(unfilter(in, in, w, h, bpp)); + removePaddingBits(out, in, w * bpp, ((w * bpp + 7) / 8) * 8, h); + } + /*we can immediately filter into the out buffer, no other steps needed*/ + else CERROR_TRY_RETURN(unfilter(out, in, w, h, bpp)); + } + else /*interlace_method is 1 (Adam7)*/ + { + unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + for(i = 0; i != 7; ++i) + { + CERROR_TRY_RETURN(unfilter(&in[padded_passstart[i]], &in[filter_passstart[i]], passw[i], passh[i], bpp)); + /*TODO: possible efficiency improvement: if in this reduced image the bits fit nicely in 1 scanline, + move bytes instead of bits or move not at all*/ + if(bpp < 8) + { + /*remove padding bits in scanlines; after this there still may be padding + bits between the different reduced images: each reduced image still starts nicely at a byte*/ + removePaddingBits(&in[passstart[i]], &in[padded_passstart[i]], passw[i] * bpp, + ((passw[i] * bpp + 7) / 8) * 8, passh[i]); + } + } + + Adam7_deinterlace(out, in, w, h, bpp); + } + + return 0; +} + +static unsigned readChunk_PLTE(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength) +{ + unsigned pos = 0, i; + if(color->palette) lodepng_free(color->palette); + color->palettesize = chunkLength / 3; + color->palette = (unsigned char*)lodepng_malloc(4 * color->palettesize); + if(!color->palette && color->palettesize) + { + color->palettesize = 0; + return 83; /*alloc fail*/ + } + if(color->palettesize > 256) return 38; /*error: palette too big*/ + + for(i = 0; i != color->palettesize; ++i) + { + color->palette[4 * i + 0] = data[pos++]; /*R*/ + color->palette[4 * i + 1] = data[pos++]; /*G*/ + color->palette[4 * i + 2] = data[pos++]; /*B*/ + color->palette[4 * i + 3] = 255; /*alpha*/ + } + + return 0; /* OK */ +} + +static unsigned readChunk_tRNS(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength) +{ + unsigned i; + if(color->colortype == LCT_PALETTE) + { + /*error: more alpha values given than there are palette entries*/ + if(chunkLength > color->palettesize) return 38; + + for(i = 0; i != chunkLength; ++i) color->palette[4 * i + 3] = data[i]; + } + else if(color->colortype == LCT_GREY) + { + /*error: this chunk must be 2 bytes for greyscale image*/ + if(chunkLength != 2) return 30; + + color->key_defined = 1; + color->key_r = color->key_g = color->key_b = 256u * data[0] + data[1]; + } + else if(color->colortype == LCT_RGB) + { + /*error: this chunk must be 6 bytes for RGB image*/ + if(chunkLength != 6) return 41; + + color->key_defined = 1; + color->key_r = 256u * data[0] + data[1]; + color->key_g = 256u * data[2] + data[3]; + color->key_b = 256u * data[4] + data[5]; + } + else return 42; /*error: tRNS chunk not allowed for other color models*/ + + return 0; /* OK */ +} + + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +/*background color chunk (bKGD)*/ +static unsigned readChunk_bKGD(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) +{ + if(info->color.colortype == LCT_PALETTE) + { + /*error: this chunk must be 1 byte for indexed color image*/ + if(chunkLength != 1) return 43; + + info->background_defined = 1; + info->background_r = info->background_g = info->background_b = data[0]; + } + else if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) + { + /*error: this chunk must be 2 bytes for greyscale image*/ + if(chunkLength != 2) return 44; + + info->background_defined = 1; + info->background_r = info->background_g = info->background_b = 256u * data[0] + data[1]; + } + else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) + { + /*error: this chunk must be 6 bytes for greyscale image*/ + if(chunkLength != 6) return 45; + + info->background_defined = 1; + info->background_r = 256u * data[0] + data[1]; + info->background_g = 256u * data[2] + data[3]; + info->background_b = 256u * data[4] + data[5]; + } + + return 0; /* OK */ +} + +/*text chunk (tEXt)*/ +static unsigned readChunk_tEXt(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) +{ + unsigned error = 0; + char *key = 0, *str = 0; + unsigned i; + + while(!error) /*not really a while loop, only used to break on error*/ + { + unsigned length, string2_begin; + + length = 0; + while(length < chunkLength && data[length] != 0) ++length; + /*even though it's not allowed by the standard, no error is thrown if + there's no null termination char, if the text is empty*/ + if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ + + key = (char*)lodepng_malloc(length + 1); + if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + + key[length] = 0; + for(i = 0; i != length; ++i) key[i] = (char)data[i]; + + string2_begin = length + 1; /*skip keyword null terminator*/ + + length = chunkLength < string2_begin ? 0 : chunkLength - string2_begin; + str = (char*)lodepng_malloc(length + 1); + if(!str) CERROR_BREAK(error, 83); /*alloc fail*/ + + str[length] = 0; + for(i = 0; i != length; ++i) str[i] = (char)data[string2_begin + i]; + + error = lodepng_add_text(info, key, str); + + break; + } + + lodepng_free(key); + lodepng_free(str); + + return error; +} + +/*compressed text chunk (zTXt)*/ +static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings, + const unsigned char* data, size_t chunkLength) +{ + unsigned error = 0; + unsigned i; + + unsigned length, string2_begin; + char *key = 0; + ucvector decoded; + + ucvector_init(&decoded); + + while(!error) /*not really a while loop, only used to break on error*/ + { + for(length = 0; length < chunkLength && data[length] != 0; ++length) ; + if(length + 2 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ + if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ + + key = (char*)lodepng_malloc(length + 1); + if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + + key[length] = 0; + for(i = 0; i != length; ++i) key[i] = (char)data[i]; + + if(data[length + 1] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ + + string2_begin = length + 2; + if(string2_begin > chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ + + length = chunkLength - string2_begin; + /*will fail if zlib error, e.g. if length is too small*/ + error = zlib_decompress(&decoded.data, &decoded.size, + (unsigned char*)(&data[string2_begin]), + length, zlibsettings); + if(error) break; + ucvector_push_back(&decoded, 0); + + error = lodepng_add_text(info, key, (char*)decoded.data); + + break; + } + + lodepng_free(key); + ucvector_cleanup(&decoded); + + return error; +} + +/*international text chunk (iTXt)*/ +static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings, + const unsigned char* data, size_t chunkLength) +{ + unsigned error = 0; + unsigned i; + + unsigned length, begin, compressed; + char *key = 0, *langtag = 0, *transkey = 0; + ucvector decoded; + ucvector_init(&decoded); + + while(!error) /*not really a while loop, only used to break on error*/ + { + /*Quick check if the chunk length isn't too small. Even without check + it'd still fail with other error checks below if it's too short. This just gives a different error code.*/ + if(chunkLength < 5) CERROR_BREAK(error, 30); /*iTXt chunk too short*/ + + /*read the key*/ + for(length = 0; length < chunkLength && data[length] != 0; ++length) ; + if(length + 3 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination char, corrupt?*/ + if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ + + key = (char*)lodepng_malloc(length + 1); + if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + + key[length] = 0; + for(i = 0; i != length; ++i) key[i] = (char)data[i]; + + /*read the compression method*/ + compressed = data[length + 1]; + if(data[length + 2] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ + + /*even though it's not allowed by the standard, no error is thrown if + there's no null termination char, if the text is empty for the next 3 texts*/ + + /*read the langtag*/ + begin = length + 3; + length = 0; + for(i = begin; i < chunkLength && data[i] != 0; ++i) ++length; + + langtag = (char*)lodepng_malloc(length + 1); + if(!langtag) CERROR_BREAK(error, 83); /*alloc fail*/ + + langtag[length] = 0; + for(i = 0; i != length; ++i) langtag[i] = (char)data[begin + i]; + + /*read the transkey*/ + begin += length + 1; + length = 0; + for(i = begin; i < chunkLength && data[i] != 0; ++i) ++length; + + transkey = (char*)lodepng_malloc(length + 1); + if(!transkey) CERROR_BREAK(error, 83); /*alloc fail*/ + + transkey[length] = 0; + for(i = 0; i != length; ++i) transkey[i] = (char)data[begin + i]; + + /*read the actual text*/ + begin += length + 1; + + length = chunkLength < begin ? 0 : chunkLength - begin; + + if(compressed) + { + /*will fail if zlib error, e.g. if length is too small*/ + error = zlib_decompress(&decoded.data, &decoded.size, + (unsigned char*)(&data[begin]), + length, zlibsettings); + if(error) break; + if(decoded.allocsize < decoded.size) decoded.allocsize = decoded.size; + ucvector_push_back(&decoded, 0); + } + else + { + if(!ucvector_resize(&decoded, length + 1)) CERROR_BREAK(error, 83 /*alloc fail*/); + + decoded.data[length] = 0; + for(i = 0; i != length; ++i) decoded.data[i] = data[begin + i]; + } + + error = lodepng_add_itext(info, key, langtag, transkey, (char*)decoded.data); + + break; + } + + lodepng_free(key); + lodepng_free(langtag); + lodepng_free(transkey); + ucvector_cleanup(&decoded); + + return error; +} + +static unsigned readChunk_tIME(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) +{ + if(chunkLength != 7) return 73; /*invalid tIME chunk size*/ + + info->time_defined = 1; + info->time.year = 256u * data[0] + data[1]; + info->time.month = data[2]; + info->time.day = data[3]; + info->time.hour = data[4]; + info->time.minute = data[5]; + info->time.second = data[6]; + + return 0; /* OK */ +} + +static unsigned readChunk_pHYs(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) +{ + if(chunkLength != 9) return 74; /*invalid pHYs chunk size*/ + + info->phys_defined = 1; + info->phys_x = 16777216u * data[0] + 65536u * data[1] + 256u * data[2] + data[3]; + info->phys_y = 16777216u * data[4] + 65536u * data[5] + 256u * data[6] + data[7]; + info->phys_unit = data[8]; + + return 0; /* OK */ +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +/*read a PNG, the result will be in the same color type as the PNG (hence "generic")*/ +static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize) +{ + unsigned char IEND = 0; + const unsigned char* chunk; + size_t i; + ucvector idat; /*the data from idat chunks*/ + ucvector scanlines; + size_t predict; + size_t numpixels; + size_t outsize = 0; + + /*for unknown chunk order*/ + unsigned unknown = 0; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + unsigned critical_pos = 1; /*1 = after IHDR, 2 = after PLTE, 3 = after IDAT*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + + /*provide some proper output values if error will happen*/ + *out = 0; + + state->error = lodepng_inspect(w, h, state, in, insize); /*reads header and resets other parameters in state->info_png*/ + if(state->error) return; + + numpixels = *w * *h; + + /*multiplication overflow*/ + if(*h != 0 && numpixels / *h != *w) CERROR_RETURN(state->error, 92); + /*multiplication overflow possible further below. Allows up to 2^31-1 pixel + bytes with 16-bit RGBA, the rest is room for filter bytes.*/ + if(numpixels > 268435455) CERROR_RETURN(state->error, 92); + + ucvector_init(&idat); + chunk = &in[33]; /*first byte of the first chunk after the header*/ + + /*loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. + IDAT data is put at the start of the in buffer*/ + while(!IEND && !state->error) + { + unsigned chunkLength; + const unsigned char* data; /*the data in the chunk*/ + + /*error: size of the in buffer too small to contain next chunk*/ + if((size_t)((chunk - in) + 12) > insize || chunk < in) CERROR_BREAK(state->error, 30); + + /*length of the data of the chunk, excluding the length bytes, chunk type and CRC bytes*/ + chunkLength = lodepng_chunk_length(chunk); + /*error: chunk length larger than the max PNG chunk size*/ + if(chunkLength > 2147483647) CERROR_BREAK(state->error, 63); + + if((size_t)((chunk - in) + chunkLength + 12) > insize || (chunk + chunkLength + 12) < in) + { + CERROR_BREAK(state->error, 64); /*error: size of the in buffer too small to contain next chunk*/ + } + + data = lodepng_chunk_data_const(chunk); + + /*IDAT chunk, containing compressed image data*/ + if(lodepng_chunk_type_equals(chunk, "IDAT")) + { + size_t oldsize = idat.size; + if(!ucvector_resize(&idat, oldsize + chunkLength)) CERROR_BREAK(state->error, 83 /*alloc fail*/); + for(i = 0; i != chunkLength; ++i) idat.data[oldsize + i] = data[i]; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + critical_pos = 3; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } + /*IEND chunk*/ + else if(lodepng_chunk_type_equals(chunk, "IEND")) + { + IEND = 1; + } + /*palette chunk (PLTE)*/ + else if(lodepng_chunk_type_equals(chunk, "PLTE")) + { + state->error = readChunk_PLTE(&state->info_png.color, data, chunkLength); + if(state->error) break; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + critical_pos = 2; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } + /*palette transparency chunk (tRNS)*/ + else if(lodepng_chunk_type_equals(chunk, "tRNS")) + { + state->error = readChunk_tRNS(&state->info_png.color, data, chunkLength); + if(state->error) break; + } +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*background color chunk (bKGD)*/ + else if(lodepng_chunk_type_equals(chunk, "bKGD")) + { + state->error = readChunk_bKGD(&state->info_png, data, chunkLength); + if(state->error) break; + } + /*text chunk (tEXt)*/ + else if(lodepng_chunk_type_equals(chunk, "tEXt")) + { + if(state->decoder.read_text_chunks) + { + state->error = readChunk_tEXt(&state->info_png, data, chunkLength); + if(state->error) break; + } + } + /*compressed text chunk (zTXt)*/ + else if(lodepng_chunk_type_equals(chunk, "zTXt")) + { + if(state->decoder.read_text_chunks) + { + state->error = readChunk_zTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength); + if(state->error) break; + } + } + /*international text chunk (iTXt)*/ + else if(lodepng_chunk_type_equals(chunk, "iTXt")) + { + if(state->decoder.read_text_chunks) + { + state->error = readChunk_iTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength); + if(state->error) break; + } + } + else if(lodepng_chunk_type_equals(chunk, "tIME")) + { + state->error = readChunk_tIME(&state->info_png, data, chunkLength); + if(state->error) break; + } + else if(lodepng_chunk_type_equals(chunk, "pHYs")) + { + state->error = readChunk_pHYs(&state->info_png, data, chunkLength); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + else /*it's not an implemented chunk type, so ignore it: skip over the data*/ + { + /*error: unknown critical chunk (5th bit of first byte of chunk type is 0)*/ + if(!lodepng_chunk_ancillary(chunk)) CERROR_BREAK(state->error, 69); + + unknown = 1; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + if(state->decoder.remember_unknown_chunks) + { + state->error = lodepng_chunk_append(&state->info_png.unknown_chunks_data[critical_pos - 1], + &state->info_png.unknown_chunks_size[critical_pos - 1], chunk); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } + + if(!state->decoder.ignore_crc && !unknown) /*check CRC if wanted, only on known chunk types*/ + { + if(lodepng_chunk_check_crc(chunk)) CERROR_BREAK(state->error, 57); /*invalid CRC*/ + } + + if(!IEND) chunk = lodepng_chunk_next_const(chunk); + } + + ucvector_init(&scanlines); + /*predict output size, to allocate exact size for output buffer to avoid more dynamic allocation. + If the decompressed size does not match the prediction, the image must be corrupt.*/ + if(state->info_png.interlace_method == 0) + { + /*The extra *h is added because this are the filter bytes every scanline starts with*/ + predict = lodepng_get_raw_size_idat(*w, *h, &state->info_png.color) + *h; + } + else + { + /*Adam-7 interlaced: predicted size is the sum of the 7 sub-images sizes*/ + const LodePNGColorMode* color = &state->info_png.color; + predict = 0; + predict += lodepng_get_raw_size_idat((*w + 7) >> 3, (*h + 7) >> 3, color) + ((*h + 7) >> 3); + if(*w > 4) predict += lodepng_get_raw_size_idat((*w + 3) >> 3, (*h + 7) >> 3, color) + ((*h + 7) >> 3); + predict += lodepng_get_raw_size_idat((*w + 3) >> 2, (*h + 3) >> 3, color) + ((*h + 3) >> 3); + if(*w > 2) predict += lodepng_get_raw_size_idat((*w + 1) >> 2, (*h + 3) >> 2, color) + ((*h + 3) >> 2); + predict += lodepng_get_raw_size_idat((*w + 1) >> 1, (*h + 1) >> 2, color) + ((*h + 1) >> 2); + if(*w > 1) predict += lodepng_get_raw_size_idat((*w + 0) >> 1, (*h + 1) >> 1, color) + ((*h + 1) >> 1); + predict += lodepng_get_raw_size_idat((*w + 0), (*h + 0) >> 1, color) + ((*h + 0) >> 1); + } + if(!state->error && !ucvector_reserve(&scanlines, predict)) state->error = 83; /*alloc fail*/ + if(!state->error) + { + state->error = zlib_decompress(&scanlines.data, &scanlines.size, idat.data, + idat.size, &state->decoder.zlibsettings); + if(!state->error && scanlines.size != predict) state->error = 91; /*decompressed size doesn't match prediction*/ + } + ucvector_cleanup(&idat); + + if(!state->error) + { + outsize = lodepng_get_raw_size(*w, *h, &state->info_png.color); + *out = (unsigned char*)lodepng_malloc(outsize); + if(!*out) state->error = 83; /*alloc fail*/ + } + if(!state->error) + { + for(i = 0; i < outsize; i++) (*out)[i] = 0; + state->error = postProcessScanlines(*out, scanlines.data, *w, *h, &state->info_png); + } + ucvector_cleanup(&scanlines); +} + +unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize) +{ + *out = 0; + decodeGeneric(out, w, h, state, in, insize); + if(state->error) return state->error; + if(!state->decoder.color_convert || lodepng_color_mode_equal(&state->info_raw, &state->info_png.color)) + { + /*same color type, no copying or converting of data needed*/ + /*store the info_png color settings on the info_raw so that the info_raw still reflects what colortype + the raw image has to the end user*/ + if(!state->decoder.color_convert) + { + state->error = lodepng_color_mode_copy(&state->info_raw, &state->info_png.color); + if(state->error) return state->error; + } + } + else + { + /*color conversion needed; sort of copy of the data*/ + unsigned char* data = *out; + size_t outsize; + + /*TODO: check if this works according to the statement in the documentation: "The converter can convert + from greyscale input color type, to 8-bit greyscale or greyscale with alpha"*/ + if(!(state->info_raw.colortype == LCT_RGB || state->info_raw.colortype == LCT_RGBA) + && !(state->info_raw.bitdepth == 8)) + { + return 56; /*unsupported color mode conversion*/ + } + + outsize = lodepng_get_raw_size(*w, *h, &state->info_raw); + *out = (unsigned char*)lodepng_malloc(outsize); + if(!(*out)) + { + state->error = 83; /*alloc fail*/ + } + else state->error = lodepng_convert(*out, data, &state->info_raw, + &state->info_png.color, *w, *h); + lodepng_free(data); + } + return state->error; +} + +unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, + size_t insize, LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned error; + LodePNGState state; + lodepng_state_init(&state); + state.info_raw.colortype = colortype; + state.info_raw.bitdepth = bitdepth; + error = lodepng_decode(out, w, h, &state, in, insize); + lodepng_state_cleanup(&state); + return error; +} + +unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) +{ + return lodepng_decode_memory(out, w, h, in, insize, LCT_RGBA, 8); +} + +unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) +{ + return lodepng_decode_memory(out, w, h, in, insize, LCT_RGB, 8); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename, + LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned char* buffer = 0; + size_t buffersize; + unsigned error; + error = lodepng_load_file(&buffer, &buffersize, filename); + if(!error) error = lodepng_decode_memory(out, w, h, buffer, buffersize, colortype, bitdepth); + lodepng_free(buffer); + return error; +} + +unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename) +{ + return lodepng_decode_file(out, w, h, filename, LCT_RGBA, 8); +} + +unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename) +{ + return lodepng_decode_file(out, w, h, filename, LCT_RGB, 8); +} +#endif /*LODEPNG_COMPILE_DISK*/ + +void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings) +{ + settings->color_convert = 1; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + settings->read_text_chunks = 1; + settings->remember_unknown_chunks = 0; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + settings->ignore_crc = 0; + lodepng_decompress_settings_init(&settings->zlibsettings); +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) + +void lodepng_state_init(LodePNGState* state) +{ +#ifdef LODEPNG_COMPILE_DECODER + lodepng_decoder_settings_init(&state->decoder); +#endif /*LODEPNG_COMPILE_DECODER*/ +#ifdef LODEPNG_COMPILE_ENCODER + lodepng_encoder_settings_init(&state->encoder); +#endif /*LODEPNG_COMPILE_ENCODER*/ + lodepng_color_mode_init(&state->info_raw); + lodepng_info_init(&state->info_png); + state->error = 1; +} + +void lodepng_state_cleanup(LodePNGState* state) +{ + lodepng_color_mode_cleanup(&state->info_raw); + lodepng_info_cleanup(&state->info_png); +} + +void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source) +{ + lodepng_state_cleanup(dest); + *dest = *source; + lodepng_color_mode_init(&dest->info_raw); + lodepng_info_init(&dest->info_png); + dest->error = lodepng_color_mode_copy(&dest->info_raw, &source->info_raw); if(dest->error) return; + dest->error = lodepng_info_copy(&dest->info_png, &source->info_png); if(dest->error) return; +} + +#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ + +#ifdef LODEPNG_COMPILE_ENCODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / PNG Encoder / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*chunkName must be string of 4 characters*/ +static unsigned addChunk(ucvector* out, const char* chunkName, const unsigned char* data, size_t length) +{ + CERROR_TRY_RETURN(lodepng_chunk_create(&out->data, &out->size, (unsigned)length, chunkName, data)); + out->allocsize = out->size; /*fix the allocsize again*/ + return 0; +} + +static void writeSignature(ucvector* out) +{ + /*8 bytes PNG signature, aka the magic bytes*/ + ucvector_push_back(out, 137); + ucvector_push_back(out, 80); + ucvector_push_back(out, 78); + ucvector_push_back(out, 71); + ucvector_push_back(out, 13); + ucvector_push_back(out, 10); + ucvector_push_back(out, 26); + ucvector_push_back(out, 10); +} + +static unsigned addChunk_IHDR(ucvector* out, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth, unsigned interlace_method) +{ + unsigned error = 0; + ucvector header; + ucvector_init(&header); + + lodepng_add32bitInt(&header, w); /*width*/ + lodepng_add32bitInt(&header, h); /*height*/ + ucvector_push_back(&header, (unsigned char)bitdepth); /*bit depth*/ + ucvector_push_back(&header, (unsigned char)colortype); /*color type*/ + ucvector_push_back(&header, 0); /*compression method*/ + ucvector_push_back(&header, 0); /*filter method*/ + ucvector_push_back(&header, interlace_method); /*interlace method*/ + + error = addChunk(out, "IHDR", header.data, header.size); + ucvector_cleanup(&header); + + return error; +} + +static unsigned addChunk_PLTE(ucvector* out, const LodePNGColorMode* info) +{ + unsigned error = 0; + size_t i; + ucvector PLTE; + ucvector_init(&PLTE); + for(i = 0; i != info->palettesize * 4; ++i) + { + /*add all channels except alpha channel*/ + if(i % 4 != 3) ucvector_push_back(&PLTE, info->palette[i]); + } + error = addChunk(out, "PLTE", PLTE.data, PLTE.size); + ucvector_cleanup(&PLTE); + + return error; +} + +static unsigned addChunk_tRNS(ucvector* out, const LodePNGColorMode* info) +{ + unsigned error = 0; + size_t i; + ucvector tRNS; + ucvector_init(&tRNS); + if(info->colortype == LCT_PALETTE) + { + size_t amount = info->palettesize; + /*the tail of palette values that all have 255 as alpha, does not have to be encoded*/ + for(i = info->palettesize; i != 0; --i) + { + if(info->palette[4 * (i - 1) + 3] == 255) --amount; + else break; + } + /*add only alpha channel*/ + for(i = 0; i != amount; ++i) ucvector_push_back(&tRNS, info->palette[4 * i + 3]); + } + else if(info->colortype == LCT_GREY) + { + if(info->key_defined) + { + ucvector_push_back(&tRNS, (unsigned char)(info->key_r >> 8)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_r & 255)); + } + } + else if(info->colortype == LCT_RGB) + { + if(info->key_defined) + { + ucvector_push_back(&tRNS, (unsigned char)(info->key_r >> 8)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_r & 255)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_g >> 8)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_g & 255)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_b >> 8)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_b & 255)); + } + } + + error = addChunk(out, "tRNS", tRNS.data, tRNS.size); + ucvector_cleanup(&tRNS); + + return error; +} + +static unsigned addChunk_IDAT(ucvector* out, const unsigned char* data, size_t datasize, + LodePNGCompressSettings* zlibsettings) +{ + ucvector zlibdata; + unsigned error = 0; + + /*compress with the Zlib compressor*/ + ucvector_init(&zlibdata); + error = zlib_compress(&zlibdata.data, &zlibdata.size, data, datasize, zlibsettings); + if(!error) error = addChunk(out, "IDAT", zlibdata.data, zlibdata.size); + ucvector_cleanup(&zlibdata); + + return error; +} + +static unsigned addChunk_IEND(ucvector* out) +{ + unsigned error = 0; + error = addChunk(out, "IEND", 0, 0); + return error; +} + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + +static unsigned addChunk_tEXt(ucvector* out, const char* keyword, const char* textstring) +{ + unsigned error = 0; + size_t i; + ucvector text; + ucvector_init(&text); + for(i = 0; keyword[i] != 0; ++i) ucvector_push_back(&text, (unsigned char)keyword[i]); + if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ + ucvector_push_back(&text, 0); /*0 termination char*/ + for(i = 0; textstring[i] != 0; ++i) ucvector_push_back(&text, (unsigned char)textstring[i]); + error = addChunk(out, "tEXt", text.data, text.size); + ucvector_cleanup(&text); + + return error; +} + +static unsigned addChunk_zTXt(ucvector* out, const char* keyword, const char* textstring, + LodePNGCompressSettings* zlibsettings) +{ + unsigned error = 0; + ucvector data, compressed; + size_t i, textsize = strlen(textstring); + + ucvector_init(&data); + ucvector_init(&compressed); + for(i = 0; keyword[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)keyword[i]); + if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ + ucvector_push_back(&data, 0); /*0 termination char*/ + ucvector_push_back(&data, 0); /*compression method: 0*/ + + error = zlib_compress(&compressed.data, &compressed.size, + (unsigned char*)textstring, textsize, zlibsettings); + if(!error) + { + for(i = 0; i != compressed.size; ++i) ucvector_push_back(&data, compressed.data[i]); + error = addChunk(out, "zTXt", data.data, data.size); + } + + ucvector_cleanup(&compressed); + ucvector_cleanup(&data); + return error; +} + +static unsigned addChunk_iTXt(ucvector* out, unsigned compressed, const char* keyword, const char* langtag, + const char* transkey, const char* textstring, LodePNGCompressSettings* zlibsettings) +{ + unsigned error = 0; + ucvector data; + size_t i, textsize = strlen(textstring); + + ucvector_init(&data); + + for(i = 0; keyword[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)keyword[i]); + if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ + ucvector_push_back(&data, 0); /*null termination char*/ + ucvector_push_back(&data, compressed ? 1 : 0); /*compression flag*/ + ucvector_push_back(&data, 0); /*compression method*/ + for(i = 0; langtag[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)langtag[i]); + ucvector_push_back(&data, 0); /*null termination char*/ + for(i = 0; transkey[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)transkey[i]); + ucvector_push_back(&data, 0); /*null termination char*/ + + if(compressed) + { + ucvector compressed_data; + ucvector_init(&compressed_data); + error = zlib_compress(&compressed_data.data, &compressed_data.size, + (unsigned char*)textstring, textsize, zlibsettings); + if(!error) + { + for(i = 0; i != compressed_data.size; ++i) ucvector_push_back(&data, compressed_data.data[i]); + } + ucvector_cleanup(&compressed_data); + } + else /*not compressed*/ + { + for(i = 0; textstring[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)textstring[i]); + } + + if(!error) error = addChunk(out, "iTXt", data.data, data.size); + ucvector_cleanup(&data); + return error; +} + +static unsigned addChunk_bKGD(ucvector* out, const LodePNGInfo* info) +{ + unsigned error = 0; + ucvector bKGD; + ucvector_init(&bKGD); + if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) + { + ucvector_push_back(&bKGD, (unsigned char)(info->background_r >> 8)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_r & 255)); + } + else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) + { + ucvector_push_back(&bKGD, (unsigned char)(info->background_r >> 8)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_r & 255)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_g >> 8)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_g & 255)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_b >> 8)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_b & 255)); + } + else if(info->color.colortype == LCT_PALETTE) + { + ucvector_push_back(&bKGD, (unsigned char)(info->background_r & 255)); /*palette index*/ + } + + error = addChunk(out, "bKGD", bKGD.data, bKGD.size); + ucvector_cleanup(&bKGD); + + return error; +} + +static unsigned addChunk_tIME(ucvector* out, const LodePNGTime* time) +{ + unsigned error = 0; + unsigned char* data = (unsigned char*)lodepng_malloc(7); + if(!data) return 83; /*alloc fail*/ + data[0] = (unsigned char)(time->year >> 8); + data[1] = (unsigned char)(time->year & 255); + data[2] = (unsigned char)time->month; + data[3] = (unsigned char)time->day; + data[4] = (unsigned char)time->hour; + data[5] = (unsigned char)time->minute; + data[6] = (unsigned char)time->second; + error = addChunk(out, "tIME", data, 7); + lodepng_free(data); + return error; +} + +static unsigned addChunk_pHYs(ucvector* out, const LodePNGInfo* info) +{ + unsigned error = 0; + ucvector data; + ucvector_init(&data); + + lodepng_add32bitInt(&data, info->phys_x); + lodepng_add32bitInt(&data, info->phys_y); + ucvector_push_back(&data, info->phys_unit); + + error = addChunk(out, "pHYs", data.data, data.size); + ucvector_cleanup(&data); + + return error; +} + +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +static void filterScanline(unsigned char* out, const unsigned char* scanline, const unsigned char* prevline, + size_t length, size_t bytewidth, unsigned char filterType) +{ + size_t i; + switch(filterType) + { + case 0: /*None*/ + for(i = 0; i != length; ++i) out[i] = scanline[i]; + break; + case 1: /*Sub*/ + for(i = 0; i != bytewidth; ++i) out[i] = scanline[i]; + for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - scanline[i - bytewidth]; + break; + case 2: /*Up*/ + if(prevline) + { + for(i = 0; i != length; ++i) out[i] = scanline[i] - prevline[i]; + } + else + { + for(i = 0; i != length; ++i) out[i] = scanline[i]; + } + break; + case 3: /*Average*/ + if(prevline) + { + for(i = 0; i != bytewidth; ++i) out[i] = scanline[i] - (prevline[i] >> 1); + for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - ((scanline[i - bytewidth] + prevline[i]) >> 1); + } + else + { + for(i = 0; i != bytewidth; ++i) out[i] = scanline[i]; + for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - (scanline[i - bytewidth] >> 1); + } + break; + case 4: /*Paeth*/ + if(prevline) + { + /*paethPredictor(0, prevline[i], 0) is always prevline[i]*/ + for(i = 0; i != bytewidth; ++i) out[i] = (scanline[i] - prevline[i]); + for(i = bytewidth; i < length; ++i) + { + out[i] = (scanline[i] - paethPredictor(scanline[i - bytewidth], prevline[i], prevline[i - bytewidth])); + } + } + else + { + for(i = 0; i != bytewidth; ++i) out[i] = scanline[i]; + /*paethPredictor(scanline[i - bytewidth], 0, 0) is always scanline[i - bytewidth]*/ + for(i = bytewidth; i < length; ++i) out[i] = (scanline[i] - scanline[i - bytewidth]); + } + break; + default: return; /*unexisting filter type given*/ + } +} + +/* log2 approximation. A slight bit faster than std::log. */ +static float flog2(float f) +{ + float result = 0; + while(f > 32) { result += 4; f /= 16; } + while(f > 2) { ++result; f /= 2; } + return result + 1.442695f * (f * f * f / 3 - 3 * f * f / 2 + 3 * f - 1.83333f); +} + +static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, + const LodePNGColorMode* info, const LodePNGEncoderSettings* settings) +{ + /* + For PNG filter method 0 + out must be a buffer with as size: h + (w * h * bpp + 7) / 8, because there are + the scanlines with 1 extra byte per scanline + */ + + unsigned bpp = lodepng_get_bpp(info); + /*the width of a scanline in bytes, not including the filter type*/ + size_t linebytes = (w * bpp + 7) / 8; + /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ + size_t bytewidth = (bpp + 7) / 8; + const unsigned char* prevline = 0; + unsigned x, y; + unsigned error = 0; + LodePNGFilterStrategy strategy = settings->filter_strategy; + + /* + There is a heuristic called the minimum sum of absolute differences heuristic, suggested by the PNG standard: + * If the image type is Palette, or the bit depth is smaller than 8, then do not filter the image (i.e. + use fixed filtering, with the filter None). + * (The other case) If the image type is Grayscale or RGB (with or without Alpha), and the bit depth is + not smaller than 8, then use adaptive filtering heuristic as follows: independently for each row, apply + all five filters and select the filter that produces the smallest sum of absolute values per row. + This heuristic is used if filter strategy is LFS_MINSUM and filter_palette_zero is true. + + If filter_palette_zero is true and filter_strategy is not LFS_MINSUM, the above heuristic is followed, + but for "the other case", whatever strategy filter_strategy is set to instead of the minimum sum + heuristic is used. + */ + if(settings->filter_palette_zero && + (info->colortype == LCT_PALETTE || info->bitdepth < 8)) strategy = LFS_ZERO; + + if(bpp == 0) return 31; /*error: invalid color type*/ + + if(strategy == LFS_ZERO) + { + for(y = 0; y != h; ++y) + { + size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + size_t inindex = linebytes * y; + out[outindex] = 0; /*filter type byte*/ + filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, 0); + prevline = &in[inindex]; + } + } + else if(strategy == LFS_MINSUM) + { + /*adaptive filtering*/ + size_t sum[5]; + unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/ + size_t smallest = 0; + unsigned char type, bestType = 0; + + for(type = 0; type != 5; ++type) + { + attempt[type] = (unsigned char*)lodepng_malloc(linebytes); + if(!attempt[type]) return 83; /*alloc fail*/ + } + + if(!error) + { + for(y = 0; y != h; ++y) + { + /*try the 5 filter types*/ + for(type = 0; type != 5; ++type) + { + filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type); + + /*calculate the sum of the result*/ + sum[type] = 0; + if(type == 0) + { + for(x = 0; x != linebytes; ++x) sum[type] += (unsigned char)(attempt[type][x]); + } + else + { + for(x = 0; x != linebytes; ++x) + { + /*For differences, each byte should be treated as signed, values above 127 are negative + (converted to signed char). Filtertype 0 isn't a difference though, so use unsigned there. + This means filtertype 0 is almost never chosen, but that is justified.*/ + unsigned char s = attempt[type][x]; + sum[type] += s < 128 ? s : (255U - s); + } + } + + /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/ + if(type == 0 || sum[type] < smallest) + { + bestType = type; + smallest = sum[type]; + } + } + + prevline = &in[y * linebytes]; + + /*now fill the out values*/ + out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ + for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType][x]; + } + } + + for(type = 0; type != 5; ++type) lodepng_free(attempt[type]); + } + else if(strategy == LFS_ENTROPY) + { + float sum[5]; + unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/ + float smallest = 0; + unsigned type, bestType = 0; + unsigned count[256]; + + for(type = 0; type != 5; ++type) + { + attempt[type] = (unsigned char*)lodepng_malloc(linebytes); + if(!attempt[type]) return 83; /*alloc fail*/ + } + + for(y = 0; y != h; ++y) + { + /*try the 5 filter types*/ + for(type = 0; type != 5; ++type) + { + filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type); + for(x = 0; x != 256; ++x) count[x] = 0; + for(x = 0; x != linebytes; ++x) ++count[attempt[type][x]]; + ++count[type]; /*the filter type itself is part of the scanline*/ + sum[type] = 0; + for(x = 0; x != 256; ++x) + { + float p = count[x] / (float)(linebytes + 1); + sum[type] += count[x] == 0 ? 0 : flog2(1 / p) * p; + } + /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/ + if(type == 0 || sum[type] < smallest) + { + bestType = type; + smallest = sum[type]; + } + } + + prevline = &in[y * linebytes]; + + /*now fill the out values*/ + out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ + for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType][x]; + } + + for(type = 0; type != 5; ++type) lodepng_free(attempt[type]); + } + else if(strategy == LFS_PREDEFINED) + { + for(y = 0; y != h; ++y) + { + size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + size_t inindex = linebytes * y; + unsigned char type = settings->predefined_filters[y]; + out[outindex] = type; /*filter type byte*/ + filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, type); + prevline = &in[inindex]; + } + } + else if(strategy == LFS_BRUTE_FORCE) + { + /*brute force filter chooser. + deflate the scanline after every filter attempt to see which one deflates best. + This is very slow and gives only slightly smaller, sometimes even larger, result*/ + size_t size[5]; + unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/ + size_t smallest = 0; + unsigned type = 0, bestType = 0; + unsigned char* dummy; + LodePNGCompressSettings zlibsettings = settings->zlibsettings; + /*use fixed tree on the attempts so that the tree is not adapted to the filtertype on purpose, + to simulate the true case where the tree is the same for the whole image. Sometimes it gives + better result with dynamic tree anyway. Using the fixed tree sometimes gives worse, but in rare + cases better compression. It does make this a bit less slow, so it's worth doing this.*/ + zlibsettings.btype = 1; + /*a custom encoder likely doesn't read the btype setting and is optimized for complete PNG + images only, so disable it*/ + zlibsettings.custom_zlib = 0; + zlibsettings.custom_deflate = 0; + for(type = 0; type != 5; ++type) + { + attempt[type] = (unsigned char*)lodepng_malloc(linebytes); + if(!attempt[type]) return 83; /*alloc fail*/ + } + for(y = 0; y != h; ++y) /*try the 5 filter types*/ + { + for(type = 0; type != 5; ++type) + { + unsigned testsize = linebytes; + /*if(testsize > 8) testsize /= 8;*/ /*it already works good enough by testing a part of the row*/ + + filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type); + size[type] = 0; + dummy = 0; + zlib_compress(&dummy, &size[type], attempt[type], testsize, &zlibsettings); + lodepng_free(dummy); + /*check if this is smallest size (or if type == 0 it's the first case so always store the values)*/ + if(type == 0 || size[type] < smallest) + { + bestType = type; + smallest = size[type]; + } + } + prevline = &in[y * linebytes]; + out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ + for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType][x]; + } + for(type = 0; type != 5; ++type) lodepng_free(attempt[type]); + } + else return 88; /* unknown filter strategy */ + + return error; +} + +static void addPaddingBits(unsigned char* out, const unsigned char* in, + size_t olinebits, size_t ilinebits, unsigned h) +{ + /*The opposite of the removePaddingBits function + olinebits must be >= ilinebits*/ + unsigned y; + size_t diff = olinebits - ilinebits; + size_t obp = 0, ibp = 0; /*bit pointers*/ + for(y = 0; y != h; ++y) + { + size_t x; + for(x = 0; x < ilinebits; ++x) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + /*obp += diff; --> no, fill in some value in the padding bits too, to avoid + "Use of uninitialised value of size ###" warning from valgrind*/ + for(x = 0; x != diff; ++x) setBitOfReversedStream(&obp, out, 0); + } +} + +/* +in: non-interlaced image with size w*h +out: the same pixels, but re-ordered according to PNG's Adam7 interlacing, with + no padding bits between scanlines, but between reduced images so that each + reduced image starts at a byte. +bpp: bits per pixel +there are no padding bits, not between scanlines, not between reduced images +in has the following size in bits: w * h * bpp. +out is possibly bigger due to padding bits between reduced images +NOTE: comments about padding bits are only relevant if bpp < 8 +*/ +static void Adam7_interlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) +{ + unsigned passw[7], passh[7]; + size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + if(bpp >= 8) + { + for(i = 0; i != 7; ++i) + { + unsigned x, y, b; + size_t bytewidth = bpp / 8; + for(y = 0; y < passh[i]; ++y) + for(x = 0; x < passw[i]; ++x) + { + size_t pixelinstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth; + size_t pixeloutstart = passstart[i] + (y * passw[i] + x) * bytewidth; + for(b = 0; b < bytewidth; ++b) + { + out[pixeloutstart + b] = in[pixelinstart + b]; + } + } + } + } + else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ + { + for(i = 0; i != 7; ++i) + { + unsigned x, y, b; + unsigned ilinebits = bpp * passw[i]; + unsigned olinebits = bpp * w; + size_t obp, ibp; /*bit pointers (for out and in buffer)*/ + for(y = 0; y < passh[i]; ++y) + for(x = 0; x < passw[i]; ++x) + { + ibp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp; + obp = (8 * passstart[i]) + (y * ilinebits + x * bpp); + for(b = 0; b < bpp; ++b) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + } + } + } +} + +/*out must be buffer big enough to contain uncompressed IDAT chunk data, and in must contain the full image. +return value is error**/ +static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const unsigned char* in, + unsigned w, unsigned h, + const LodePNGInfo* info_png, const LodePNGEncoderSettings* settings) +{ + /* + This function converts the pure 2D image with the PNG's colortype, into filtered-padded-interlaced data. Steps: + *) if no Adam7: 1) add padding bits (= posible extra bits per scanline if bpp < 8) 2) filter + *) if adam7: 1) Adam7_interlace 2) 7x add padding bits 3) 7x filter + */ + unsigned bpp = lodepng_get_bpp(&info_png->color); + unsigned error = 0; + + if(info_png->interlace_method == 0) + { + *outsize = h + (h * ((w * bpp + 7) / 8)); /*image size plus an extra byte per scanline + possible padding bits*/ + *out = (unsigned char*)lodepng_malloc(*outsize); + if(!(*out) && (*outsize)) error = 83; /*alloc fail*/ + + if(!error) + { + /*non multiple of 8 bits per scanline, padding bits needed per scanline*/ + if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8) + { + unsigned char* padded = (unsigned char*)lodepng_malloc(h * ((w * bpp + 7) / 8)); + if(!padded) error = 83; /*alloc fail*/ + if(!error) + { + addPaddingBits(padded, in, ((w * bpp + 7) / 8) * 8, w * bpp, h); + error = filter(*out, padded, w, h, &info_png->color, settings); + } + lodepng_free(padded); + } + else + { + /*we can immediately filter into the out buffer, no other steps needed*/ + error = filter(*out, in, w, h, &info_png->color, settings); + } + } + } + else /*interlace_method is 1 (Adam7)*/ + { + unsigned passw[7], passh[7]; + size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned char* adam7; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + *outsize = filter_passstart[7]; /*image size plus an extra byte per scanline + possible padding bits*/ + *out = (unsigned char*)lodepng_malloc(*outsize); + if(!(*out)) error = 83; /*alloc fail*/ + + adam7 = (unsigned char*)lodepng_malloc(passstart[7]); + if(!adam7 && passstart[7]) error = 83; /*alloc fail*/ + + if(!error) + { + unsigned i; + + Adam7_interlace(adam7, in, w, h, bpp); + for(i = 0; i != 7; ++i) + { + if(bpp < 8) + { + unsigned char* padded = (unsigned char*)lodepng_malloc(padded_passstart[i + 1] - padded_passstart[i]); + if(!padded) ERROR_BREAK(83); /*alloc fail*/ + addPaddingBits(padded, &adam7[passstart[i]], + ((passw[i] * bpp + 7) / 8) * 8, passw[i] * bpp, passh[i]); + error = filter(&(*out)[filter_passstart[i]], padded, + passw[i], passh[i], &info_png->color, settings); + lodepng_free(padded); + } + else + { + error = filter(&(*out)[filter_passstart[i]], &adam7[padded_passstart[i]], + passw[i], passh[i], &info_png->color, settings); + } + + if(error) break; + } + } + + lodepng_free(adam7); + } + + return error; +} + +/* +palette must have 4 * palettesize bytes allocated, and given in format RGBARGBARGBARGBA... +returns 0 if the palette is opaque, +returns 1 if the palette has a single color with alpha 0 ==> color key +returns 2 if the palette is semi-translucent. +*/ +static unsigned getPaletteTranslucency(const unsigned char* palette, size_t palettesize) +{ + size_t i; + unsigned key = 0; + unsigned r = 0, g = 0, b = 0; /*the value of the color with alpha 0, so long as color keying is possible*/ + for(i = 0; i != palettesize; ++i) + { + if(!key && palette[4 * i + 3] == 0) + { + r = palette[4 * i + 0]; g = palette[4 * i + 1]; b = palette[4 * i + 2]; + key = 1; + i = (size_t)(-1); /*restart from beginning, to detect earlier opaque colors with key's value*/ + } + else if(palette[4 * i + 3] != 255) return 2; + /*when key, no opaque RGB may have key's RGB*/ + else if(key && r == palette[i * 4 + 0] && g == palette[i * 4 + 1] && b == palette[i * 4 + 2]) return 2; + } + return key; +} + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +static unsigned addUnknownChunks(ucvector* out, unsigned char* data, size_t datasize) +{ + unsigned char* inchunk = data; + while((size_t)(inchunk - data) < datasize) + { + CERROR_TRY_RETURN(lodepng_chunk_append(&out->data, &out->size, inchunk)); + out->allocsize = out->size; /*fix the allocsize again*/ + inchunk = lodepng_chunk_next(inchunk); + } + return 0; +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +unsigned lodepng_encode(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h, + LodePNGState* state) +{ + LodePNGInfo info; + ucvector outv; + unsigned char* data = 0; /*uncompressed version of the IDAT chunk data*/ + size_t datasize = 0; + + /*provide some proper output values if error will happen*/ + *out = 0; + *outsize = 0; + state->error = 0; + + lodepng_info_init(&info); + lodepng_info_copy(&info, &state->info_png); + + if((info.color.colortype == LCT_PALETTE || state->encoder.force_palette) + && (info.color.palettesize == 0 || info.color.palettesize > 256)) + { + state->error = 68; /*invalid palette size, it is only allowed to be 1-256*/ + return state->error; + } + + if(state->encoder.auto_convert) + { + state->error = lodepng_auto_choose_color(&info.color, image, w, h, &state->info_raw); + } + if(state->error) return state->error; + + if(state->encoder.zlibsettings.btype > 2) + { + CERROR_RETURN_ERROR(state->error, 61); /*error: unexisting btype*/ + } + if(state->info_png.interlace_method > 1) + { + CERROR_RETURN_ERROR(state->error, 71); /*error: unexisting interlace mode*/ + } + + state->error = checkColorValidity(info.color.colortype, info.color.bitdepth); + if(state->error) return state->error; /*error: unexisting color type given*/ + state->error = checkColorValidity(state->info_raw.colortype, state->info_raw.bitdepth); + if(state->error) return state->error; /*error: unexisting color type given*/ + + if(!lodepng_color_mode_equal(&state->info_raw, &info.color)) + { + unsigned char* converted; + size_t size = (w * h * (size_t)lodepng_get_bpp(&info.color) + 7) / 8; + + converted = (unsigned char*)lodepng_malloc(size); + if(!converted && size) state->error = 83; /*alloc fail*/ + if(!state->error) + { + state->error = lodepng_convert(converted, image, &info.color, &state->info_raw, w, h); + } + if(!state->error) preProcessScanlines(&data, &datasize, converted, w, h, &info, &state->encoder); + lodepng_free(converted); + } + else preProcessScanlines(&data, &datasize, image, w, h, &info, &state->encoder); + + ucvector_init(&outv); + while(!state->error) /*while only executed once, to break on error*/ + { +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + size_t i; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + /*write signature and chunks*/ + writeSignature(&outv); + /*IHDR*/ + addChunk_IHDR(&outv, w, h, info.color.colortype, info.color.bitdepth, info.interlace_method); +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*unknown chunks between IHDR and PLTE*/ + if(info.unknown_chunks_data[0]) + { + state->error = addUnknownChunks(&outv, info.unknown_chunks_data[0], info.unknown_chunks_size[0]); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + /*PLTE*/ + if(info.color.colortype == LCT_PALETTE) + { + addChunk_PLTE(&outv, &info.color); + } + if(state->encoder.force_palette && (info.color.colortype == LCT_RGB || info.color.colortype == LCT_RGBA)) + { + addChunk_PLTE(&outv, &info.color); + } + /*tRNS*/ + if(info.color.colortype == LCT_PALETTE && getPaletteTranslucency(info.color.palette, info.color.palettesize) != 0) + { + addChunk_tRNS(&outv, &info.color); + } + if((info.color.colortype == LCT_GREY || info.color.colortype == LCT_RGB) && info.color.key_defined) + { + addChunk_tRNS(&outv, &info.color); + } +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*bKGD (must come between PLTE and the IDAt chunks*/ + if(info.background_defined) addChunk_bKGD(&outv, &info); + /*pHYs (must come before the IDAT chunks)*/ + if(info.phys_defined) addChunk_pHYs(&outv, &info); + + /*unknown chunks between PLTE and IDAT*/ + if(info.unknown_chunks_data[1]) + { + state->error = addUnknownChunks(&outv, info.unknown_chunks_data[1], info.unknown_chunks_size[1]); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + /*IDAT (multiple IDAT chunks must be consecutive)*/ + state->error = addChunk_IDAT(&outv, data, datasize, &state->encoder.zlibsettings); + if(state->error) break; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*tIME*/ + if(info.time_defined) addChunk_tIME(&outv, &info.time); + /*tEXt and/or zTXt*/ + for(i = 0; i != info.text_num; ++i) + { + if(strlen(info.text_keys[i]) > 79) + { + state->error = 66; /*text chunk too large*/ + break; + } + if(strlen(info.text_keys[i]) < 1) + { + state->error = 67; /*text chunk too small*/ + break; + } + if(state->encoder.text_compression) + { + addChunk_zTXt(&outv, info.text_keys[i], info.text_strings[i], &state->encoder.zlibsettings); + } + else + { + addChunk_tEXt(&outv, info.text_keys[i], info.text_strings[i]); + } + } + /*LodePNG version id in text chunk*/ + if(state->encoder.add_id) + { + unsigned alread_added_id_text = 0; + for(i = 0; i != info.text_num; ++i) + { + if(!strcmp(info.text_keys[i], "LodePNG")) + { + alread_added_id_text = 1; + break; + } + } + if(alread_added_id_text == 0) + { + addChunk_tEXt(&outv, "LodePNG", LODEPNG_VERSION_STRING); /*it's shorter as tEXt than as zTXt chunk*/ + } + } + /*iTXt*/ + for(i = 0; i != info.itext_num; ++i) + { + if(strlen(info.itext_keys[i]) > 79) + { + state->error = 66; /*text chunk too large*/ + break; + } + if(strlen(info.itext_keys[i]) < 1) + { + state->error = 67; /*text chunk too small*/ + break; + } + addChunk_iTXt(&outv, state->encoder.text_compression, + info.itext_keys[i], info.itext_langtags[i], info.itext_transkeys[i], info.itext_strings[i], + &state->encoder.zlibsettings); + } + + /*unknown chunks between IDAT and IEND*/ + if(info.unknown_chunks_data[2]) + { + state->error = addUnknownChunks(&outv, info.unknown_chunks_data[2], info.unknown_chunks_size[2]); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + addChunk_IEND(&outv); + + break; /*this isn't really a while loop; no error happened so break out now!*/ + } + + lodepng_info_cleanup(&info); + lodepng_free(data); + /*instead of cleaning the vector up, give it to the output*/ + *out = outv.data; + *outsize = outv.size; + + return state->error; +} + +unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, const unsigned char* image, + unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned error; + LodePNGState state; + lodepng_state_init(&state); + state.info_raw.colortype = colortype; + state.info_raw.bitdepth = bitdepth; + state.info_png.color.colortype = colortype; + state.info_png.color.bitdepth = bitdepth; + lodepng_encode(out, outsize, image, w, h, &state); + error = state.error; + lodepng_state_cleanup(&state); + return error; +} + +unsigned lodepng_encode32(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) +{ + return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGBA, 8); +} + +unsigned lodepng_encode24(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) +{ + return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGB, 8); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned lodepng_encode_file(const char* filename, const unsigned char* image, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned char* buffer; + size_t buffersize; + unsigned error = lodepng_encode_memory(&buffer, &buffersize, image, w, h, colortype, bitdepth); + if(!error) error = lodepng_save_file(buffer, buffersize, filename); + lodepng_free(buffer); + return error; +} + +unsigned lodepng_encode32_file(const char* filename, const unsigned char* image, unsigned w, unsigned h) +{ + return lodepng_encode_file(filename, image, w, h, LCT_RGBA, 8); +} + +unsigned lodepng_encode24_file(const char* filename, const unsigned char* image, unsigned w, unsigned h) +{ + return lodepng_encode_file(filename, image, w, h, LCT_RGB, 8); +} +#endif /*LODEPNG_COMPILE_DISK*/ + +void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings) +{ + lodepng_compress_settings_init(&settings->zlibsettings); + settings->filter_palette_zero = 1; + settings->filter_strategy = LFS_MINSUM; + settings->auto_convert = 1; + settings->force_palette = 0; + settings->predefined_filters = 0; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + settings->add_id = 0; + settings->text_compression = 1; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} + +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ERROR_TEXT +/* +This returns the description of a numerical error code in English. This is also +the documentation of all the error codes. +*/ +const char* lodepng_error_text(unsigned code) +{ + switch(code) + { + case 0: return "no error, everything went ok"; + case 1: return "nothing done yet"; /*the Encoder/Decoder has done nothing yet, error checking makes no sense yet*/ + case 10: return "end of input memory reached without huffman end code"; /*while huffman decoding*/ + case 11: return "error in code tree made it jump outside of huffman tree"; /*while huffman decoding*/ + case 13: return "problem while processing dynamic deflate block"; + case 14: return "problem while processing dynamic deflate block"; + case 15: return "problem while processing dynamic deflate block"; + case 16: return "unexisting code while processing dynamic deflate block"; + case 17: return "end of out buffer memory reached while inflating"; + case 18: return "invalid distance code while inflating"; + case 19: return "end of out buffer memory reached while inflating"; + case 20: return "invalid deflate block BTYPE encountered while decoding"; + case 21: return "NLEN is not ones complement of LEN in a deflate block"; + /*end of out buffer memory reached while inflating: + This can happen if the inflated deflate data is longer than the amount of bytes required to fill up + all the pixels of the image, given the color depth and image dimensions. Something that doesn't + happen in a normal, well encoded, PNG image.*/ + case 22: return "end of out buffer memory reached while inflating"; + case 23: return "end of in buffer memory reached while inflating"; + case 24: return "invalid FCHECK in zlib header"; + case 25: return "invalid compression method in zlib header"; + case 26: return "FDICT encountered in zlib header while it's not used for PNG"; + case 27: return "PNG file is smaller than a PNG header"; + /*Checks the magic file header, the first 8 bytes of the PNG file*/ + case 28: return "incorrect PNG signature, it's no PNG or corrupted"; + case 29: return "first chunk is not the header chunk"; + case 30: return "chunk length too large, chunk broken off at end of file"; + case 31: return "illegal PNG color type or bpp"; + case 32: return "illegal PNG compression method"; + case 33: return "illegal PNG filter method"; + case 34: return "illegal PNG interlace method"; + case 35: return "chunk length of a chunk is too large or the chunk too small"; + case 36: return "illegal PNG filter type encountered"; + case 37: return "illegal bit depth for this color type given"; + case 38: return "the palette is too big"; /*more than 256 colors*/ + case 39: return "more palette alpha values given in tRNS chunk than there are colors in the palette"; + case 40: return "tRNS chunk has wrong size for greyscale image"; + case 41: return "tRNS chunk has wrong size for RGB image"; + case 42: return "tRNS chunk appeared while it was not allowed for this color type"; + case 43: return "bKGD chunk has wrong size for palette image"; + case 44: return "bKGD chunk has wrong size for greyscale image"; + case 45: return "bKGD chunk has wrong size for RGB image"; + case 48: return "empty input buffer given to decoder. Maybe caused by non-existing file?"; + case 49: return "jumped past memory while generating dynamic huffman tree"; + case 50: return "jumped past memory while generating dynamic huffman tree"; + case 51: return "jumped past memory while inflating huffman block"; + case 52: return "jumped past memory while inflating"; + case 53: return "size of zlib data too small"; + case 54: return "repeat symbol in tree while there was no value symbol yet"; + /*jumped past tree while generating huffman tree, this could be when the + tree will have more leaves than symbols after generating it out of the + given lenghts. They call this an oversubscribed dynamic bit lengths tree in zlib.*/ + case 55: return "jumped past tree while generating huffman tree"; + case 56: return "given output image colortype or bitdepth not supported for color conversion"; + case 57: return "invalid CRC encountered (checking CRC can be disabled)"; + case 58: return "invalid ADLER32 encountered (checking ADLER32 can be disabled)"; + case 59: return "requested color conversion not supported"; + case 60: return "invalid window size given in the settings of the encoder (must be 0-32768)"; + case 61: return "invalid BTYPE given in the settings of the encoder (only 0, 1 and 2 are allowed)"; + /*LodePNG leaves the choice of RGB to greyscale conversion formula to the user.*/ + case 62: return "conversion from color to greyscale not supported"; + case 63: return "length of a chunk too long, max allowed for PNG is 2147483647 bytes per chunk"; /*(2^31-1)*/ + /*this would result in the inability of a deflated block to ever contain an end code. It must be at least 1.*/ + case 64: return "the length of the END symbol 256 in the Huffman tree is 0"; + case 66: return "the length of a text chunk keyword given to the encoder is longer than the maximum of 79 bytes"; + case 67: return "the length of a text chunk keyword given to the encoder is smaller than the minimum of 1 byte"; + case 68: return "tried to encode a PLTE chunk with a palette that has less than 1 or more than 256 colors"; + case 69: return "unknown chunk type with 'critical' flag encountered by the decoder"; + case 71: return "unexisting interlace mode given to encoder (must be 0 or 1)"; + case 72: return "while decoding, unexisting compression method encountering in zTXt or iTXt chunk (it must be 0)"; + case 73: return "invalid tIME chunk size"; + case 74: return "invalid pHYs chunk size"; + /*length could be wrong, or data chopped off*/ + case 75: return "no null termination char found while decoding text chunk"; + case 76: return "iTXt chunk too short to contain required bytes"; + case 77: return "integer overflow in buffer size"; + case 78: return "failed to open file for reading"; /*file doesn't exist or couldn't be opened for reading*/ + case 79: return "failed to open file for writing"; + case 80: return "tried creating a tree of 0 symbols"; + case 81: return "lazy matching at pos 0 is impossible"; + case 82: return "color conversion to palette requested while a color isn't in palette"; + case 83: return "memory allocation failed"; + case 84: return "given image too small to contain all pixels to be encoded"; + case 86: return "impossible offset in lz77 encoding (internal bug)"; + case 87: return "must provide custom zlib function pointer if LODEPNG_COMPILE_ZLIB is not defined"; + case 88: return "invalid filter strategy given for LodePNGEncoderSettings.filter_strategy"; + case 89: return "text chunk keyword too short or long: must have size 1-79"; + /*the windowsize in the LodePNGCompressSettings. Requiring POT(==> & instead of %) makes encoding 12% faster.*/ + case 90: return "windowsize must be a power of two"; + case 91: return "invalid decompressed idat size"; + case 92: return "too many pixels, not supported"; + case 93: return "zero width or height is invalid"; + case 94: return "header chunk must have a size of 13 bytes"; + } + return "unknown error code"; +} +#endif /*LODEPNG_COMPILE_ERROR_TEXT*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // C++ Wrapper // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_CPP +namespace lodepng +{ + +#ifdef LODEPNG_COMPILE_DISK +unsigned load_file(std::vector& buffer, const std::string& filename) +{ + long size = lodepng_filesize(filename.c_str()); + if(size < 0) return 78; + buffer.resize((size_t)size); + return size == 0 ? 0 : lodepng_buffer_file(&buffer[0], (size_t)size, filename.c_str()); +} + +/*write given buffer to the file, overwriting the file, it doesn't append to it.*/ +unsigned save_file(const std::vector& buffer, const std::string& filename) +{ + return lodepng_save_file(buffer.empty() ? 0 : &buffer[0], buffer.size(), filename.c_str()); +} +#endif /* LODEPNG_COMPILE_DISK */ + +#ifdef LODEPNG_COMPILE_ZLIB +#ifdef LODEPNG_COMPILE_DECODER +unsigned decompress(std::vector& out, const unsigned char* in, size_t insize, + const LodePNGDecompressSettings& settings) +{ + unsigned char* buffer = 0; + size_t buffersize = 0; + unsigned error = zlib_decompress(&buffer, &buffersize, in, insize, &settings); + if(buffer) + { + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned decompress(std::vector& out, const std::vector& in, + const LodePNGDecompressSettings& settings) +{ + return decompress(out, in.empty() ? 0 : &in[0], in.size(), settings); +} +#endif /* LODEPNG_COMPILE_DECODER */ + +#ifdef LODEPNG_COMPILE_ENCODER +unsigned compress(std::vector& out, const unsigned char* in, size_t insize, + const LodePNGCompressSettings& settings) +{ + unsigned char* buffer = 0; + size_t buffersize = 0; + unsigned error = zlib_compress(&buffer, &buffersize, in, insize, &settings); + if(buffer) + { + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned compress(std::vector& out, const std::vector& in, + const LodePNGCompressSettings& settings) +{ + return compress(out, in.empty() ? 0 : &in[0], in.size(), settings); +} +#endif /* LODEPNG_COMPILE_ENCODER */ +#endif /* LODEPNG_COMPILE_ZLIB */ + + +#ifdef LODEPNG_COMPILE_PNG + +State::State() +{ + lodepng_state_init(this); +} + +State::State(const State& other) +{ + lodepng_state_init(this); + lodepng_state_copy(this, &other); +} + +State::~State() +{ + lodepng_state_cleanup(this); +} + +State& State::operator=(const State& other) +{ + lodepng_state_copy(this, &other); + return *this; +} + +#ifdef LODEPNG_COMPILE_DECODER + +unsigned decode(std::vector& out, unsigned& w, unsigned& h, const unsigned char* in, + size_t insize, LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned char* buffer; + unsigned error = lodepng_decode_memory(&buffer, &w, &h, in, insize, colortype, bitdepth); + if(buffer && !error) + { + State state; + state.info_raw.colortype = colortype; + state.info_raw.bitdepth = bitdepth; + size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw); + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + const std::vector& in, LodePNGColorType colortype, unsigned bitdepth) +{ + return decode(out, w, h, in.empty() ? 0 : &in[0], (unsigned)in.size(), colortype, bitdepth); +} + +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + State& state, + const unsigned char* in, size_t insize) +{ + unsigned char* buffer = NULL; + unsigned error = lodepng_decode(&buffer, &w, &h, &state, in, insize); + if(buffer && !error) + { + size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw); + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + } + lodepng_free(buffer); + return error; +} + +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + State& state, + const std::vector& in) +{ + return decode(out, w, h, state, in.empty() ? 0 : &in[0], in.size()); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned decode(std::vector& out, unsigned& w, unsigned& h, const std::string& filename, + LodePNGColorType colortype, unsigned bitdepth) +{ + std::vector buffer; + unsigned error = load_file(buffer, filename); + if(error) return error; + return decode(out, w, h, buffer, colortype, bitdepth); +} +#endif /* LODEPNG_COMPILE_DECODER */ +#endif /* LODEPNG_COMPILE_DISK */ + +#ifdef LODEPNG_COMPILE_ENCODER +unsigned encode(std::vector& out, const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned char* buffer; + size_t buffersize; + unsigned error = lodepng_encode_memory(&buffer, &buffersize, in, w, h, colortype, bitdepth); + if(buffer) + { + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned encode(std::vector& out, + const std::vector& in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) +{ + if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84; + return encode(out, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth); +} + +unsigned encode(std::vector& out, + const unsigned char* in, unsigned w, unsigned h, + State& state) +{ + unsigned char* buffer; + size_t buffersize; + unsigned error = lodepng_encode(&buffer, &buffersize, in, w, h, &state); + if(buffer) + { + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned encode(std::vector& out, + const std::vector& in, unsigned w, unsigned h, + State& state) +{ + if(lodepng_get_raw_size(w, h, &state.info_raw) > in.size()) return 84; + return encode(out, in.empty() ? 0 : &in[0], w, h, state); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned encode(const std::string& filename, + const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) +{ + std::vector buffer; + unsigned error = encode(buffer, in, w, h, colortype, bitdepth); + if(!error) error = save_file(buffer, filename); + return error; +} + +unsigned encode(const std::string& filename, + const std::vector& in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) +{ + if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84; + return encode(filename, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth); +} +#endif /* LODEPNG_COMPILE_DISK */ +#endif /* LODEPNG_COMPILE_ENCODER */ +#endif /* LODEPNG_COMPILE_PNG */ +} /* namespace lodepng */ +#endif /*LODEPNG_COMPILE_CPP*/ diff --git a/src/lodepng.h b/src/lodepng.h new file mode 100755 index 00000000..fcf9f714 --- /dev/null +++ b/src/lodepng.h @@ -0,0 +1,1760 @@ +/* +LodePNG version 20160501 + +Copyright (c) 2005-2016 Lode Vandevenne + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +#ifndef LODEPNG_H +#define LODEPNG_H + +#include /*for size_t*/ + +extern const char* LODEPNG_VERSION_STRING; + +/* +The following #defines are used to create code sections. They can be disabled +to disable code sections, which can give faster compile time and smaller binary. +The "NO_COMPILE" defines are designed to be used to pass as defines to the +compiler command to disable them without modifying this header, e.g. +-DLODEPNG_NO_COMPILE_ZLIB for gcc. +In addition to those below, you can also define LODEPNG_NO_COMPILE_CRC to +allow implementing a custom lodepng_crc32. +*/ +/*deflate & zlib. If disabled, you must specify alternative zlib functions in +the custom_zlib field of the compress and decompress settings*/ +#ifndef LODEPNG_NO_COMPILE_ZLIB +#define LODEPNG_COMPILE_ZLIB +#endif +/*png encoder and png decoder*/ +#ifndef LODEPNG_NO_COMPILE_PNG +#define LODEPNG_COMPILE_PNG +#endif +/*deflate&zlib decoder and png decoder*/ +#ifndef LODEPNG_NO_COMPILE_DECODER +#define LODEPNG_COMPILE_DECODER +#endif +/*deflate&zlib encoder and png encoder*/ +#ifndef LODEPNG_NO_COMPILE_ENCODER +#define LODEPNG_COMPILE_ENCODER +#endif +/*the optional built in harddisk file loading and saving functions*/ +#ifndef LODEPNG_NO_COMPILE_DISK +#define LODEPNG_COMPILE_DISK +#endif +/*support for chunks other than IHDR, IDAT, PLTE, tRNS, IEND: ancillary and unknown chunks*/ +#ifndef LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS +#define LODEPNG_COMPILE_ANCILLARY_CHUNKS +#endif +/*ability to convert error numerical codes to English text string*/ +#ifndef LODEPNG_NO_COMPILE_ERROR_TEXT +#define LODEPNG_COMPILE_ERROR_TEXT +#endif +/*Compile the default allocators (C's free, malloc and realloc). If you disable this, +you can define the functions lodepng_free, lodepng_malloc and lodepng_realloc in your +source files with custom allocators.*/ +#ifndef LODEPNG_NO_COMPILE_ALLOCATORS +#define LODEPNG_COMPILE_ALLOCATORS +#endif +/*compile the C++ version (you can disable the C++ wrapper here even when compiling for C++)*/ +#ifdef __cplusplus +#ifndef LODEPNG_NO_COMPILE_CPP +#define LODEPNG_COMPILE_CPP +#endif +#endif + +#ifdef LODEPNG_COMPILE_CPP +#include +#include +#endif /*LODEPNG_COMPILE_CPP*/ + +#ifdef LODEPNG_COMPILE_PNG +/*The PNG color types (also used for raw).*/ +typedef enum LodePNGColorType +{ + LCT_GREY = 0, /*greyscale: 1,2,4,8,16 bit*/ + LCT_RGB = 2, /*RGB: 8,16 bit*/ + LCT_PALETTE = 3, /*palette: 1,2,4,8 bit*/ + LCT_GREY_ALPHA = 4, /*greyscale with alpha: 8,16 bit*/ + LCT_RGBA = 6 /*RGB with alpha: 8,16 bit*/ +} LodePNGColorType; + +#ifdef LODEPNG_COMPILE_DECODER +/* +Converts PNG data in memory to raw pixel data. +out: Output parameter. Pointer to buffer that will contain the raw pixel data. + After decoding, its size is w * h * (bytes per pixel) bytes larger than + initially. Bytes per pixel depends on colortype and bitdepth. + Must be freed after usage with free(*out). + Note: for 16-bit per channel colors, uses big endian format like PNG does. +w: Output parameter. Pointer to width of pixel data. +h: Output parameter. Pointer to height of pixel data. +in: Memory buffer with the PNG file. +insize: size of the in buffer. +colortype: the desired color type for the raw output image. See explanation on PNG color types. +bitdepth: the desired bit depth for the raw output image. See explanation on PNG color types. +Return value: LodePNG error code (0 means no error). +*/ +unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, + const unsigned char* in, size_t insize, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_decode_memory, but always decodes to 32-bit RGBA raw image*/ +unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, + const unsigned char* in, size_t insize); + +/*Same as lodepng_decode_memory, but always decodes to 24-bit RGB raw image*/ +unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, + const unsigned char* in, size_t insize); + +#ifdef LODEPNG_COMPILE_DISK +/* +Load PNG from disk, from file with given name. +Same as the other decode functions, but instead takes a filename as input. +*/ +unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, + const char* filename, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_decode_file, but always decodes to 32-bit RGBA raw image.*/ +unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, + const char* filename); + +/*Same as lodepng_decode_file, but always decodes to 24-bit RGB raw image.*/ +unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, + const char* filename); +#endif /*LODEPNG_COMPILE_DISK*/ +#endif /*LODEPNG_COMPILE_DECODER*/ + + +#ifdef LODEPNG_COMPILE_ENCODER +/* +Converts raw pixel data into a PNG image in memory. The colortype and bitdepth + of the output PNG image cannot be chosen, they are automatically determined + by the colortype, bitdepth and content of the input pixel data. + Note: for 16-bit per channel colors, needs big endian format like PNG does. +out: Output parameter. Pointer to buffer that will contain the PNG image data. + Must be freed after usage with free(*out). +outsize: Output parameter. Pointer to the size in bytes of the out buffer. +image: The raw pixel data to encode. The size of this buffer should be + w * h * (bytes per pixel), bytes per pixel depends on colortype and bitdepth. +w: width of the raw pixel data in pixels. +h: height of the raw pixel data in pixels. +colortype: the color type of the raw input image. See explanation on PNG color types. +bitdepth: the bit depth of the raw input image. See explanation on PNG color types. +Return value: LodePNG error code (0 means no error). +*/ +unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_encode_memory, but always encodes from 32-bit RGBA raw image.*/ +unsigned lodepng_encode32(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h); + +/*Same as lodepng_encode_memory, but always encodes from 24-bit RGB raw image.*/ +unsigned lodepng_encode24(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h); + +#ifdef LODEPNG_COMPILE_DISK +/* +Converts raw pixel data into a PNG file on disk. +Same as the other encode functions, but instead takes a filename as output. +NOTE: This overwrites existing files without warning! +*/ +unsigned lodepng_encode_file(const char* filename, + const unsigned char* image, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_encode_file, but always encodes from 32-bit RGBA raw image.*/ +unsigned lodepng_encode32_file(const char* filename, + const unsigned char* image, unsigned w, unsigned h); + +/*Same as lodepng_encode_file, but always encodes from 24-bit RGB raw image.*/ +unsigned lodepng_encode24_file(const char* filename, + const unsigned char* image, unsigned w, unsigned h); +#endif /*LODEPNG_COMPILE_DISK*/ +#endif /*LODEPNG_COMPILE_ENCODER*/ + + +#ifdef LODEPNG_COMPILE_CPP +namespace lodepng +{ +#ifdef LODEPNG_COMPILE_DECODER +/*Same as lodepng_decode_memory, but decodes to an std::vector. The colortype +is the format to output the pixels to. Default is RGBA 8-bit per channel.*/ +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + const unsigned char* in, size_t insize, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + const std::vector& in, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#ifdef LODEPNG_COMPILE_DISK +/* +Converts PNG file from disk to raw pixel data in memory. +Same as the other decode functions, but instead takes a filename as input. +*/ +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + const std::string& filename, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#endif /* LODEPNG_COMPILE_DISK */ +#endif /* LODEPNG_COMPILE_DECODER */ + +#ifdef LODEPNG_COMPILE_ENCODER +/*Same as lodepng_encode_memory, but encodes to an std::vector. colortype +is that of the raw input data. The output PNG color type will be auto chosen.*/ +unsigned encode(std::vector& out, + const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +unsigned encode(std::vector& out, + const std::vector& in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#ifdef LODEPNG_COMPILE_DISK +/* +Converts 32-bit RGBA raw pixel data into a PNG file on disk. +Same as the other encode functions, but instead takes a filename as output. +NOTE: This overwrites existing files without warning! +*/ +unsigned encode(const std::string& filename, + const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +unsigned encode(const std::string& filename, + const std::vector& in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#endif /* LODEPNG_COMPILE_DISK */ +#endif /* LODEPNG_COMPILE_ENCODER */ +} /* namespace lodepng */ +#endif /*LODEPNG_COMPILE_CPP*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ERROR_TEXT +/*Returns an English description of the numerical error code.*/ +const char* lodepng_error_text(unsigned code); +#endif /*LODEPNG_COMPILE_ERROR_TEXT*/ + +#ifdef LODEPNG_COMPILE_DECODER +/*Settings for zlib decompression*/ +typedef struct LodePNGDecompressSettings LodePNGDecompressSettings; +struct LodePNGDecompressSettings +{ + unsigned ignore_adler32; /*if 1, continue and don't give an error message if the Adler32 checksum is corrupted*/ + + /*use custom zlib decoder instead of built in one (default: null)*/ + unsigned (*custom_zlib)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGDecompressSettings*); + /*use custom deflate decoder instead of built in one (default: null) + if custom_zlib is used, custom_deflate is ignored since only the built in + zlib function will call custom_deflate*/ + unsigned (*custom_inflate)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGDecompressSettings*); + + const void* custom_context; /*optional custom settings for custom functions*/ +}; + +extern const LodePNGDecompressSettings lodepng_default_decompress_settings; +void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/* +Settings for zlib compression. Tweaking these settings tweaks the balance +between speed and compression ratio. +*/ +typedef struct LodePNGCompressSettings LodePNGCompressSettings; +struct LodePNGCompressSettings /*deflate = compress*/ +{ + /*LZ77 related settings*/ + unsigned btype; /*the block type for LZ (0, 1, 2 or 3, see zlib standard). Should be 2 for proper compression.*/ + unsigned use_lz77; /*whether or not to use LZ77. Should be 1 for proper compression.*/ + unsigned windowsize; /*must be a power of two <= 32768. higher compresses more but is slower. Default value: 2048.*/ + unsigned minmatch; /*mininum lz77 length. 3 is normally best, 6 can be better for some PNGs. Default: 0*/ + unsigned nicematch; /*stop searching if >= this length found. Set to 258 for best compression. Default: 128*/ + unsigned lazymatching; /*use lazy matching: better compression but a bit slower. Default: true*/ + + /*use custom zlib encoder instead of built in one (default: null)*/ + unsigned (*custom_zlib)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGCompressSettings*); + /*use custom deflate encoder instead of built in one (default: null) + if custom_zlib is used, custom_deflate is ignored since only the built in + zlib function will call custom_deflate*/ + unsigned (*custom_deflate)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGCompressSettings*); + + const void* custom_context; /*optional custom settings for custom functions*/ +}; + +extern const LodePNGCompressSettings lodepng_default_compress_settings; +void lodepng_compress_settings_init(LodePNGCompressSettings* settings); +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_PNG +/* +Color mode of an image. Contains all information required to decode the pixel +bits to RGBA colors. This information is the same as used in the PNG file +format, and is used both for PNG and raw image data in LodePNG. +*/ +typedef struct LodePNGColorMode +{ + /*header (IHDR)*/ + LodePNGColorType colortype; /*color type, see PNG standard or documentation further in this header file*/ + unsigned bitdepth; /*bits per sample, see PNG standard or documentation further in this header file*/ + + /* + palette (PLTE and tRNS) + + Dynamically allocated with the colors of the palette, including alpha. + When encoding a PNG, to store your colors in the palette of the LodePNGColorMode, first use + lodepng_palette_clear, then for each color use lodepng_palette_add. + If you encode an image without alpha with palette, don't forget to put value 255 in each A byte of the palette. + + When decoding, by default you can ignore this palette, since LodePNG already + fills the palette colors in the pixels of the raw RGBA output. + + The palette is only supported for color type 3. + */ + unsigned char* palette; /*palette in RGBARGBA... order. When allocated, must be either 0, or have size 1024*/ + size_t palettesize; /*palette size in number of colors (amount of bytes is 4 * palettesize)*/ + + /* + transparent color key (tRNS) + + This color uses the same bit depth as the bitdepth value in this struct, which can be 1-bit to 16-bit. + For greyscale PNGs, r, g and b will all 3 be set to the same. + + When decoding, by default you can ignore this information, since LodePNG sets + pixels with this key to transparent already in the raw RGBA output. + + The color key is only supported for color types 0 and 2. + */ + unsigned key_defined; /*is a transparent color key given? 0 = false, 1 = true*/ + unsigned key_r; /*red/greyscale component of color key*/ + unsigned key_g; /*green component of color key*/ + unsigned key_b; /*blue component of color key*/ +} LodePNGColorMode; + +/*init, cleanup and copy functions to use with this struct*/ +void lodepng_color_mode_init(LodePNGColorMode* info); +void lodepng_color_mode_cleanup(LodePNGColorMode* info); +/*return value is error code (0 means no error)*/ +unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source); + +void lodepng_palette_clear(LodePNGColorMode* info); +/*add 1 color to the palette*/ +unsigned lodepng_palette_add(LodePNGColorMode* info, + unsigned char r, unsigned char g, unsigned char b, unsigned char a); + +/*get the total amount of bits per pixel, based on colortype and bitdepth in the struct*/ +unsigned lodepng_get_bpp(const LodePNGColorMode* info); +/*get the amount of color channels used, based on colortype in the struct. +If a palette is used, it counts as 1 channel.*/ +unsigned lodepng_get_channels(const LodePNGColorMode* info); +/*is it a greyscale type? (only colortype 0 or 4)*/ +unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info); +/*has it got an alpha channel? (only colortype 2 or 6)*/ +unsigned lodepng_is_alpha_type(const LodePNGColorMode* info); +/*has it got a palette? (only colortype 3)*/ +unsigned lodepng_is_palette_type(const LodePNGColorMode* info); +/*only returns true if there is a palette and there is a value in the palette with alpha < 255. +Loops through the palette to check this.*/ +unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info); +/* +Check if the given color info indicates the possibility of having non-opaque pixels in the PNG image. +Returns true if the image can have translucent or invisible pixels (it still be opaque if it doesn't use such pixels). +Returns false if the image can only have opaque pixels. +In detail, it returns true only if it's a color type with alpha, or has a palette with non-opaque values, +or if "key_defined" is true. +*/ +unsigned lodepng_can_have_alpha(const LodePNGColorMode* info); +/*Returns the byte size of a raw image buffer with given width, height and color mode*/ +size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color); + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +/*The information of a Time chunk in PNG.*/ +typedef struct LodePNGTime +{ + unsigned year; /*2 bytes used (0-65535)*/ + unsigned month; /*1-12*/ + unsigned day; /*1-31*/ + unsigned hour; /*0-23*/ + unsigned minute; /*0-59*/ + unsigned second; /*0-60 (to allow for leap seconds)*/ +} LodePNGTime; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +/*Information about the PNG image, except pixels, width and height.*/ +typedef struct LodePNGInfo +{ + /*header (IHDR), palette (PLTE) and transparency (tRNS) chunks*/ + unsigned compression_method;/*compression method of the original file. Always 0.*/ + unsigned filter_method; /*filter method of the original file*/ + unsigned interlace_method; /*interlace method of the original file*/ + LodePNGColorMode color; /*color type and bits, palette and transparency of the PNG file*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /* + suggested background color chunk (bKGD) + This color uses the same color mode as the PNG (except alpha channel), which can be 1-bit to 16-bit. + + For greyscale PNGs, r, g and b will all 3 be set to the same. When encoding + the encoder writes the red one. For palette PNGs: When decoding, the RGB value + will be stored, not a palette index. But when encoding, specify the index of + the palette in background_r, the other two are then ignored. + + The decoder does not use this background color to edit the color of pixels. + */ + unsigned background_defined; /*is a suggested background color given?*/ + unsigned background_r; /*red component of suggested background color*/ + unsigned background_g; /*green component of suggested background color*/ + unsigned background_b; /*blue component of suggested background color*/ + + /* + non-international text chunks (tEXt and zTXt) + + The char** arrays each contain num strings. The actual messages are in + text_strings, while text_keys are keywords that give a short description what + the actual text represents, e.g. Title, Author, Description, or anything else. + + A keyword is minimum 1 character and maximum 79 characters long. It's + discouraged to use a single line length longer than 79 characters for texts. + + Don't allocate these text buffers yourself. Use the init/cleanup functions + correctly and use lodepng_add_text and lodepng_clear_text. + */ + size_t text_num; /*the amount of texts in these char** buffers (there may be more texts in itext)*/ + char** text_keys; /*the keyword of a text chunk (e.g. "Comment")*/ + char** text_strings; /*the actual text*/ + + /* + international text chunks (iTXt) + Similar to the non-international text chunks, but with additional strings + "langtags" and "transkeys". + */ + size_t itext_num; /*the amount of international texts in this PNG*/ + char** itext_keys; /*the English keyword of the text chunk (e.g. "Comment")*/ + char** itext_langtags; /*language tag for this text's language, ISO/IEC 646 string, e.g. ISO 639 language tag*/ + char** itext_transkeys; /*keyword translated to the international language - UTF-8 string*/ + char** itext_strings; /*the actual international text - UTF-8 string*/ + + /*time chunk (tIME)*/ + unsigned time_defined; /*set to 1 to make the encoder generate a tIME chunk*/ + LodePNGTime time; + + /*phys chunk (pHYs)*/ + unsigned phys_defined; /*if 0, there is no pHYs chunk and the values below are undefined, if 1 else there is one*/ + unsigned phys_x; /*pixels per unit in x direction*/ + unsigned phys_y; /*pixels per unit in y direction*/ + unsigned phys_unit; /*may be 0 (unknown unit) or 1 (metre)*/ + + /* + unknown chunks + There are 3 buffers, one for each position in the PNG where unknown chunks can appear + each buffer contains all unknown chunks for that position consecutively + The 3 buffers are the unknown chunks between certain critical chunks: + 0: IHDR-PLTE, 1: PLTE-IDAT, 2: IDAT-IEND + Do not allocate or traverse this data yourself. Use the chunk traversing functions declared + later, such as lodepng_chunk_next and lodepng_chunk_append, to read/write this struct. + */ + unsigned char* unknown_chunks_data[3]; + size_t unknown_chunks_size[3]; /*size in bytes of the unknown chunks, given for protection*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNGInfo; + +/*init, cleanup and copy functions to use with this struct*/ +void lodepng_info_init(LodePNGInfo* info); +void lodepng_info_cleanup(LodePNGInfo* info); +/*return value is error code (0 means no error)*/ +unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source); + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +void lodepng_clear_text(LodePNGInfo* info); /*use this to clear the texts again after you filled them in*/ +unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str); /*push back both texts at once*/ + +void lodepng_clear_itext(LodePNGInfo* info); /*use this to clear the itexts again after you filled them in*/ +unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, + const char* transkey, const char* str); /*push back the 4 texts of 1 chunk at once*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +/* +Converts raw buffer from one color type to another color type, based on +LodePNGColorMode structs to describe the input and output color type. +See the reference manual at the end of this header file to see which color conversions are supported. +return value = LodePNG error code (0 if all went ok, an error if the conversion isn't supported) +The out buffer must have size (w * h * bpp + 7) / 8, where bpp is the bits per pixel +of the output color type (lodepng_get_bpp). +For < 8 bpp images, there should not be padding bits at the end of scanlines. +For 16-bit per channel colors, uses big endian format like PNG does. +Return value is LodePNG error code +*/ +unsigned lodepng_convert(unsigned char* out, const unsigned char* in, + const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, + unsigned w, unsigned h); + +#ifdef LODEPNG_COMPILE_DECODER +/* +Settings for the decoder. This contains settings for the PNG and the Zlib +decoder, but not the Info settings from the Info structs. +*/ +typedef struct LodePNGDecoderSettings +{ + LodePNGDecompressSettings zlibsettings; /*in here is the setting to ignore Adler32 checksums*/ + + unsigned ignore_crc; /*ignore CRC checksums*/ + + unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + unsigned read_text_chunks; /*if false but remember_unknown_chunks is true, they're stored in the unknown chunks*/ + /*store all bytes from unknown chunks in the LodePNGInfo (off by default, useful for a png editor)*/ + unsigned remember_unknown_chunks; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNGDecoderSettings; + +void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/*automatically use color type with less bits per pixel if losslessly possible. Default: AUTO*/ +typedef enum LodePNGFilterStrategy +{ + /*every filter at zero*/ + LFS_ZERO, + /*Use filter that gives minimum sum, as described in the official PNG filter heuristic.*/ + LFS_MINSUM, + /*Use the filter type that gives smallest Shannon entropy for this scanline. Depending + on the image, this is better or worse than minsum.*/ + LFS_ENTROPY, + /* + Brute-force-search PNG filters by compressing each filter for each scanline. + Experimental, very slow, and only rarely gives better compression than MINSUM. + */ + LFS_BRUTE_FORCE, + /*use predefined_filters buffer: you specify the filter type for each scanline*/ + LFS_PREDEFINED +} LodePNGFilterStrategy; + +/*Gives characteristics about the colors of the image, which helps decide which color model to use for encoding. +Used internally by default if "auto_convert" is enabled. Public because it's useful for custom algorithms.*/ +typedef struct LodePNGColorProfile +{ + unsigned colored; /*not greyscale*/ + unsigned key; /*if true, image is not opaque. Only if true and alpha is false, color key is possible.*/ + unsigned short key_r; /*these values are always in 16-bit bitdepth in the profile*/ + unsigned short key_g; + unsigned short key_b; + unsigned alpha; /*alpha channel or alpha palette required*/ + unsigned numcolors; /*amount of colors, up to 257. Not valid if bits == 16.*/ + unsigned char palette[1024]; /*Remembers up to the first 256 RGBA colors, in no particular order*/ + unsigned bits; /*bits per channel (not for palette). 1,2 or 4 for greyscale only. 16 if 16-bit per channel required.*/ +} LodePNGColorProfile; + +void lodepng_color_profile_init(LodePNGColorProfile* profile); + +/*Get a LodePNGColorProfile of the image.*/ +unsigned lodepng_get_color_profile(LodePNGColorProfile* profile, + const unsigned char* image, unsigned w, unsigned h, + const LodePNGColorMode* mode_in); +/*The function LodePNG uses internally to decide the PNG color with auto_convert. +Chooses an optimal color model, e.g. grey if only grey pixels, palette if < 256 colors, ...*/ +unsigned lodepng_auto_choose_color(LodePNGColorMode* mode_out, + const unsigned char* image, unsigned w, unsigned h, + const LodePNGColorMode* mode_in); + +/*Settings for the encoder.*/ +typedef struct LodePNGEncoderSettings +{ + LodePNGCompressSettings zlibsettings; /*settings for the zlib encoder, such as window size, ...*/ + + unsigned auto_convert; /*automatically choose output PNG color type. Default: true*/ + + /*If true, follows the official PNG heuristic: if the PNG uses a palette or lower than + 8 bit depth, set all filters to zero. Otherwise use the filter_strategy. Note that to + completely follow the official PNG heuristic, filter_palette_zero must be true and + filter_strategy must be LFS_MINSUM*/ + unsigned filter_palette_zero; + /*Which filter strategy to use when not using zeroes due to filter_palette_zero. + Set filter_palette_zero to 0 to ensure always using your chosen strategy. Default: LFS_MINSUM*/ + LodePNGFilterStrategy filter_strategy; + /*used if filter_strategy is LFS_PREDEFINED. In that case, this must point to a buffer with + the same length as the amount of scanlines in the image, and each value must <= 5. You + have to cleanup this buffer, LodePNG will never free it. Don't forget that filter_palette_zero + must be set to 0 to ensure this is also used on palette or low bitdepth images.*/ + const unsigned char* predefined_filters; + + /*force creating a PLTE chunk if colortype is 2 or 6 (= a suggested palette). + If colortype is 3, PLTE is _always_ created.*/ + unsigned force_palette; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*add LodePNG identifier and version as a text chunk, for debugging*/ + unsigned add_id; + /*encode text chunks as zTXt chunks instead of tEXt chunks, and use compression in iTXt chunks*/ + unsigned text_compression; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNGEncoderSettings; + +void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings); +#endif /*LODEPNG_COMPILE_ENCODER*/ + + +#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) +/*The settings, state and information for extended encoding and decoding.*/ +typedef struct LodePNGState +{ +#ifdef LODEPNG_COMPILE_DECODER + LodePNGDecoderSettings decoder; /*the decoding settings*/ +#endif /*LODEPNG_COMPILE_DECODER*/ +#ifdef LODEPNG_COMPILE_ENCODER + LodePNGEncoderSettings encoder; /*the encoding settings*/ +#endif /*LODEPNG_COMPILE_ENCODER*/ + LodePNGColorMode info_raw; /*specifies the format in which you would like to get the raw pixel buffer*/ + LodePNGInfo info_png; /*info of the PNG image obtained after decoding*/ + unsigned error; +#ifdef LODEPNG_COMPILE_CPP + /* For the lodepng::State subclass. */ + virtual ~LodePNGState(){} +#endif +} LodePNGState; + +/*init, cleanup and copy functions to use with this struct*/ +void lodepng_state_init(LodePNGState* state); +void lodepng_state_cleanup(LodePNGState* state); +void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source); +#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ + +#ifdef LODEPNG_COMPILE_DECODER +/* +Same as lodepng_decode_memory, but uses a LodePNGState to allow custom settings and +getting much more information about the PNG image and color mode. +*/ +unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize); + +/* +Read the PNG header, but not the actual data. This returns only the information +that is in the header chunk of the PNG, such as width, height and color type. The +information is placed in the info_png field of the LodePNGState. +*/ +unsigned lodepng_inspect(unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize); +#endif /*LODEPNG_COMPILE_DECODER*/ + + +#ifdef LODEPNG_COMPILE_ENCODER +/*This function allocates the out buffer with standard malloc and stores the size in *outsize.*/ +unsigned lodepng_encode(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h, + LodePNGState* state); +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/* +The lodepng_chunk functions are normally not needed, except to traverse the +unknown chunks stored in the LodePNGInfo struct, or add new ones to it. +It also allows traversing the chunks of an encoded PNG file yourself. + +PNG standard chunk naming conventions: +First byte: uppercase = critical, lowercase = ancillary +Second byte: uppercase = public, lowercase = private +Third byte: must be uppercase +Fourth byte: uppercase = unsafe to copy, lowercase = safe to copy +*/ + +/* +Gets the length of the data of the chunk. Total chunk length has 12 bytes more. +There must be at least 4 bytes to read from. If the result value is too large, +it may be corrupt data. +*/ +unsigned lodepng_chunk_length(const unsigned char* chunk); + +/*puts the 4-byte type in null terminated string*/ +void lodepng_chunk_type(char type[5], const unsigned char* chunk); + +/*check if the type is the given type*/ +unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type); + +/*0: it's one of the critical chunk types, 1: it's an ancillary chunk (see PNG standard)*/ +unsigned char lodepng_chunk_ancillary(const unsigned char* chunk); + +/*0: public, 1: private (see PNG standard)*/ +unsigned char lodepng_chunk_private(const unsigned char* chunk); + +/*0: the chunk is unsafe to copy, 1: the chunk is safe to copy (see PNG standard)*/ +unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk); + +/*get pointer to the data of the chunk, where the input points to the header of the chunk*/ +unsigned char* lodepng_chunk_data(unsigned char* chunk); +const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk); + +/*returns 0 if the crc is correct, 1 if it's incorrect (0 for OK as usual!)*/ +unsigned lodepng_chunk_check_crc(const unsigned char* chunk); + +/*generates the correct CRC from the data and puts it in the last 4 bytes of the chunk*/ +void lodepng_chunk_generate_crc(unsigned char* chunk); + +/*iterate to next chunks. don't use on IEND chunk, as there is no next chunk then*/ +unsigned char* lodepng_chunk_next(unsigned char* chunk); +const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk); + +/* +Appends chunk to the data in out. The given chunk should already have its chunk header. +The out variable and outlength are updated to reflect the new reallocated buffer. +Returns error code (0 if it went ok) +*/ +unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk); + +/* +Appends new chunk to out. The chunk to append is given by giving its length, type +and data separately. The type is a 4-letter string. +The out variable and outlength are updated to reflect the new reallocated buffer. +Returne error code (0 if it went ok) +*/ +unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, + const char* type, const unsigned char* data); + + +/*Calculate CRC32 of buffer*/ +unsigned lodepng_crc32(const unsigned char* buf, size_t len); +#endif /*LODEPNG_COMPILE_PNG*/ + + +#ifdef LODEPNG_COMPILE_ZLIB +/* +This zlib part can be used independently to zlib compress and decompress a +buffer. It cannot be used to create gzip files however, and it only supports the +part of zlib that is required for PNG, it does not support dictionaries. +*/ + +#ifdef LODEPNG_COMPILE_DECODER +/*Inflate a buffer. Inflate is the decompression step of deflate. Out buffer must be freed after use.*/ +unsigned lodepng_inflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings); + +/* +Decompresses Zlib data. Reallocates the out buffer and appends the data. The +data must be according to the zlib specification. +Either, *out must be NULL and *outsize must be 0, or, *out must be a valid +buffer and *outsize its size in bytes. out must be freed by user after usage. +*/ +unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/* +Compresses data with Zlib. Reallocates the out buffer and appends the data. +Zlib adds a small header and trailer around the deflate data. +The data is output in the format of the zlib specification. +Either, *out must be NULL and *outsize must be 0, or, *out must be a valid +buffer and *outsize its size in bytes. out must be freed by user after usage. +*/ +unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings); + +/* +Find length-limited Huffman code for given frequencies. This function is in the +public interface only for tests, it's used internally by lodepng_deflate. +*/ +unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, + size_t numcodes, unsigned maxbitlen); + +/*Compress a buffer with deflate. See RFC 1951. Out buffer must be freed after use.*/ +unsigned lodepng_deflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings); + +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_ZLIB*/ + +#ifdef LODEPNG_COMPILE_DISK +/* +Load a file from disk into buffer. The function allocates the out buffer, and +after usage you should free it. +out: output parameter, contains pointer to loaded buffer. +outsize: output parameter, size of the allocated out buffer +filename: the path to the file to load +return value: error code (0 means ok) +*/ +unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename); + +/* +Save a file from buffer to disk. Warning, if it exists, this function overwrites +the file without warning! +buffer: the buffer to write +buffersize: size of the buffer to write +filename: the path to the file to save to +return value: error code (0 means ok) +*/ +unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename); +#endif /*LODEPNG_COMPILE_DISK*/ + +#ifdef LODEPNG_COMPILE_CPP +/* The LodePNG C++ wrapper uses std::vectors instead of manually allocated memory buffers. */ +namespace lodepng +{ +#ifdef LODEPNG_COMPILE_PNG +class State : public LodePNGState +{ + public: + State(); + State(const State& other); + virtual ~State(); + State& operator=(const State& other); +}; + +#ifdef LODEPNG_COMPILE_DECODER +/* Same as other lodepng::decode, but using a State for more settings and information. */ +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + State& state, + const unsigned char* in, size_t insize); +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + State& state, + const std::vector& in); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/* Same as other lodepng::encode, but using a State for more settings and information. */ +unsigned encode(std::vector& out, + const unsigned char* in, unsigned w, unsigned h, + State& state); +unsigned encode(std::vector& out, + const std::vector& in, unsigned w, unsigned h, + State& state); +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_DISK +/* +Load a file from disk into an std::vector. +return value: error code (0 means ok) +*/ +unsigned load_file(std::vector& buffer, const std::string& filename); + +/* +Save the binary data in an std::vector to a file on disk. The file is overwritten +without warning. +*/ +unsigned save_file(const std::vector& buffer, const std::string& filename); +#endif /* LODEPNG_COMPILE_DISK */ +#endif /* LODEPNG_COMPILE_PNG */ + +#ifdef LODEPNG_COMPILE_ZLIB +#ifdef LODEPNG_COMPILE_DECODER +/* Zlib-decompress an unsigned char buffer */ +unsigned decompress(std::vector& out, const unsigned char* in, size_t insize, + const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); + +/* Zlib-decompress an std::vector */ +unsigned decompress(std::vector& out, const std::vector& in, + const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); +#endif /* LODEPNG_COMPILE_DECODER */ + +#ifdef LODEPNG_COMPILE_ENCODER +/* Zlib-compress an unsigned char buffer */ +unsigned compress(std::vector& out, const unsigned char* in, size_t insize, + const LodePNGCompressSettings& settings = lodepng_default_compress_settings); + +/* Zlib-compress an std::vector */ +unsigned compress(std::vector& out, const std::vector& in, + const LodePNGCompressSettings& settings = lodepng_default_compress_settings); +#endif /* LODEPNG_COMPILE_ENCODER */ +#endif /* LODEPNG_COMPILE_ZLIB */ +} /* namespace lodepng */ +#endif /*LODEPNG_COMPILE_CPP*/ + +/* +TODO: +[.] test if there are no memory leaks or security exploits - done a lot but needs to be checked often +[.] check compatibility with various compilers - done but needs to be redone for every newer version +[X] converting color to 16-bit per channel types +[ ] read all public PNG chunk types (but never let the color profile and gamma ones touch RGB values) +[ ] make sure encoder generates no chunks with size > (2^31)-1 +[ ] partial decoding (stream processing) +[X] let the "isFullyOpaque" function check color keys and transparent palettes too +[X] better name for the variables "codes", "codesD", "codelengthcodes", "clcl" and "lldl" +[ ] don't stop decoding on errors like 69, 57, 58 (make warnings) +[ ] make warnings like: oob palette, checksum fail, data after iend, wrong/unknown crit chunk, no null terminator in text, ... +[ ] let the C++ wrapper catch exceptions coming from the standard library and return LodePNG error codes +[ ] allow user to provide custom color conversion functions, e.g. for premultiplied alpha, padding bits or not, ... +[ ] allow user to give data (void*) to custom allocator +*/ + +#endif /*LODEPNG_H inclusion guard*/ + +/* +LodePNG Documentation +--------------------- + +0. table of contents +-------------------- + + 1. about + 1.1. supported features + 1.2. features not supported + 2. C and C++ version + 3. security + 4. decoding + 5. encoding + 6. color conversions + 6.1. PNG color types + 6.2. color conversions + 6.3. padding bits + 6.4. A note about 16-bits per channel and endianness + 7. error values + 8. chunks and PNG editing + 9. compiler support + 10. examples + 10.1. decoder C++ example + 10.2. decoder C example + 11. state settings reference + 12. changes + 13. contact information + + +1. about +-------- + +PNG is a file format to store raster images losslessly with good compression, +supporting different color types and alpha channel. + +LodePNG is a PNG codec according to the Portable Network Graphics (PNG) +Specification (Second Edition) - W3C Recommendation 10 November 2003. + +The specifications used are: + +*) Portable Network Graphics (PNG) Specification (Second Edition): + http://www.w3.org/TR/2003/REC-PNG-20031110 +*) RFC 1950 ZLIB Compressed Data Format version 3.3: + http://www.gzip.org/zlib/rfc-zlib.html +*) RFC 1951 DEFLATE Compressed Data Format Specification ver 1.3: + http://www.gzip.org/zlib/rfc-deflate.html + +The most recent version of LodePNG can currently be found at +http://lodev.org/lodepng/ + +LodePNG works both in C (ISO C90) and C++, with a C++ wrapper that adds +extra functionality. + +LodePNG exists out of two files: +-lodepng.h: the header file for both C and C++ +-lodepng.c(pp): give it the name lodepng.c or lodepng.cpp (or .cc) depending on your usage + +If you want to start using LodePNG right away without reading this doc, get the +examples from the LodePNG website to see how to use it in code, or check the +smaller examples in chapter 13 here. + +LodePNG is simple but only supports the basic requirements. To achieve +simplicity, the following design choices were made: There are no dependencies +on any external library. There are functions to decode and encode a PNG with +a single function call, and extended versions of these functions taking a +LodePNGState struct allowing to specify or get more information. By default +the colors of the raw image are always RGB or RGBA, no matter what color type +the PNG file uses. To read and write files, there are simple functions to +convert the files to/from buffers in memory. + +This all makes LodePNG suitable for loading textures in games, demos and small +programs, ... It's less suitable for full fledged image editors, loading PNGs +over network (it requires all the image data to be available before decoding can +begin), life-critical systems, ... + +1.1. supported features +----------------------- + +The following features are supported by the decoder: + +*) decoding of PNGs with any color type, bit depth and interlace mode, to a 24- or 32-bit color raw image, + or the same color type as the PNG +*) encoding of PNGs, from any raw image to 24- or 32-bit color, or the same color type as the raw image +*) Adam7 interlace and deinterlace for any color type +*) loading the image from harddisk or decoding it from a buffer from other sources than harddisk +*) support for alpha channels, including RGBA color model, translucent palettes and color keying +*) zlib decompression (inflate) +*) zlib compression (deflate) +*) CRC32 and ADLER32 checksums +*) handling of unknown chunks, allowing making a PNG editor that stores custom and unknown chunks. +*) the following chunks are supported (generated/interpreted) by both encoder and decoder: + IHDR: header information + PLTE: color palette + IDAT: pixel data + IEND: the final chunk + tRNS: transparency for palettized images + tEXt: textual information + zTXt: compressed textual information + iTXt: international textual information + bKGD: suggested background color + pHYs: physical dimensions + tIME: modification time + +1.2. features not supported +--------------------------- + +The following features are _not_ supported: + +*) some features needed to make a conformant PNG-Editor might be still missing. +*) partial loading/stream processing. All data must be available and is processed in one call. +*) The following public chunks are not supported but treated as unknown chunks by LodePNG + cHRM, gAMA, iCCP, sRGB, sBIT, hIST, sPLT + Some of these are not supported on purpose: LodePNG wants to provide the RGB values + stored in the pixels, not values modified by system dependent gamma or color models. + + +2. C and C++ version +-------------------- + +The C version uses buffers allocated with alloc that you need to free() +yourself. You need to use init and cleanup functions for each struct whenever +using a struct from the C version to avoid exploits and memory leaks. + +The C++ version has extra functions with std::vectors in the interface and the +lodepng::State class which is a LodePNGState with constructor and destructor. + +These files work without modification for both C and C++ compilers because all +the additional C++ code is in "#ifdef __cplusplus" blocks that make C-compilers +ignore it, and the C code is made to compile both with strict ISO C90 and C++. + +To use the C++ version, you need to rename the source file to lodepng.cpp +(instead of lodepng.c), and compile it with a C++ compiler. + +To use the C version, you need to rename the source file to lodepng.c (instead +of lodepng.cpp), and compile it with a C compiler. + + +3. Security +----------- + +Even if carefully designed, it's always possible that LodePNG contains possible +exploits. If you discover one, please let me know, and it will be fixed. + +When using LodePNG, care has to be taken with the C version of LodePNG, as well +as the C-style structs when working with C++. The following conventions are used +for all C-style structs: + +-if a struct has a corresponding init function, always call the init function when making a new one +-if a struct has a corresponding cleanup function, call it before the struct disappears to avoid memory leaks +-if a struct has a corresponding copy function, use the copy function instead of "=". + The destination must also be inited already. + + +4. Decoding +----------- + +Decoding converts a PNG compressed image to a raw pixel buffer. + +Most documentation on using the decoder is at its declarations in the header +above. For C, simple decoding can be done with functions such as +lodepng_decode32, and more advanced decoding can be done with the struct +LodePNGState and lodepng_decode. For C++, all decoding can be done with the +various lodepng::decode functions, and lodepng::State can be used for advanced +features. + +When using the LodePNGState, it uses the following fields for decoding: +*) LodePNGInfo info_png: it stores extra information about the PNG (the input) in here +*) LodePNGColorMode info_raw: here you can say what color mode of the raw image (the output) you want to get +*) LodePNGDecoderSettings decoder: you can specify a few extra settings for the decoder to use + +LodePNGInfo info_png +-------------------- + +After decoding, this contains extra information of the PNG image, except the actual +pixels, width and height because these are already gotten directly from the decoder +functions. + +It contains for example the original color type of the PNG image, text comments, +suggested background color, etc... More details about the LodePNGInfo struct are +at its declaration documentation. + +LodePNGColorMode info_raw +------------------------- + +When decoding, here you can specify which color type you want +the resulting raw image to be. If this is different from the colortype of the +PNG, then the decoder will automatically convert the result. This conversion +always works, except if you want it to convert a color PNG to greyscale or to +a palette with missing colors. + +By default, 32-bit color is used for the result. + +LodePNGDecoderSettings decoder +------------------------------ + +The settings can be used to ignore the errors created by invalid CRC and Adler32 +chunks, and to disable the decoding of tEXt chunks. + +There's also a setting color_convert, true by default. If false, no conversion +is done, the resulting data will be as it was in the PNG (after decompression) +and you'll have to puzzle the colors of the pixels together yourself using the +color type information in the LodePNGInfo. + + +5. Encoding +----------- + +Encoding converts a raw pixel buffer to a PNG compressed image. + +Most documentation on using the encoder is at its declarations in the header +above. For C, simple encoding can be done with functions such as +lodepng_encode32, and more advanced decoding can be done with the struct +LodePNGState and lodepng_encode. For C++, all encoding can be done with the +various lodepng::encode functions, and lodepng::State can be used for advanced +features. + +Like the decoder, the encoder can also give errors. However it gives less errors +since the encoder input is trusted, the decoder input (a PNG image that could +be forged by anyone) is not trusted. + +When using the LodePNGState, it uses the following fields for encoding: +*) LodePNGInfo info_png: here you specify how you want the PNG (the output) to be. +*) LodePNGColorMode info_raw: here you say what color type of the raw image (the input) has +*) LodePNGEncoderSettings encoder: you can specify a few settings for the encoder to use + +LodePNGInfo info_png +-------------------- + +When encoding, you use this the opposite way as when decoding: for encoding, +you fill in the values you want the PNG to have before encoding. By default it's +not needed to specify a color type for the PNG since it's automatically chosen, +but it's possible to choose it yourself given the right settings. + +The encoder will not always exactly match the LodePNGInfo struct you give, +it tries as close as possible. Some things are ignored by the encoder. The +encoder uses, for example, the following settings from it when applicable: +colortype and bitdepth, text chunks, time chunk, the color key, the palette, the +background color, the interlace method, unknown chunks, ... + +When encoding to a PNG with colortype 3, the encoder will generate a PLTE chunk. +If the palette contains any colors for which the alpha channel is not 255 (so +there are translucent colors in the palette), it'll add a tRNS chunk. + +LodePNGColorMode info_raw +------------------------- + +You specify the color type of the raw image that you give to the input here, +including a possible transparent color key and palette you happen to be using in +your raw image data. + +By default, 32-bit color is assumed, meaning your input has to be in RGBA +format with 4 bytes (unsigned chars) per pixel. + +LodePNGEncoderSettings encoder +------------------------------ + +The following settings are supported (some are in sub-structs): +*) auto_convert: when this option is enabled, the encoder will +automatically choose the smallest possible color mode (including color key) that +can encode the colors of all pixels without information loss. +*) btype: the block type for LZ77. 0 = uncompressed, 1 = fixed huffman tree, + 2 = dynamic huffman tree (best compression). Should be 2 for proper + compression. +*) use_lz77: whether or not to use LZ77 for compressed block types. Should be + true for proper compression. +*) windowsize: the window size used by the LZ77 encoder (1 - 32768). Has value + 2048 by default, but can be set to 32768 for better, but slow, compression. +*) force_palette: if colortype is 2 or 6, you can make the encoder write a PLTE + chunk if force_palette is true. This can used as suggested palette to convert + to by viewers that don't support more than 256 colors (if those still exist) +*) add_id: add text chunk "Encoder: LodePNG " to the image. +*) text_compression: default 1. If 1, it'll store texts as zTXt instead of tEXt chunks. + zTXt chunks use zlib compression on the text. This gives a smaller result on + large texts but a larger result on small texts (such as a single program name). + It's all tEXt or all zTXt though, there's no separate setting per text yet. + + +6. color conversions +-------------------- + +An important thing to note about LodePNG, is that the color type of the PNG, and +the color type of the raw image, are completely independent. By default, when +you decode a PNG, you get the result as a raw image in the color type you want, +no matter whether the PNG was encoded with a palette, greyscale or RGBA color. +And if you encode an image, by default LodePNG will automatically choose the PNG +color type that gives good compression based on the values of colors and amount +of colors in the image. It can be configured to let you control it instead as +well, though. + +To be able to do this, LodePNG does conversions from one color mode to another. +It can convert from almost any color type to any other color type, except the +following conversions: RGB to greyscale is not supported, and converting to a +palette when the palette doesn't have a required color is not supported. This is +not supported on purpose: this is information loss which requires a color +reduction algorithm that is beyong the scope of a PNG encoder (yes, RGB to grey +is easy, but there are multiple ways if you want to give some channels more +weight). + +By default, when decoding, you get the raw image in 32-bit RGBA or 24-bit RGB +color, no matter what color type the PNG has. And by default when encoding, +LodePNG automatically picks the best color model for the output PNG, and expects +the input image to be 32-bit RGBA or 24-bit RGB. So, unless you want to control +the color format of the images yourself, you can skip this chapter. + +6.1. PNG color types +-------------------- + +A PNG image can have many color types, ranging from 1-bit color to 64-bit color, +as well as palettized color modes. After the zlib decompression and unfiltering +in the PNG image is done, the raw pixel data will have that color type and thus +a certain amount of bits per pixel. If you want the output raw image after +decoding to have another color type, a conversion is done by LodePNG. + +The PNG specification gives the following color types: + +0: greyscale, bit depths 1, 2, 4, 8, 16 +2: RGB, bit depths 8 and 16 +3: palette, bit depths 1, 2, 4 and 8 +4: greyscale with alpha, bit depths 8 and 16 +6: RGBA, bit depths 8 and 16 + +Bit depth is the amount of bits per pixel per color channel. So the total amount +of bits per pixel is: amount of channels * bitdepth. + +6.2. color conversions +---------------------- + +As explained in the sections about the encoder and decoder, you can specify +color types and bit depths in info_png and info_raw to change the default +behaviour. + +If, when decoding, you want the raw image to be something else than the default, +you need to set the color type and bit depth you want in the LodePNGColorMode, +or the parameters colortype and bitdepth of the simple decoding function. + +If, when encoding, you use another color type than the default in the raw input +image, you need to specify its color type and bit depth in the LodePNGColorMode +of the raw image, or use the parameters colortype and bitdepth of the simple +encoding function. + +If, when encoding, you don't want LodePNG to choose the output PNG color type +but control it yourself, you need to set auto_convert in the encoder settings +to false, and specify the color type you want in the LodePNGInfo of the +encoder (including palette: it can generate a palette if auto_convert is true, +otherwise not). + +If the input and output color type differ (whether user chosen or auto chosen), +LodePNG will do a color conversion, which follows the rules below, and may +sometimes result in an error. + +To avoid some confusion: +-the decoder converts from PNG to raw image +-the encoder converts from raw image to PNG +-the colortype and bitdepth in LodePNGColorMode info_raw, are those of the raw image +-the colortype and bitdepth in the color field of LodePNGInfo info_png, are those of the PNG +-when encoding, the color type in LodePNGInfo is ignored if auto_convert + is enabled, it is automatically generated instead +-when decoding, the color type in LodePNGInfo is set by the decoder to that of the original + PNG image, but it can be ignored since the raw image has the color type you requested instead +-if the color type of the LodePNGColorMode and PNG image aren't the same, a conversion + between the color types is done if the color types are supported. If it is not + supported, an error is returned. If the types are the same, no conversion is done. +-even though some conversions aren't supported, LodePNG supports loading PNGs from any + colortype and saving PNGs to any colortype, sometimes it just requires preparing + the raw image correctly before encoding. +-both encoder and decoder use the same color converter. + +Non supported color conversions: +-color to greyscale: no error is thrown, but the result will look ugly because +only the red channel is taken +-anything to palette when that palette does not have that color in it: in this +case an error is thrown + +Supported color conversions: +-anything to 8-bit RGB, 8-bit RGBA, 16-bit RGB, 16-bit RGBA +-any grey or grey+alpha, to grey or grey+alpha +-anything to a palette, as long as the palette has the requested colors in it +-removing alpha channel +-higher to smaller bitdepth, and vice versa + +If you want no color conversion to be done (e.g. for speed or control): +-In the encoder, you can make it save a PNG with any color type by giving the +raw color mode and LodePNGInfo the same color mode, and setting auto_convert to +false. +-In the decoder, you can make it store the pixel data in the same color type +as the PNG has, by setting the color_convert setting to false. Settings in +info_raw are then ignored. + +The function lodepng_convert does the color conversion. It is available in the +interface but normally isn't needed since the encoder and decoder already call +it. + +6.3. padding bits +----------------- + +In the PNG file format, if a less than 8-bit per pixel color type is used and the scanlines +have a bit amount that isn't a multiple of 8, then padding bits are used so that each +scanline starts at a fresh byte. But that is NOT true for the LodePNG raw input and output. +The raw input image you give to the encoder, and the raw output image you get from the decoder +will NOT have these padding bits, e.g. in the case of a 1-bit image with a width +of 7 pixels, the first pixel of the second scanline will the the 8th bit of the first byte, +not the first bit of a new byte. + +6.4. A note about 16-bits per channel and endianness +---------------------------------------------------- + +LodePNG uses unsigned char arrays for 16-bit per channel colors too, just like +for any other color format. The 16-bit values are stored in big endian (most +significant byte first) in these arrays. This is the opposite order of the +little endian used by x86 CPU's. + +LodePNG always uses big endian because the PNG file format does so internally. +Conversions to other formats than PNG uses internally are not supported by +LodePNG on purpose, there are myriads of formats, including endianness of 16-bit +colors, the order in which you store R, G, B and A, and so on. Supporting and +converting to/from all that is outside the scope of LodePNG. + +This may mean that, depending on your use case, you may want to convert the big +endian output of LodePNG to little endian with a for loop. This is certainly not +always needed, many applications and libraries support big endian 16-bit colors +anyway, but it means you cannot simply cast the unsigned char* buffer to an +unsigned short* buffer on x86 CPUs. + + +7. error values +--------------- + +All functions in LodePNG that return an error code, return 0 if everything went +OK, or a non-zero code if there was an error. + +The meaning of the LodePNG error values can be retrieved with the function +lodepng_error_text: given the numerical error code, it returns a description +of the error in English as a string. + +Check the implementation of lodepng_error_text to see the meaning of each code. + + +8. chunks and PNG editing +------------------------- + +If you want to add extra chunks to a PNG you encode, or use LodePNG for a PNG +editor that should follow the rules about handling of unknown chunks, or if your +program is able to read other types of chunks than the ones handled by LodePNG, +then that's possible with the chunk functions of LodePNG. + +A PNG chunk has the following layout: + +4 bytes length +4 bytes type name +length bytes data +4 bytes CRC + +8.1. iterating through chunks +----------------------------- + +If you have a buffer containing the PNG image data, then the first chunk (the +IHDR chunk) starts at byte number 8 of that buffer. The first 8 bytes are the +signature of the PNG and are not part of a chunk. But if you start at byte 8 +then you have a chunk, and can check the following things of it. + +NOTE: none of these functions check for memory buffer boundaries. To avoid +exploits, always make sure the buffer contains all the data of the chunks. +When using lodepng_chunk_next, make sure the returned value is within the +allocated memory. + +unsigned lodepng_chunk_length(const unsigned char* chunk): + +Get the length of the chunk's data. The total chunk length is this length + 12. + +void lodepng_chunk_type(char type[5], const unsigned char* chunk): +unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type): + +Get the type of the chunk or compare if it's a certain type + +unsigned char lodepng_chunk_critical(const unsigned char* chunk): +unsigned char lodepng_chunk_private(const unsigned char* chunk): +unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk): + +Check if the chunk is critical in the PNG standard (only IHDR, PLTE, IDAT and IEND are). +Check if the chunk is private (public chunks are part of the standard, private ones not). +Check if the chunk is safe to copy. If it's not, then, when modifying data in a critical +chunk, unsafe to copy chunks of the old image may NOT be saved in the new one if your +program doesn't handle that type of unknown chunk. + +unsigned char* lodepng_chunk_data(unsigned char* chunk): +const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk): + +Get a pointer to the start of the data of the chunk. + +unsigned lodepng_chunk_check_crc(const unsigned char* chunk): +void lodepng_chunk_generate_crc(unsigned char* chunk): + +Check if the crc is correct or generate a correct one. + +unsigned char* lodepng_chunk_next(unsigned char* chunk): +const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk): + +Iterate to the next chunk. This works if you have a buffer with consecutive chunks. Note that these +functions do no boundary checking of the allocated data whatsoever, so make sure there is enough +data available in the buffer to be able to go to the next chunk. + +unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk): +unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, + const char* type, const unsigned char* data): + +These functions are used to create new chunks that are appended to the data in *out that has +length *outlength. The append function appends an existing chunk to the new data. The create +function creates a new chunk with the given parameters and appends it. Type is the 4-letter +name of the chunk. + +8.2. chunks in info_png +----------------------- + +The LodePNGInfo struct contains fields with the unknown chunk in it. It has 3 +buffers (each with size) to contain 3 types of unknown chunks: +the ones that come before the PLTE chunk, the ones that come between the PLTE +and the IDAT chunks, and the ones that come after the IDAT chunks. +It's necessary to make the distionction between these 3 cases because the PNG +standard forces to keep the ordering of unknown chunks compared to the critical +chunks, but does not force any other ordering rules. + +info_png.unknown_chunks_data[0] is the chunks before PLTE +info_png.unknown_chunks_data[1] is the chunks after PLTE, before IDAT +info_png.unknown_chunks_data[2] is the chunks after IDAT + +The chunks in these 3 buffers can be iterated through and read by using the same +way described in the previous subchapter. + +When using the decoder to decode a PNG, you can make it store all unknown chunks +if you set the option settings.remember_unknown_chunks to 1. By default, this +option is off (0). + +The encoder will always encode unknown chunks that are stored in the info_png. +If you need it to add a particular chunk that isn't known by LodePNG, you can +use lodepng_chunk_append or lodepng_chunk_create to the chunk data in +info_png.unknown_chunks_data[x]. + +Chunks that are known by LodePNG should not be added in that way. E.g. to make +LodePNG add a bKGD chunk, set background_defined to true and add the correct +parameters there instead. + + +9. compiler support +------------------- + +No libraries other than the current standard C library are needed to compile +LodePNG. For the C++ version, only the standard C++ library is needed on top. +Add the files lodepng.c(pp) and lodepng.h to your project, include +lodepng.h where needed, and your program can read/write PNG files. + +It is compatible with C90 and up, and C++03 and up. + +If performance is important, use optimization when compiling! For both the +encoder and decoder, this makes a large difference. + +Make sure that LodePNG is compiled with the same compiler of the same version +and with the same settings as the rest of the program, or the interfaces with +std::vectors and std::strings in C++ can be incompatible. + +CHAR_BITS must be 8 or higher, because LodePNG uses unsigned chars for octets. + +*) gcc and g++ + +LodePNG is developed in gcc so this compiler is natively supported. It gives no +warnings with compiler options "-Wall -Wextra -pedantic -ansi", with gcc and g++ +version 4.7.1 on Linux, 32-bit and 64-bit. + +*) Clang + +Fully supported and warning-free. + +*) Mingw + +The Mingw compiler (a port of gcc for Windows) should be fully supported by +LodePNG. + +*) Visual Studio and Visual C++ Express Edition + +LodePNG should be warning-free with warning level W4. Two warnings were disabled +with pragmas though: warning 4244 about implicit conversions, and warning 4996 +where it wants to use a non-standard function fopen_s instead of the standard C +fopen. + +Visual Studio may want "stdafx.h" files to be included in each source file and +give an error "unexpected end of file while looking for precompiled header". +This is not standard C++ and will not be added to the stock LodePNG. You can +disable it for lodepng.cpp only by right clicking it, Properties, C/C++, +Precompiled Headers, and set it to Not Using Precompiled Headers there. + +NOTE: Modern versions of VS should be fully supported, but old versions, e.g. +VS6, are not guaranteed to work. + +*) Compilers on Macintosh + +LodePNG has been reported to work both with gcc and LLVM for Macintosh, both for +C and C++. + +*) Other Compilers + +If you encounter problems on any compilers, feel free to let me know and I may +try to fix it if the compiler is modern and standards complient. + + +10. examples +------------ + +This decoder example shows the most basic usage of LodePNG. More complex +examples can be found on the LodePNG website. + +10.1. decoder C++ example +------------------------- + +#include "lodepng.h" +#include + +int main(int argc, char *argv[]) +{ + const char* filename = argc > 1 ? argv[1] : "test.png"; + + //load and decode + std::vector image; + unsigned width, height; + unsigned error = lodepng::decode(image, width, height, filename); + + //if there's an error, display it + if(error) std::cout << "decoder error " << error << ": " << lodepng_error_text(error) << std::endl; + + //the pixels are now in the vector "image", 4 bytes per pixel, ordered RGBARGBA..., use it as texture, draw it, ... +} + +10.2. decoder C example +----------------------- + +#include "lodepng.h" + +int main(int argc, char *argv[]) +{ + unsigned error; + unsigned char* image; + size_t width, height; + const char* filename = argc > 1 ? argv[1] : "test.png"; + + error = lodepng_decode32_file(&image, &width, &height, filename); + + if(error) printf("decoder error %u: %s\n", error, lodepng_error_text(error)); + + / * use image here * / + + free(image); + return 0; +} + +11. state settings reference +---------------------------- + +A quick reference of some settings to set on the LodePNGState + +For decoding: + +state.decoder.zlibsettings.ignore_adler32: ignore ADLER32 checksums +state.decoder.zlibsettings.custom_...: use custom inflate function +state.decoder.ignore_crc: ignore CRC checksums +state.decoder.color_convert: convert internal PNG color to chosen one +state.decoder.read_text_chunks: whether to read in text metadata chunks +state.decoder.remember_unknown_chunks: whether to read in unknown chunks +state.info_raw.colortype: desired color type for decoded image +state.info_raw.bitdepth: desired bit depth for decoded image +state.info_raw....: more color settings, see struct LodePNGColorMode +state.info_png....: no settings for decoder but ouput, see struct LodePNGInfo + +For encoding: + +state.encoder.zlibsettings.btype: disable compression by setting it to 0 +state.encoder.zlibsettings.use_lz77: use LZ77 in compression +state.encoder.zlibsettings.windowsize: tweak LZ77 windowsize +state.encoder.zlibsettings.minmatch: tweak min LZ77 length to match +state.encoder.zlibsettings.nicematch: tweak LZ77 match where to stop searching +state.encoder.zlibsettings.lazymatching: try one more LZ77 matching +state.encoder.zlibsettings.custom_...: use custom deflate function +state.encoder.auto_convert: choose optimal PNG color type, if 0 uses info_png +state.encoder.filter_palette_zero: PNG filter strategy for palette +state.encoder.filter_strategy: PNG filter strategy to encode with +state.encoder.force_palette: add palette even if not encoding to one +state.encoder.add_id: add LodePNG identifier and version as a text chunk +state.encoder.text_compression: use compressed text chunks for metadata +state.info_raw.colortype: color type of raw input image you provide +state.info_raw.bitdepth: bit depth of raw input image you provide +state.info_raw: more color settings, see struct LodePNGColorMode +state.info_png.color.colortype: desired color type if auto_convert is false +state.info_png.color.bitdepth: desired bit depth if auto_convert is false +state.info_png.color....: more color settings, see struct LodePNGColorMode +state.info_png....: more PNG related settings, see struct LodePNGInfo + + +12. changes +----------- + +The version number of LodePNG is the date of the change given in the format +yyyymmdd. + +Some changes aren't backwards compatible. Those are indicated with a (!) +symbol. + +*) 18 apr 2016: Changed qsort to custom stable sort (for platforms w/o qsort). +*) 09 apr 2016: Fixed colorkey usage detection, and better file loading (within + the limits of pure C90). +*) 08 dec 2015: Made load_file function return error if file can't be opened. +*) 24 okt 2015: Bugfix with decoding to palette output. +*) 18 apr 2015: Boundary PM instead of just package-merge for faster encoding. +*) 23 aug 2014: Reduced needless memory usage of decoder. +*) 28 jun 2014: Removed fix_png setting, always support palette OOB for + simplicity. Made ColorProfile public. +*) 09 jun 2014: Faster encoder by fixing hash bug and more zeros optimization. +*) 22 dec 2013: Power of two windowsize required for optimization. +*) 15 apr 2013: Fixed bug with LAC_ALPHA and color key. +*) 25 mar 2013: Added an optional feature to ignore some PNG errors (fix_png). +*) 11 mar 2013 (!): Bugfix with custom free. Changed from "my" to "lodepng_" + prefix for the custom allocators and made it possible with a new #define to + use custom ones in your project without needing to change lodepng's code. +*) 28 jan 2013: Bugfix with color key. +*) 27 okt 2012: Tweaks in text chunk keyword length error handling. +*) 8 okt 2012 (!): Added new filter strategy (entropy) and new auto color mode. + (no palette). Better deflate tree encoding. New compression tweak settings. + Faster color conversions while decoding. Some internal cleanups. +*) 23 sep 2012: Reduced warnings in Visual Studio a little bit. +*) 1 sep 2012 (!): Removed #define's for giving custom (de)compression functions + and made it work with function pointers instead. +*) 23 jun 2012: Added more filter strategies. Made it easier to use custom alloc + and free functions and toggle #defines from compiler flags. Small fixes. +*) 6 may 2012 (!): Made plugging in custom zlib/deflate functions more flexible. +*) 22 apr 2012 (!): Made interface more consistent, renaming a lot. Removed + redundant C++ codec classes. Reduced amount of structs. Everything changed, + but it is cleaner now imho and functionality remains the same. Also fixed + several bugs and shrunk the implementation code. Made new samples. +*) 6 nov 2011 (!): By default, the encoder now automatically chooses the best + PNG color model and bit depth, based on the amount and type of colors of the + raw image. For this, autoLeaveOutAlphaChannel replaced by auto_choose_color. +*) 9 okt 2011: simpler hash chain implementation for the encoder. +*) 8 sep 2011: lz77 encoder lazy matching instead of greedy matching. +*) 23 aug 2011: tweaked the zlib compression parameters after benchmarking. + A bug with the PNG filtertype heuristic was fixed, so that it chooses much + better ones (it's quite significant). A setting to do an experimental, slow, + brute force search for PNG filter types is added. +*) 17 aug 2011 (!): changed some C zlib related function names. +*) 16 aug 2011: made the code less wide (max 120 characters per line). +*) 17 apr 2011: code cleanup. Bugfixes. Convert low to 16-bit per sample colors. +*) 21 feb 2011: fixed compiling for C90. Fixed compiling with sections disabled. +*) 11 dec 2010: encoding is made faster, based on suggestion by Peter Eastman + to optimize long sequences of zeros. +*) 13 nov 2010: added LodePNG_InfoColor_hasPaletteAlpha and + LodePNG_InfoColor_canHaveAlpha functions for convenience. +*) 7 nov 2010: added LodePNG_error_text function to get error code description. +*) 30 okt 2010: made decoding slightly faster +*) 26 okt 2010: (!) changed some C function and struct names (more consistent). + Reorganized the documentation and the declaration order in the header. +*) 08 aug 2010: only changed some comments and external samples. +*) 05 jul 2010: fixed bug thanks to warnings in the new gcc version. +*) 14 mar 2010: fixed bug where too much memory was allocated for char buffers. +*) 02 sep 2008: fixed bug where it could create empty tree that linux apps could + read by ignoring the problem but windows apps couldn't. +*) 06 jun 2008: added more error checks for out of memory cases. +*) 26 apr 2008: added a few more checks here and there to ensure more safety. +*) 06 mar 2008: crash with encoding of strings fixed +*) 02 feb 2008: support for international text chunks added (iTXt) +*) 23 jan 2008: small cleanups, and #defines to divide code in sections +*) 20 jan 2008: support for unknown chunks allowing using LodePNG for an editor. +*) 18 jan 2008: support for tIME and pHYs chunks added to encoder and decoder. +*) 17 jan 2008: ability to encode and decode compressed zTXt chunks added + Also various fixes, such as in the deflate and the padding bits code. +*) 13 jan 2008: Added ability to encode Adam7-interlaced images. Improved + filtering code of encoder. +*) 07 jan 2008: (!) changed LodePNG to use ISO C90 instead of C++. A + C++ wrapper around this provides an interface almost identical to before. + Having LodePNG be pure ISO C90 makes it more portable. The C and C++ code + are together in these files but it works both for C and C++ compilers. +*) 29 dec 2007: (!) changed most integer types to unsigned int + other tweaks +*) 30 aug 2007: bug fixed which makes this Borland C++ compatible +*) 09 aug 2007: some VS2005 warnings removed again +*) 21 jul 2007: deflate code placed in new namespace separate from zlib code +*) 08 jun 2007: fixed bug with 2- and 4-bit color, and small interlaced images +*) 04 jun 2007: improved support for Visual Studio 2005: crash with accessing + invalid std::vector element [0] fixed, and level 3 and 4 warnings removed +*) 02 jun 2007: made the encoder add a tag with version by default +*) 27 may 2007: zlib and png code separated (but still in the same file), + simple encoder/decoder functions added for more simple usage cases +*) 19 may 2007: minor fixes, some code cleaning, new error added (error 69), + moved some examples from here to lodepng_examples.cpp +*) 12 may 2007: palette decoding bug fixed +*) 24 apr 2007: changed the license from BSD to the zlib license +*) 11 mar 2007: very simple addition: ability to encode bKGD chunks. +*) 04 mar 2007: (!) tEXt chunk related fixes, and support for encoding + palettized PNG images. Plus little interface change with palette and texts. +*) 03 mar 2007: Made it encode dynamic Huffman shorter with repeat codes. + Fixed a bug where the end code of a block had length 0 in the Huffman tree. +*) 26 feb 2007: Huffman compression with dynamic trees (BTYPE 2) now implemented + and supported by the encoder, resulting in smaller PNGs at the output. +*) 27 jan 2007: Made the Adler-32 test faster so that a timewaste is gone. +*) 24 jan 2007: gave encoder an error interface. Added color conversion from any + greyscale type to 8-bit greyscale with or without alpha. +*) 21 jan 2007: (!) Totally changed the interface. It allows more color types + to convert to and is more uniform. See the manual for how it works now. +*) 07 jan 2007: Some cleanup & fixes, and a few changes over the last days: + encode/decode custom tEXt chunks, separate classes for zlib & deflate, and + at last made the decoder give errors for incorrect Adler32 or Crc. +*) 01 jan 2007: Fixed bug with encoding PNGs with less than 8 bits per channel. +*) 29 dec 2006: Added support for encoding images without alpha channel, and + cleaned out code as well as making certain parts faster. +*) 28 dec 2006: Added "Settings" to the encoder. +*) 26 dec 2006: The encoder now does LZ77 encoding and produces much smaller files now. + Removed some code duplication in the decoder. Fixed little bug in an example. +*) 09 dec 2006: (!) Placed output parameters of public functions as first parameter. + Fixed a bug of the decoder with 16-bit per color. +*) 15 okt 2006: Changed documentation structure +*) 09 okt 2006: Encoder class added. It encodes a valid PNG image from the + given image buffer, however for now it's not compressed. +*) 08 sep 2006: (!) Changed to interface with a Decoder class +*) 30 jul 2006: (!) LodePNG_InfoPng , width and height are now retrieved in different + way. Renamed decodePNG to decodePNGGeneric. +*) 29 jul 2006: (!) Changed the interface: image info is now returned as a + struct of type LodePNG::LodePNG_Info, instead of a vector, which was a bit clumsy. +*) 28 jul 2006: Cleaned the code and added new error checks. + Corrected terminology "deflate" into "inflate". +*) 23 jun 2006: Added SDL example in the documentation in the header, this + example allows easy debugging by displaying the PNG and its transparency. +*) 22 jun 2006: (!) Changed way to obtain error value. Added + loadFile function for convenience. Made decodePNG32 faster. +*) 21 jun 2006: (!) Changed type of info vector to unsigned. + Changed position of palette in info vector. Fixed an important bug that + happened on PNGs with an uncompressed block. +*) 16 jun 2006: Internally changed unsigned into unsigned where + needed, and performed some optimizations. +*) 07 jun 2006: (!) Renamed functions to decodePNG and placed them + in LodePNG namespace. Changed the order of the parameters. Rewrote the + documentation in the header. Renamed files to lodepng.cpp and lodepng.h +*) 22 apr 2006: Optimized and improved some code +*) 07 sep 2005: (!) Changed to std::vector interface +*) 12 aug 2005: Initial release (C++, decoder only) + + +13. contact information +----------------------- + +Feel free to contact me with suggestions, problems, comments, ... concerning +LodePNG. If you encounter a PNG image that doesn't work properly with this +decoder, feel free to send it and I'll use it to find and fix the problem. + +My email address is (puzzle the account and domain together with an @ symbol): +Domain: gmail dot com. +Account: lode dot vandevenne. + + +Copyright (c) 2005-2016 Lode Vandevenne +*/