Merge pull request #35 from fluggo/master-1.7.8x

Add Python 3.2 support
This commit is contained in:
Alex Clark ☺ 2013-01-10 06:59:12 -08:00
commit b48257e259
230 changed files with 6784 additions and 2113 deletions

BIN
Images/lena.fli Normal file

Binary file not shown.

BIN
Images/lena.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
Images/lena.psd Normal file

Binary file not shown.

BIN
Images/lena.tar Normal file

Binary file not shown.

175
Images/lena.xpm Normal file
View File

@ -0,0 +1,175 @@
/* XPM */
static char * lena_xpm[] = {
"128 128 44 1",
" c None",
". c #CC9966",
"+ c #663333",
"@ c #996666",
"# c #CC6666",
"$ c #CC9999",
"% c #FFCC99",
"& c #996633",
"* c #FF9966",
"= c #663366",
"- c #FFCCCC",
"; c #CCCC99",
"> c #FF9999",
", c #993333",
"' c #333333",
") c #CCCCCC",
"! c #996699",
"~ c #CC6633",
"{ c #666666",
"] c #999999",
"^ c #666699",
"/ c #330000",
"( c #663300",
"_ c #330033",
": c #999966",
"< c #FFFFCC",
"[ c #333366",
"} c #660033",
"| c #CC99CC",
"1 c #9999CC",
"2 c #660000",
"3 c #FFFFFF",
"4 c #CCCC66",
"5 c #FFCC66",
"6 c #666633",
"7 c #993366",
"8 c #FFFF99",
"9 c #993300",
"0 c #333300",
"a c #FF99CC",
"b c #CCCCFF",
"c c #CC9933",
"d c #CC6699",
"e c #000000",
".....*...*.%*..#&@#&@&#&#&#.&#.#.#.#.#.#..#.*.#...#..#.#.#.#..#..#..#..#..#.#.#@#.>..>...*..*...*....%%%%.&&.@.#.@.#..&#.~.#&#$.",
">%*..*.*..*%.*.&#@&#@#&#&#&#*&.#.#.#.#.*#..#&.~.#.#.#.&.#.#.#.#.#.#&.#..#&.@.@&#&#.>.*.*...*..*..*...%%%%%&&~@#&#.@&##.&#.#.@.>@",
"...>...*.*.>.%*&#,&#&#&@&#.&#.#.#.#.~.#.#.~.>.#.#..~.#*.~.&*.#.*&*.#..#&.#.##.#@&#.$.>.>.*..*..*.....%%;%%@&@.#.@.#..&#..&#.#@+(",
".*...*...%*.*.>&&@@#@&##&#.#&#.~.#.#.#.#.##.#&*.~.#..#.#.#.#.#.#.#.#~.#.#.#&.#&@#&#.>.....*..*..*.*...%%%%%&.&@.#&#.#.#.#$.$&+++",
"..>.*.*.*.%.>.~&#&#&#.@&#&#&.#.#.#..#.~.~.*.~>&>.#.#*.#.#.~.~.#.#.~.#.*&*.#.#.#.#&#..>.>*..>..*.......%%<%%$&#.#&$&#.&#.&>@,++2+",
".*.%...%*.*..*.#&@#@&##&#&#&#&#.&.#*.#.#.#.#*.~*#.~.#~.~*#.#*#.*.#.#.#.#&.#.#.#&@.##.*..%*..*..*>.*.....%%%%&&&.#~.#.#.#.$&+++++",
"..>.*.*.%*.*..*#&,&#@&#&#&#.#.~#.~.&>.~.~#*&#~#.~>#.~$~$&.~..#.#~.~.~.#.#.#.#&$#&#&$.>.>..%*.>....*.....%%%-.@#&.#&#.#.$$,++++++",
"..*.*%.*%.*.>..#&@#&##&#&#&#&.#.#.#.~.#.*.#.*.~.~.#.#.~.##&#.~.#.##.#*&*~.#.#&#.@#&>.>%.*>.%..*.>..*.*..%%%%%&&&.#.&#&#.@++++'=+",
".*...*.*.*.*.*.~#@&#@&#&#&.#~.#&*&*&#.~#.~*#~#.#*#.~.#&>..#.#.#...#.#.#.#.#..#.#&#.#..>...*.*..%*..>...>.%<%-%@.&#.#.$@@++++++=+",
".%.*%.%*.%.*.*.&&,&#&#@&#&#.#&.#&*#.~.*.#..#.*~.#.##..#&..&*&#.##.~.#~.#~.#~#.#.@#@.#..>.>..*.*..>.*.*....%%%%.&&#.#&$,++++=+='+",
"*>.*.*..**..*>.#,@#@#&#&##&#&#*&>&*#.#~.#~.#.#.#*#.&#&.#@#.@..#..@.#..#.#~..#.#&#&#.>.>...*.$..*.*...*.*.>%%%-%&&@&$#@++/++'++=+",
"..%*.%*...*.*.*&,&#&@#&#&&#.#.#.#&.~#.#.#.~.#.#..#$#$.$...$&@.@.#.@.##.#.##.##.#.@#.#..*.>.%*.>...>.#.#....%%<-.&#.@&+++=+=+=+=+",
"*.*.*.*.*%*.*.*&#,@#&##&##&~#&*&*#*&*&*&*@.#.~.#$..$.$.-$%$-%$.@.@.&..#*#.#*&#&##&#.#.>...*....*>.*.*.*.~..%%%%%@@.@++++++=+=++=",
"%..%*..*.*.*..*&&&,@#&##&#.#.#.#.#.#.#.#.#.#.#..@>@.$$$;$%$.$-$%$.#@.#..#.##.##.#@&#$.>.>.>.*>.....*.~.*....%<%<.$+++/+=+=++=/++",
"*.*..~.~.%*.*.*# #&,&#&#&#~.#~.~#.#*&*#..@.#.$.$$.$.$;$;$%$%$-.$.&@#.#~.##.#&##.#.#....*...*.>*.#..#.~....<%%-&+++++'=+[++=++",
".%*.*.&*.*%*.*. @#&#&#.#&#.##.~.#.#..>.#.$&#$@.$$:$$;$;$;$;-;-$.@&#$#.#&###&@.#..#.>..>.>..~..*#*.*.~...%%<-@+++=++=++=++=+",
"*.%*&,&*.*.*.* @#&##&#.~&*&>~.#.>@#&.@#.@$.@$.$.$.$;$;%-;.)%-%$&@.##.#.@.##&#.>.*.#.#.*&*.*.*.#.#..*...-%-+++/+{++_++=+}+",
"*.>.~&~..%*.*. &#&#&#&#.##&.#~#&*&##.@.#&$#.@.$.$;$.%).;-;$;$)%$&@&@#.##,@@.#..>.>..>.>.~.*.#.#>.>.#.*.-$+/+=+=+=++=+=+_+",
".*.&#(#.**.%*. @#&#&##.#&*#.#..##.#&#@.$.$@>$$.$.$%]%;$;;-;)%)%--&@&@&#&#&##.#..*.#.#..>..~.*..#.*...#..++='+++=++=+'+++@",
"%.#&~&~..*c*.* #@&#&#&#.#&*&#*#.&#.#.#@##.&.@.$$.$%$$;$%]%)$;$;-<-%@&@$&##@&#.>.>.#.#&#.*.*.*.>*.~.*..>++++=+=++'=+++=++$",
"*.~&,&#.*%.*.*. &#@#&#.#&#.#.#.#&#&#&@.#..@$#.#.@.$.]%;-;-;$;$;-;)--<$@#&,@&##.*.*.>.#&#&$..*.#.*.#.*$.$&++/+++='=+}+=++@$$",
".#@&,&#.*.*%*.*& @&#&#@&#.#.#.~&*.#&#.##&@@.#.@.#.$.$.$.$%$;$)-3))-;;-;-&@@@#@#&#.>.*.#.@(,$#...*#.**.*..@++++!'+}+=+=+@+@@$.",
".&,&#&&>.*..*.#&#@,&#@&#&#&#&#&#.#.##&#&#.#.#&$.#.$.@.$.$$-$;$$%)%-;-;3;)<-)&@&@&,#.~.*>.>#&,+.@**.*.~>.#.>.+++'+++=+=+=++@@@.$.",
"&#&#&,#..*%*.*.,&,@@#@#&##&#.#&#&#.&~#.##&#&#.#$.#.>.#.$.;.$$;-;-)-);)-)<)%3-++@@&@#.*.*..>@,+@@..#*.*~**.>+++_+='++=+=+=++@.$..",
"&,@,&@&>.*.%.>.#&+&#&@&#&#&#&#.#.#.#&#~.#.#.$&#.#..#.$.$.$$.-;--)%)););););-<-&+,@~@*.**>.#&+2+@>*.*#.*.#>&2+++=++=++_+++@@$$...",
"&#&@,#&>.%**.*.&,@,&@#&@@#&#.#&#.~#.#&#&#&#&#.@.#.$.@.@.$.$;-$-;-;-)-;-);-);-)-$+@&#.*..*.>@++++@.#.**.>*$,+/=+=++'=+'+=+@$$.$..",
"@,#&@&#.*..%.>.#&@@,@##&#&##&#.#.#&#&#&#.##.#.$.$.#..#.@$.--;%)$-)%));)<))<)-<)%@+@.#.**.>.#++++#@.>&#.>.@++++=+'+++=+++@$.@..-.",
"@&@,&,&>..**.*.#&,&#&@&@#&#&#.#&>&#&#.#&#.#.#.#.#.>@.@.$%).-$;-;$-;-%)-)%)-;)%)-$+@&.*..*.#@+++++.@...$.#++}=+=+=+=+++++$$$.$...",
",#@,@&#..*...>&#@+&@,@#&#&#.#&#&%#&.#&##.#.#.#.#...#&$.-.-;$;$-;)-))-;-;-;)-;3;3-@@&$.*.*.>&++++/@.-%%$$+++++++=+'+=+++$.$..$.$.",
"@,&#@,&#%.%*.*.&,@,&#&#&#&#&#.#.>&#&#.#&#&#.#.@.#@@..$%$%$.-;$;-;-;-;--)--;)-;);-$(#..*.>.>@++/++--;-<<)/'+[+=+++=++'+@$&$.$%.$.",
"@,@&,&..*.*%..>&,&@@,@#@#&#&#&#%>&#&#.#.#.#.#.#..&@.$%$%]%).-;$;-;$)%$;-%)-;))<)3-@@...*..#@++=@-)%)%)-<{+[++{+=+='}+@:$.$..$.>.",
"@&#@#,&#.%.*.*.&,@,@&&#&@#&#.#&%>&#&#&#&#.#.#.@>&#.$%$.-.$;$;-;$;$;-)--)-;-)%);)))%@..*.*..@++]-]$<);<)-]'='=++++=@++$.$..$..$.$",
"#&,&#&#.**%.%*#&,&&##&#&#&##&&#%.#&#&#&>&#&.#..#&-*$.$.-$-.)$.-$;$-.;-;.-)%;);-;-)).$...*>&&+$)$))--;)%)$+'+=+=++'}'$$$.$.%$....",
"#&@#,~&*...*..*&@,@&&#&##&#.#&.%*&#&#.#.#.#.&#.&.>%.$.$.;-$%$).-$;-$;--);$);-);)-))-$.>..~@.%;;-;));-;3-{+'+++=+=++@@$$..$...$$.",
"@&#&##&*.*5.%*.#,&@,&#&#&##&#&>%#&#~@#&#@.##.@.>..#.$%$-$.).$;$;%$;-.;-%)%$;-;-;);-;%$....%--$3)-;-));-)++=+[+/++/+@$.$$..$%>..>",
"~@#&,&#*.%*.*.*&@,&#&#&#&#&#@&%.#&#&~.#&#.&#.#..>.$.%$.%$.-;$.$$%$.-;$.$;$;$;-;-)$)-%$.$-%-;%;-;-)-;-3%)'+'++=+=++@$$$.%$..$..$.",
"@&###&#.*.5.%.>&,@@&#&#,&#@~&#%..~#&#&#&#$&#..>..#.>$.$.$%$.-;%.-.$%$%)%$;-)%$);%).]%-%%$.-;-);-)%)%;-3-+'=+_++++@$$.$.$..$.>..$",
"~@&#~#&*..%**.*.,(#,&#&##&#&#&%.>.*&#&#.#.#.#.#..#...$.-.$.$..$.%;$.%$.-;$%)$;$$;$;-;$)%-;-$%)-;-;-)-;-]++'+'=+++@.$$.$.>...$.>.",
"#&#&,&#.*..%.*.#@@&@&#&#&##&#&-%..#.#&#&#.#.$..#.$.>.$.$.-;%$%.-..$;.).$%$-.-$;$;$;$;$;-);-;)-;-)%$%)%-{+_=+=+'+@$$..$.%$.>..$.$",
",@&##,~*.5*%*.*&,@,##&,&#&#@&~%.**.~&#&#&#.#.#..>.$.$%$.$.$.$.$.$%$.$%$%$;$:-$-.$%$;-;-;$)-)%)-;-$:$.)-+'+'=+++@@.$.$.$...$.>.>.",
"&#,&#&#.*..%.*.#,&@&#&#&#&#&#&%..*&*#&#&>$.#$.#..$.#.$.-$.-.-..-..$%$.-$;-$$%]$;-;%)%))););$)%)%-.$@;$$++=++=++@$.$.$..$%.$..$.$",
"@&#&#&#..*.*.*.&@,@#&#&,#&#&&#%.*.*.&#.#.#.#&$.#.>.$.$.$.$$.$$$.$$$%$$%$.$;$$.$$;$%$;)%)-);-;-;-.).$$-'+'+='+'@@.$..-.>.$...$...",
"&#@,#~#*.%5%.%*#+,&@,#&#&##&#.%*.*.*~&#.>@#.>..#&$.#$$$$$.$$@@$$$.$$$$:$$-.$;-;-%;)%)$;);-)-;--$;@.@;-++=+=+++@$.$.$..$..>$..$>.",
",&#&#&&*.*.*.*.~@@,&#&#&#&#&,.%%..*..#.#.#.#.>.#.$#..$&@@@@@$$@$-$$]-$$+.{$%-$;-%$;-;-;-)-;--;-.$@:@-$/++_+=++@$.$..$.$.$..$..$.",
"@&#,##~.*.%.%*>&,@@,&#,&#&#&,.*.*.**.&#.#$#$.#.@*@.$>@$$@@@+$)@!]+@@@++{+$;$:-%]%)%$;-);;--;-%$@&+@%-+'+=++++@$$.$.>.%.$.$..$..$",
"&#&&#&#*..5*..*&,@,@&#&#,#&#&&%%%*.*.#.#&#.#.$.#.$#.@$@@@{!@!@!+=$=@'+++@$$-$%-;)-;).)%-%)%$.@&@&$%)+++'+==++.$.$%$.$$.$.%$.$...",
"#&#@~#..*.*%%*.#@+#@#&#&&#&,&~%%5*.~.~&#.$#$&#..#.$#$@$@!@={=!!@[@[@=e+)$;-;);$%;$-;-);$<$&@6+@&]$-(++++=++++$$.$.$%.$..$....$..",
"&#&#&##*.%..*..~#+&#&,###&#&#(%%%...>&@#.#.#.#.@>.@#$@@+@+=+!{=!!=+!++)@-]%$%)%$;)$;$%)%@]&@&@.$.)+++'++=+=+@$.$%.$.$.-.$.$$..$.",
"@#&##&#.**%.%*.#&,@,@&#&,#&#&#.%5....#@>#$&#.$#.$$@$@=!==+=]!_+=@[+{+$$)%$);$;;-$-;---@@@@.:%.-$-++++=+=+++@$.#.$.%.$.$.$.$.$$.$",
"&&#&#~#...5*%*.&,@,@#@#&#&#&&,&%%%%..@.$.,.#@&$@,$@+}@='=/={+=]!_!/!$]%$;).-$;$;)-$;.@{@@$-$..%%+/'++=+'=++@$$.%..$.%..$%$.$.$.$",
"#&#&#&#**.*..**#@,&@,@#@#&##.#&%%%..#$##&#.&$.$$+@+!@=+!={=+={=@@_]$@-;$%$;$;$;$;-.$(+@${@:%.--+++++=+=++++@..$.$%.$.$%$.$.$.$$.",
"#&###&#.%.%*%...,@,#&#&,#&,&#&#&%%%.&..#$#.>@#@@@@=@=+=!+_'+=+='!!{@)$--;$;$;$%;$)%]&@@@$@$$%.(+++++'+_+=+@$.$%..$%.$..$.%$.$..$",
"#&@&#,&**.%.*%*&,@&@,#@&#&#&#&&9%%.>.#@..@.@.@@@@@@=_=+=@_+=@@!+!]@$).;$.-.$;$;-;-%-.@@@@@:-@++++++=@+'+++@@@.$.%$..$..$.$.$.$.$",
"#&##&###..*%.*.~@,+#@&###~#&#.#&.%%.&.,.#&#$@$@+=+@=+=^@[+++=++!@]@)$%).).)$.).-;$;%.+@@@$@.6+/++++++=+=+@$&$%..$.$.-.$..$..$...",
"&#&#&,&*.%.%*%*#&,@&#,@&@&#&#~&#&-%#.#&#&>.@@@}+=+={!==@!+'+'+@+$1$)$%$.$$.-;-%;-%-%$@++=@]$+/+=+{=+=/+++@$$.$.%.%..$.%$.%$..$.$",
"#&@##&#.*%*.....,@,@@&##,#&#&>&#&%%&#&.@.@>@@+!+='+==+![$!+++@@$]$-$;$;$%$.$;$%-;-%%%$++@+$]+++=+++++'+++$@$.$.$.$$%.$.$.$%.$...",
"&#&#&,&#..%.%*>&,@(##@#&#&#&#.#&#->.&#&>&@++!+=+=+=+[=+=@++/@$$$$]$).$..$;$-%-;%-%;%.$@+}{$$+'+=+={+=+++@@$.$..$...$..%.$.$..$.$",
"&#&##&#*.*%*...#&@,@&#@#&##.#~&#..-&#..#$@@++++^+==+^=@!'=/@$$$-$$$-;-.$.$%$%$%-%--%%#@+}@]$@++=++=+++++$@.$.$..$.$.$.$;..;.$...",
"@&#@#,&...%.%*.#&@,@#&#&#&#~$~#.##%#.@.$@++!_=@={+=+=='=+@{@.$;$)&$%$.$.-$%$%-;%)%%%-%@+++@${+={=++=+++@$$.$..:.$.$:$.$.$$.$.$$.",
"&@&#&,#*.*%*%*.&,@@&@#@##&#&#.&#&$@.@.#@+!++@'+=+'=+=+=@'@$:$.$%-:-$.$.%>%$-.-%%-;-%%>@@+/@$++=+={++'++@@$$.$%$.;..$..$..$.$:..$",
"#&#@#&@....%.%>&#(@#@&#&#&#&##*#@&#.#$@@+@_!_=+{=+={==+/+@@$.$;$$$..$%>.$>%$%-;.-%%)%-$+}+@)@++={+=++++$..$;$...$$..$:@.$:$.$$$.",
"@&#&#~##..*%.*.&@@,&#@#@##~#.&#.>++&$.@+=+=@=+=++++='+^+]@-;-..-%$@&&#.>%>-.$%-;-)%%%$#++++-@+@+=+[+++@$@.$..$;..$.$.$.@.$$.@.$$",
"&#@,@,&*.%..%%>~@(@@&#&#&@&##.*.#+2$@@@+!=^!'={+_+=@!@_+@:-.).;-.$.$.,(#.>$%$%%%$;-%.@@++++%@+=+{+=+++@$$.$....$;.$:.$.$.$.$$@.@",
"@&&#&#@#.*%.*..&#@,@#&#&#~#&#&>.$@(@@@+@++=!+=+'@/=/@+'$@)$%$.-&@$$$.$&,&#.>.$;%%$@@&@#@+++]$++=+=+'++.@.$%$.$..$%.$.$.$:$$$:$@$",
"##&#@9&..*%*%%*.,+#&#&#&#&@&>..>.$@++!=^!!/^+^+=1'+=++@:-.;-$%@@@+++++$.#.>.%%-;-$@+++@++++$@@++=+=++@$@.$.$..$..$$.$.$.$.$.@$:$",
"&#&#&#,>...%.*..&,@,&#&&#&#..$..$+@+=@!@^]=@=+'+_!'+0+$.$;-%-+(+,++@@2+#.#*>.%-;@+++++}+++{$@@+++'+++@..$.$.$..$...$.$.$.$$$$$@$",
"&,@,@(&.**%*.%*&,@,@&#,.,&#-.$.@$++^+^_=!@_'+==/^+_++@:.-.-%+@,++@++--(@~.#.>%%$++@@a+++=++$]@=+==+++.@$.$.$.$.$.>$.$.$$.@.:@@.@",
"#&#&#,,...*%.*..@,&##&#&#@+,$$$(+/@=+=!+^1+[+'+='=+'+@$$.%-&@&,&@+@@$-#@#&#..)%6@+@@$7++++@@$@@++=+++$..$.$.$..$..$.$.$.$.@.$:$.",
"@&#@,&@#.%.%*%.~#,&#&@.,+&@--%+++{!'=!=^+!+==+=+=+'+$..$;-&&$$@@&$.--%.$~#*.>%-@.$#$$,@+++!{$@@+=+'+@:$.$.$.$.$.$..$.$.@$:$.@..;",
"#@#&@,&#.*5.%*..&@#&##.+#$$$@++@@'}'={=!!!'/'=+'=+++@-$%-&@...*$#$@&@$-.#.#.$%;$.$.@,+@}++@@|{++++++@$.$.$..$....$.@.$.@.@.;.%%%",
"#&@,@,&#.*%*%.*.,,&#&#$#$$+@=+'+1$!==^={$1+=++=++/+$]$.-&&*#>.$.$.$.-.#.>.#*$-%-$.##@#@++++@$@+=+=+@.@...$.$.$.$.$.$.@.$.$.$%;.%",
",@#&,+,.>.%*%.*.&#&#.@&$@!+!+==@!{^'==!!!!{+='/='+@@$--#&#...>.>.$.$.$%#*#.*$%-.$.$.#$,@+++@$@@++++@$.-$..$.$.$....$.:@&$%%%%%.%",
"@&+@,&+...%.*%.#,#,@##$#$$|={={^{!+_=]={@$!+++=+++@$$%$&@.#*>.>%$%%$%$..>.#.>%--.*>##@@+}+{+|$+++++@....$..$...$.$.@.@.;%.;%.;5%",
"@,&,@+,#.*%*%.*.&,&#.$@$+=+='=!+!{[='==!^/@!'++/+@]$--(,#.~.*..>.>.%$%>.*#*#$%-%$...>##+++++$]+++++$@.$..$.$$.$.@:$...$.-%.%%.;%",
"@,@+,&+...*%*%.~#&,@@#$+!@^=!'!1'_+==+=+++]@+=+++$$$)++&#&>~>.>%%%$%..$.*.#..---..>.#$#+++++-$++++@.$...$...$.@...@.@.%;%%;%%%%%",
"@+@@,+,@>%..%*..,#&#&@@$!{=!==!{=='+[+{=++$@@'/+$&--@+/@~#*~.>.$>%.%>.>.>*#~$%%-.>.#.#@,++++$$++++@$.$..$.$.$.:$.$.:..%%.%;.;%;%",
",@(+,+&#..*%.%*&,@#@@$$+@!]={^@!{+=='_++++$@$@+/@$-)+/@@#.~**.>..>%$%..*#.~.#$-%...>$#++7+++1$++++@.$.%..$.@.$.@.$&$.;%%4%%%%;%%",
"+,@@+,+&>.%*.*..&@&#$$+!@^===!1]|'+=+}{@+@$$+++]@%$+++/&###~#..>...>.>..#*#..%--.>..>@,+++++$$++++$.$.$...$.$.:$.@...%.%.%4;%%;-",
"@@+,+,+..*.%*%*#,,@@@$@+!{={1{=$=/'+=+@+]@+@/'/$@%@'++@@~*~**>.$*>%..$*.~.#*@.-<..$#.@+++!+/$$@++@$....$...$.$.@.@.$%%454%%%;-%)",
",@+@,++#$%*%.%..,@.#@@@=@!==!=^][+='/=@$@.++++$@:$+/+/@+@#*#*.*$..>.>..##*.#..--...>@,}++@+/$$$+(@@$.$..$.$.$.$.$@..%%%%4%;%;%)%",
"@,@++(,....*%*..#,@@@$+@!{=@^+!!{|+={++=+@+/+@;$-@+'++@,#&*#.#.>*>.%>*#.*#.#.$%-.>.@$+++=++++$$/+.$.$.$..$.$:$...@.%%.4%%%;%%;%;",
",@,@,@+.>.%..%*&&&,@@@@!@=_!='!!]1+={}'+!++++$-$]+/+++@@&#*~*>.>.>.>.$*.#&#&#&>.*..#@+=++++++$$+&$..$.$.$.$.@.$.$..;%%%4;%%;%-%%",
"@,@,+&@...%*%*.>#+#@$@+!+=]=!=]!|!'+!@/++/@@@$6-++=+/+#@~#.#*~>*.#*.*.>.*..#.$%$.>$@+}+=@++++-@+@.$.>.$..@..$:@.@..%%4%%%;%;%;;%",
"@+@@+,@.$*.%.%..&+&#@$+{!@=_{=!!{!!'@^++!@$$@@$+'+++++#@$~#*#.#.>.>>.>.#.>.%%-%$..#@++++!+@+($$@#.$.$..$.$.$..$..$.%%%;%;%%;-;-;",
",@,+@+#..%.*%*.##,@@$@!+!{==={={=1@={@/+]$$$@@@+++=@++@&#.~*~**.#...*..>..>-.%>.>$.++=++@+++/$.@...$.$..$..@.$.@..%%.%5%;%;-%<%;",
"++@+,+@.>.%.*%..&@@#@$+@!+!'==!!^!1+@'+@@$-@@]+++@++++#+##.#.#*.*.>.>.*.>..%$%%$.$@/+=+7@@++($@@$.$...$.@.:$.:.@..%%%;%<%%<;%-;%",
"+,@+@,&$..*%.*.#&,@@@!+!+[=@^@[+^={|++.)$-+@$++{+=+!+++&#.~***#.#*.~.#..*$*>%$.$#@+++++=+@,++@:....$.$..$.$.@.$.@.%%%5;%;;%;%;-<",
"++,++@,.>%.%%%.#&@#@$@=+!'===!{=^!!{@)@-%@@@+/+@}++++++@##.#~.**.#&#.~#.#&.#.,&@>$++++++}@++(@@@.$....$...$..@....%%%%%%%%;-<%;%",
"+++@+@&$..*%*%*.@$,@@@@=+={^'|!{!!{+@$&3$&]$++=+++=+=+,+&#~.#*#.*>*~#.~~>&#.>$.$$}+}'+=+@@+@+&$.$..$..$.@.$:$.]@&%%;%4%;%;%<-;%<",
"@++++@&>..%*.%.#&$+$@@'=+_=@=]=!^!={]$$;@$$++'/=+++@+++@@&#~.~.#.#.*#*#.*>%-*#$>@+++++++}@2@+&$.$..$..$:.$..$..$&%%%%%<%<%;%%;%%",
"++7+,+@..>.%%*..#+@@d+@='='=^@[@^^@!$]$$@-+++++++=++=+@,,@~@~#*~.*>.~.#*#.>.>.>@+_+=+++@+@+@2+$..$..$..$.$:@:$@:@;%;8%;%;%-;%;%;",
"=++++@&#.%.*%>..,@$@@+!+=$[@b{!{=^!]@$$$-+@+}{=+++++@++@,@#&#.#.#.#*#*#.#~##$#$,+=++{++@7@}@++.$..$..$.$.$.$.$.@.%%%%;%<%;%)%%%%",
"+++++#@..*%.%*..@,$@@+!'_=='|^@1!+1@@{$-@++=++++++=+{+@++&#&#&>.#*.>..#.>..>.>@@/=+++++@+@+@++.$...$..$.$.$@:$@:@;%<%%<%%<%%;%;%",
"+=++@@@#..*%.%>.@+@@+@@='@[=$^!]!^+1$+]$+++++=+=++++=+++++,#&##.#.#.>*.>.>$%$.++=+[+{++@+#+#++$.$..$.$.$:$.$$$.@&;<%;%;;%-<%%%%%",
"+++++@..>.%*%..#@,@@=+^+=^+^]='1|]=]$@@+=+=++'+++++=+'+++&+,,&#.#....>.>%$.>$#(++=+++++@@+7@@(-.$.$..@.$.$@:@$@].-%;<%<%;%%)%;%%",
"+=}++@@...%.*%*.@+@+++!+'='_!]={!!]!!{!+'=+=+='@+++++=@+++(+(,#&#.#>..%.>%$.$@+++'={'++@+@+@@+.$..$:$.@$.$.$.@:@:%<%;%%<%;%%%%..",
"+++++#@#.*.%*%.#+@$@=@==+='=]|={!^|{|$1@_+'}{@}@_+'+=+++@+#+,+,(#&&#.#>.%$.$.@++=++++++@!@+#++%$&@.@.$.]$$@$]@$&.;%%4%;%%%-$$+++",
"++++++&$>.>..*..@-+$+'@={=+{!]=={!^!]!{)!'=++=+@+=+++=+=++++&#.#.#.>...$*.$%$.@+'='@{=+@+!+@@($.@.@&$@.@.@.$.@]@%%<%%%%;%;.(++++",
"++++}@,&$%*%*$*.-++===+=+=+_{|]=[!$^@^!+]@'=@++=+++=+'+@++,@#@#$#.#.>.*.$..$%$;-@+'++++!@@@+@($.&@.@.@@@.]@@.@&$;%%4%8%%%.@++++@",
"@@+++++#.>.%.%>.+@]++_{='!{+[@^@|]^!^@^|]!++='+@=+'=++=++++@@#.#.#.#.#..>.$.-%----]/'++++7@+@+.$.$&$&@&@@&@@@@@&%;%%%%%;$&(++@@@",
"@!@@+@+&..**%*..@++='+=@_+^@='|^!!{^@1@^$+1+@+=+++++=++=@++,@#.#.#.>..>...%.-.-;-)--+++@+@@+,@.@.$.@.$@.@@&@&$&@%;%;%;%.&+(@,+@,",
"$]@@@++,.$%..%>.$@++_+|{=]+^+={={==!{!]!{={{=++=+=+'=++++@+@&#$##.#.#.~.>.$.%%$%%)%3;@'+++@++@$.@.$.$.@.@@@&@&@&%4%%%%$(+(@&@,@@",
"@$$$@@2@.*.*%*..$@+=+_+=@_@'!{=$={'!^$!]=$_$+'/@=+=++'=++@+,@.#..#.*.>..*.%%$%.;$%;-%-$+{+@++.$.$.@.@.@$&$@&$.@&%%<;%%@(@@@+&@&@",
"{$]$@@+@$%.%*.>.@)/'={=+='=+=+[{==!{!{1@1+)=+=+{+'+=@+++@@++#.##.#.#..#..>...$%%;%-;%<)@++@++$$.$.:$.$.$@.@@&$&%;%%%;.@(@&#@#@,@",
"+@|$$@(,..>%*%..@@+/=+='=+{='=+={[+=!!]|]!+{$+/=+=++=++@@@#(@#&$*.#.*#.*..%.%.%-%;%;-%--{++++$.$.$@.@$@.$#.@.&$%%%;%%@(@@,@.@&&&",
"'@]$$@++...%.%*.$@+=/!+=+=@=+_{==@^{+^!@|{=|)=++{+=+{+}+@@@(,.#.#.*>.*.>.>..-..%$%-;%<;--+@++.@$..:$..$.@.@.#..%%%%%.&,@&@#@,@#@",
"++]$$$+&.*%*%*.$$+'=+[='_'$'='_@^{!!!{!]|'=@-+/!+=++=+++#@#2@.#.#.#.~>.*..>..%$%;%;%-;-%)++++$..$..@$@.@$.@&..%%%<%%$&@&#@@&@&&@",
"''$]$@++$%.%.%*.$++'=+=+=@!'+=+='=+{!'!1!@={|'+@{=+++++@@@&2&#.#*~.*..#.>.%$..%.%$;%%;-<-)++($.@.$...$@.@.@.$%%%%%%.&&,@&##@#@@@",
"++!$$$(+..*%*...@+_@_+[+[@@_{='=+[={!=@^$^@!{+_+++=++++#&#@(#.#..#*#.*.*.>..%$.-.%-;-%)-;3/0@@...@.$@.$@.@..%%%;%%%$&#&#@&@,@@#&",
"''])$@(+..%.%*..@'+'+[+=@[++=+=+='+=]=!]|]!@^++=++@++++@#.#,~.*#*..#*#.#..>.$%.%$;%-%;-<--@+@.$..$...@.@$&@%<%%%%%%&&&#&#@,@&@@@",
"/+@]$$+($.%*%%*.@@==/='=+]='+'='=+^='!{|=]|$@{++=+++},@#.@(&##..~**..#*.>.>.>.$%.-;%)%--;-)(]..@..@$.$.@.@:%;%4%%%$&#&&#.&#@@@+@",
"''!)$]+,..%..*..$++'+=+[+!@_!+_+='!+=@!1$_'[+=]$@=+++@@#.>,&&*#.#.~*#.*#.>.$.%$.-.-;-;-;-<$+&]..$..@.@:@.@.%%%%<%*.&&#&#@,&@,@@@",
"++{$$$@($.*%*%.>@'+=+'=+'='+'=+'=+^'^^@^@1+=+++@+@@++&#@.#(##.#*.*$*.#.*#*.*$..%.%%%-;-;-;-(@.$..@.$:$$.@...%%8%%.#.&&#&@@#@@@,@",
"_/!]$]@+.>%.%*..$++=++{=++=+=+=+{=+^+^]1+^@'/={++++2+#&#@#+&#.*.#.~.**#*.>.*..$..$;%%-<-%)-:$.@.$..$@.@:@...%.%%%.~#&#&@,@@@+@@@",
"+'+$]$+&&.*%*%.>$@+'+=+'={={+=+=+[+^='!^+^@|'++=++++@&#..#&#.#*.*.#*#.*.#*.>.%.%.%.-;%);-<--:@.@&$.$$].$&.....%%%.&#&@,&@,@#@@+@",
"_+{$$]@+$..%.*..$@}'++='+=+='='+!'_$!'={[@^@=++/++++#@##@2&#.#*#.*.*.~>~.*..>..$..%$%-%-)%-<@&@&@&@.@$@.$....4%%.#&,&@,@&@@+@@@+",
"+/=]$$&&&>%*.%..@@+=+'}=+{=++=+_=@!{!={=={!+'_{+=+++#&$*@(#.#.>.*#.#.*.#.#*...%.%.%.;-;-;-;-.@&+(@@@@@@$...&.%%%.@&@,&@@@@@&@@++",
"+'+]$)@+...*%*..@++'=+'='=+[+='+'_+^$|{!]='=++=+/++@#.##2&#.#.*#*.*.*#.**.*.>*.$.$%$%;-%<--<$6@&@&+({(@+&$..%%%..,+&@,@@,@@@@@++",
"+++$$).(..%*%.%.@=+++=++='={+=+==+=={|!^@=+^/=+/+++#@#&,(#.#.*#.*#.*#*.#.#*...*.%..%$%;-;-%--&@@@@@++++(+%%.%%%.@(@+@&@@@+@@@+++",
"{@{]$]$+&..*%*.&$@_'+'='+=+='=++='=+_{$^!{='=/+=++@#$#&2#.#.>.~*.*.*.#*#*.#.>.>..$%.%-%-;3;-%{&@&@@@@++(,%>.%<.&++,@+@@(@@@@@+@+",
"@@@$$;$&@%%.%%.&$+++=+=+='=@=+[/=+='=!_@!{_++[+++@#@~,(,.#.#.*.~*#.**..*.*.*...*..$%.;-;-%-;-$@&@@&@@++(+.%-.>&(+@+@@@@+@@@@@@++",
"+{@]$]$&&.*.*%%&@=+=+'='+='='=@='!+=+^@^+='=+/+++@@#(2,~#.#.#*#.*.~.#*~.#*#.#*.$*.$%$.%-;)%-<-6@@@@6@@+@&>%%$&+(+@+@@+@+@@@@{+@+",
"@@@$$.]&@.%.%...@++'=+=+=+=++={}+!'!'=@1+=++++}+@(,(#~..~#.*.**~*.**.*>.*.~.*.>..>.%.-;%-;-%--+@&@@@@&@&#.>.&,&+@+@@@@+@@&@@++++",
"+@{@)$$&..*%*%..{++=+{='='=^+!@='!+=]={!{='=++++,(#&&#~#.*##.#*.#.#*.*.~.#*.#.**...$%.$;%)%);-:@@@&@@@&@&..,@(@&+@@@@++@@@@@@+++",
"+'@@$)$&@..%%%.#++_+=+=+!+=@[+=@={!_+={!@++++/+,@&.#*.*~#..~.#****.~.#*.*..*.*#.>>.%$%%$%)%----+6@@@&@@.##&~@#@+@@@+@+@@]@@++{++",
"+++{$-)$..%*.%.@++++'+{='='@={=$=+!'^$_+^+_+++@$&#&~&~*.~#*#*.~.~.*.*.#*.#*#.*.*..>..$;%;-;;-;-+@&@@&$&#&&#&#&@@@@+@+@@.@@@+++++",
"++'@)-.$&$.%%%%&+'=+==+=+=={=@={@[@='={!$@+++,@,.&.#*&~~.*&.#*#*#*~.*.*.*..*>.*>.>.%.%$;%)%--;-@&@&@@.@.#&#.#&@@+@+@@@@@@@++++!@",
"++++-))$...>.%.@++_++{={'=@_+=+={=]+_@[/^@+@+@#@#.~.~*.~*#*#*.~.*.*.**.*.#*.*#.*.>.$..$;$%);--)$6@&@&#.@*&#.#@,@+@@+@@$@@@++++@@"};

View File

@ -8,6 +8,10 @@ include *.rst
include *.c include *.c
include *.h include *.h
include selftest.py tox.ini include selftest.py tox.ini
recursive-include Tests *.py *.txt
graft Tests/fonts
graft Tests/icc
graft Tests/images
recursive-include Scripts *.py README recursive-include Scripts *.py README
graft Images graft Images
recursive-include docs *.txt *.html *.rst *.css *.py README CHANGES CONTENTS Makefile make.bat recursive-include docs *.txt *.html *.rst *.css *.py README CHANGES CONTENTS Makefile make.bat

View File

@ -18,13 +18,15 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
from __future__ import print_function
__version__ = "0.4" __version__ = "0.4"
import Image, ImageFile, ImagePalette from . import Image, ImageFile, ImagePalette
from PngImagePlugin import i16, i32, ChunkStream, _MODES from .PngImagePlugin import i8, i16, i32, ChunkStream, _MODES
MAGIC = "\212ARG\r\n\032\n" MAGIC = b"\212ARG\r\n\032\n"
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# ARG parser # ARG parser
@ -60,18 +62,18 @@ class ArgStream(ChunkStream):
# assertions # assertions
if self.count != 0: if self.count != 0:
raise SyntaxError, "misplaced AHDR chunk" raise SyntaxError("misplaced AHDR chunk")
s = self.fp.read(bytes) s = self.fp.read(bytes)
self.size = i32(s), i32(s[4:]) self.size = i32(s), i32(s[4:])
try: try:
self.mode, self.rawmode = _MODES[(ord(s[8]), ord(s[9]))] self.mode, self.rawmode = _MODES[(i8(s[8]), i8(s[9]))]
except: except:
raise SyntaxError, "unknown ARG mode" raise SyntaxError("unknown ARG mode")
if Image.DEBUG: if Image.DEBUG:
print "AHDR size", self.size print("AHDR size", self.size)
print "AHDR mode", self.mode, self.rawmode print("AHDR mode", self.mode, self.rawmode)
return s return s
@ -80,7 +82,7 @@ class ArgStream(ChunkStream):
# assertions # assertions
if self.count != 0: if self.count != 0:
raise SyntaxError, "misplaced AFRM chunk" raise SyntaxError("misplaced AFRM chunk")
self.show = 1 self.show = 1
self.id = 0 self.id = 0
@ -98,7 +100,7 @@ class ArgStream(ChunkStream):
self.repair = None self.repair = None
if Image.DEBUG: if Image.DEBUG:
print "AFRM", self.id, self.count print("AFRM", self.id, self.count)
return s return s
@ -107,7 +109,7 @@ class ArgStream(ChunkStream):
# assertions # assertions
if self.count != 0: if self.count != 0:
raise SyntaxError, "misplaced ADEF chunk" raise SyntaxError("misplaced ADEF chunk")
self.show = 0 self.show = 0
self.id = 0 self.id = 0
@ -121,7 +123,7 @@ class ArgStream(ChunkStream):
self.count = i16(s[2:4]) self.count = i16(s[2:4])
if Image.DEBUG: if Image.DEBUG:
print "ADEF", self.id, self.count print("ADEF", self.id, self.count)
return s return s
@ -130,7 +132,7 @@ class ArgStream(ChunkStream):
# assertions # assertions
if self.count == 0: if self.count == 0:
raise SyntaxError, "misplaced NAME chunk" raise SyntaxError("misplaced NAME chunk")
name = self.fp.read(bytes) name = self.fp.read(bytes)
self.names[self.id] = name self.names[self.id] = name
@ -141,26 +143,26 @@ class ArgStream(ChunkStream):
"AEND -- end of animation" "AEND -- end of animation"
if Image.DEBUG: if Image.DEBUG:
print "AEND" print("AEND")
self.eof = 1 self.eof = 1
raise EOFError, "end of ARG file" raise EOFError("end of ARG file")
def __getmodesize(self, s, full=1): def __getmodesize(self, s, full=1):
size = i32(s), i32(s[4:]) size = i32(s), i32(s[4:])
try: try:
mode, rawmode = _MODES[(ord(s[8]), ord(s[9]))] mode, rawmode = _MODES[(i8(s[8]), i8(s[9]))]
except: except:
raise SyntaxError, "unknown image mode" raise SyntaxError("unknown image mode")
if full: if full:
if ord(s[12]): if i8(s[12]):
pass # interlace not yet supported pass # interlace not yet supported
if ord(s[11]): if i8(s[11]):
raise SyntaxError, "unknown filter category" raise SyntaxError("unknown filter category")
return size, mode, rawmode return size, mode, rawmode
@ -169,7 +171,7 @@ class ArgStream(ChunkStream):
# assertions # assertions
if self.count == 0: if self.count == 0:
raise SyntaxError, "misplaced PAST chunk" raise SyntaxError("misplaced PAST chunk")
if self.repair is not None: if self.repair is not None:
# we must repair the target image before we # we must repair the target image before we
@ -206,7 +208,7 @@ class ArgStream(ChunkStream):
# assertions # assertions
if self.count == 0: if self.count == 0:
raise SyntaxError, "misplaced BLNK chunk" raise SyntaxError("misplaced BLNK chunk")
s = self.fp.read(bytes) s = self.fp.read(bytes)
size, mode, rawmode = self.__getmodesize(s, 0) size, mode, rawmode = self.__getmodesize(s, 0)
@ -223,7 +225,7 @@ class ArgStream(ChunkStream):
# assertions # assertions
if self.count == 0: if self.count == 0:
raise SyntaxError, "misplaced IHDR chunk" raise SyntaxError("misplaced IHDR chunk")
# image header # image header
s = self.fp.read(bytes) s = self.fp.read(bytes)
@ -234,7 +236,7 @@ class ArgStream(ChunkStream):
self.im = Image.core.new(mode, size) self.im = Image.core.new(mode, size)
self.decoder = Image.core.zip_decoder(rawmode) self.decoder = Image.core.zip_decoder(rawmode)
self.decoder.setimage(self.im, (0,0) + size) self.decoder.setimage(self.im, (0,0) + size)
self.data = "" self.data = b""
return s return s
@ -243,20 +245,20 @@ class ArgStream(ChunkStream):
# assertions # assertions
if self.count == 0: if self.count == 0:
raise SyntaxError, "misplaced DHDR chunk" raise SyntaxError("misplaced DHDR chunk")
s = self.fp.read(bytes) s = self.fp.read(bytes)
size, mode, rawmode = self.__getmodesize(s) size, mode, rawmode = self.__getmodesize(s)
# delta header # delta header
diff = ord(s[13]) diff = i8(s[13])
offs = i32(s[14:18]), i32(s[18:22]) offs = i32(s[14:18]), i32(s[18:22])
bbox = offs + (offs[0]+size[0], offs[1]+size[1]) bbox = offs + (offs[0]+size[0], offs[1]+size[1])
if Image.DEBUG: if Image.DEBUG:
print "DHDR", diff, bbox print("DHDR", diff, bbox)
# FIXME: decode and apply image # FIXME: decode and apply image
self.action = ("DHDR", diff, bbox) self.action = ("DHDR", diff, bbox)
@ -267,7 +269,7 @@ class ArgStream(ChunkStream):
self.decoder = Image.core.zip_decoder(rawmode) self.decoder = Image.core.zip_decoder(rawmode)
self.decoder.setimage(self.im, (0,0) + size) self.decoder.setimage(self.im, (0,0) + size)
self.data = "" self.data = b""
return s return s
@ -276,7 +278,7 @@ class ArgStream(ChunkStream):
# assertions # assertions
if self.count == 0: if self.count == 0:
raise SyntaxError, "misplaced JHDR chunk" raise SyntaxError("misplaced JHDR chunk")
# image header # image header
s = self.fp.read(bytes) s = self.fp.read(bytes)
@ -287,7 +289,7 @@ class ArgStream(ChunkStream):
self.im = Image.core.new(mode, size) self.im = Image.core.new(mode, size)
self.decoder = Image.core.jpeg_decoder(rawmode) self.decoder = Image.core.jpeg_decoder(rawmode)
self.decoder.setimage(self.im, (0,0) + size) self.decoder.setimage(self.im, (0,0) + size)
self.data = "" self.data = b""
return s return s
@ -296,7 +298,7 @@ class ArgStream(ChunkStream):
# assertions # assertions
if self.count == 0: if self.count == 0:
raise SyntaxError, "misplaced UHDR chunk" raise SyntaxError("misplaced UHDR chunk")
# image header # image header
s = self.fp.read(bytes) s = self.fp.read(bytes)
@ -307,7 +309,7 @@ class ArgStream(ChunkStream):
self.im = Image.core.new(mode, size) self.im = Image.core.new(mode, size)
self.decoder = Image.core.raw_decoder(rawmode) self.decoder = Image.core.raw_decoder(rawmode)
self.decoder.setimage(self.im, (0,0) + size) self.decoder.setimage(self.im, (0,0) + size)
self.data = "" self.data = b""
return s return s
@ -321,7 +323,7 @@ class ArgStream(ChunkStream):
if n < 0: if n < 0:
# end of image # end of image
if e < 0: if e < 0:
raise IOError, "decoder error %d" % e raise IOError("decoder error %d" % e)
else: else:
self.data = self.data[n:] self.data = self.data[n:]
@ -386,7 +388,7 @@ class ArgStream(ChunkStream):
"SYNC -- reset decoder" "SYNC -- reset decoder"
if self.count != 0: if self.count != 0:
raise SyntaxError, "misplaced sYNC chunk" raise SyntaxError("misplaced sYNC chunk")
s = self.fp.read(bytes) s = self.fp.read(bytes)
self.__reset() self.__reset()
@ -418,7 +420,7 @@ class ArgImageFile(ImageFile.ImageFile):
) )
if self.fp.read(8) != MAGIC: if self.fp.read(8) != MAGIC:
raise SyntaxError, "not an ARG file" raise SyntaxError("not an ARG file")
self.arg = ArgStream(self.fp) self.arg = ArgStream(self.fp)
@ -427,7 +429,7 @@ class ArgImageFile(ImageFile.ImageFile):
cid, offset, bytes = self.arg.read() cid, offset, bytes = self.arg.read()
if cid != "AHDR": if cid != "AHDR":
raise SyntaxError, "expected an AHDR chunk" raise SyntaxError("expected an AHDR chunk")
s = self.arg.call(cid, offset, bytes) s = self.arg.call(cid, offset, bytes)
@ -452,11 +454,11 @@ class ArgImageFile(ImageFile.ImageFile):
def seek(self, frame): def seek(self, frame):
if self.arg.eof: if self.arg.eof:
raise EOFError, "end of animation" raise EOFError("end of animation")
self.fp = self.arg.fp self.fp = self.arg.fp
while 1: while True:
# #
# process chunks # process chunks
@ -464,7 +466,7 @@ class ArgImageFile(ImageFile.ImageFile):
cid, offset, bytes = self.arg.read() cid, offset, bytes = self.arg.read()
if self.arg.eof: if self.arg.eof:
raise EOFError, "end of animation" raise EOFError("end of animation")
try: try:
s = self.arg.call(cid, offset, bytes) s = self.arg.call(cid, offset, bytes)
@ -473,7 +475,7 @@ class ArgImageFile(ImageFile.ImageFile):
except "glurk": # AttributeError except "glurk": # AttributeError
if Image.DEBUG: if Image.DEBUG:
print cid, bytes, "(unknown)" print(cid, bytes, "(unknown)")
s = self.fp.read(bytes) s = self.fp.read(bytes)
self.arg.crc(cid, s) self.arg.crc(cid, s)

View File

@ -17,10 +17,9 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import Image from . import Image
import FontFile from . import FontFile
import string
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# parse X Bitmap Distribution Format (BDF) # parse X Bitmap Distribution Format (BDF)
@ -44,39 +43,39 @@ bdf_spacing = {
def bdf_char(f): def bdf_char(f):
# skip to STARTCHAR # skip to STARTCHAR
while 1: while True:
s = f.readline() s = f.readline()
if not s: if not s:
return None return None
if s[:9] == "STARTCHAR": if s[:9] == b"STARTCHAR":
break break
id = string.strip(s[9:]) id = s[9:].strip().decode('ascii')
# load symbol properties # load symbol properties
props = {} props = {}
while 1: while True:
s = f.readline() s = f.readline()
if not s or s[:6] == "BITMAP": if not s or s[:6] == b"BITMAP":
break break
i = string.find(s, " ") i = s.find(b" ")
props[s[:i]] = s[i+1:-1] props[s[:i].decode('ascii')] = s[i+1:-1].decode('ascii')
# load bitmap # load bitmap
bitmap = [] bitmap = []
while 1: while True:
s = f.readline() s = f.readline()
if not s or s[:7] == "ENDCHAR": if not s or s[:7] == b"ENDCHAR":
break break
bitmap.append(s[:-1]) bitmap.append(s[:-1])
bitmap = string.join(bitmap, "") bitmap = b"".join(bitmap)
[x, y, l, d] = map(int, string.split(props["BBX"])) [x, y, l, d] = [int(s) for s in props["BBX"].split()]
[dx, dy] = map(int, string.split(props["DWIDTH"])) [dx, dy] = [int(s) for s in props["DWIDTH"].split()]
bbox = (dx, dy), (l, -d-y, x+l, -d), (0, 0, x, y) bbox = (dx, dy), (l, -d-y, x+l, -d), (0, 0, x, y)
try: try:
im = Image.fromstring("1", (x, y), bitmap, "hex", "1") im = Image.frombytes("1", (x, y), bitmap, "hex", "1")
except ValueError: except ValueError:
# deal with zero-width characters # deal with zero-width characters
im = Image.new("1", (x, y)) im = Image.new("1", (x, y))
@ -93,38 +92,38 @@ class BdfFontFile(FontFile.FontFile):
FontFile.FontFile.__init__(self) FontFile.FontFile.__init__(self)
s = fp.readline() s = fp.readline()
if s[:13] != "STARTFONT 2.1": if s[:13] != b"STARTFONT 2.1":
raise SyntaxError, "not a valid BDF file" raise SyntaxError("not a valid BDF file")
props = {} props = {}
comments = [] comments = []
while 1: while True:
s = fp.readline() s = fp.readline()
if not s or s[:13] == "ENDPROPERTIES": if not s or s[:13] == b"ENDPROPERTIES":
break break
i = string.find(s, " ") i = s.find(b" ")
props[s[:i]] = s[i+1:-1] props[s[:i].decode('ascii')] = s[i+1:-1].decode('ascii')
if s[:i] in ["COMMENT", "COPYRIGHT"]: if s[:i] in [b"COMMENT", b"COPYRIGHT"]:
if string.find(s, "LogicalFontDescription") < 0: if s.find(b"LogicalFontDescription") < 0:
comments.append(s[i+1:-1]) comments.append(s[i+1:-1].decode('ascii'))
font = string.split(props["FONT"], "-") font = props["FONT"].split("-")
font[4] = bdf_slant[string.upper(font[4])] font[4] = bdf_slant[font[4].upper()]
font[11] = bdf_spacing[string.upper(font[11])] font[11] = bdf_spacing[font[11].upper()]
ascent = int(props["FONT_ASCENT"]) ascent = int(props["FONT_ASCENT"])
descent = int(props["FONT_DESCENT"]) descent = int(props["FONT_DESCENT"])
fontname = string.join(font[1:], ";") fontname = ";".join(font[1:])
# print "#", fontname # print "#", fontname
# for i in comments: # for i in comments:
# print "#", i # print "#", i
font = [] font = []
while 1: while True:
c = bdf_char(fp) c = bdf_char(fp)
if not c: if not c:
break break

View File

@ -27,21 +27,19 @@
__version__ = "0.7" __version__ = "0.7"
import string from . import Image, ImageFile, ImagePalette, _binary
import Image, ImageFile, ImagePalette
i8 = _binary.i8
i16 = _binary.i16le
i32 = _binary.i32le
o8 = _binary.o8
o16 = _binary.o16le
o32 = _binary.o32le
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Read BMP file # Read BMP file
def i16(c):
return ord(c[0]) + (ord(c[1])<<8)
def i32(c):
return ord(c[0]) + (ord(c[1])<<8) + (ord(c[2])<<16) + (ord(c[3])<<24)
BIT2MODE = { BIT2MODE = {
# bits => mode, rawmode # bits => mode, rawmode
1: ("P", "P;1"), 1: ("P", "P;1"),
@ -53,7 +51,7 @@ BIT2MODE = {
} }
def _accept(prefix): def _accept(prefix):
return prefix[:2] == "BM" return prefix[:2] == b"BM"
## ##
# Image plugin for the Windows BMP format. # Image plugin for the Windows BMP format.
@ -93,7 +91,7 @@ class BmpImageFile(ImageFile.ImageFile):
lutsize = 4 lutsize = 4
colors = i32(s[32:]) colors = i32(s[32:])
direction = -1 direction = -1
if s[11] == '\xff': if i8(s[11]) == 0xff:
# upside-down storage # upside-down storage
self.size = self.size[0], 2**32 - self.size[1] self.size = self.size[0], 2**32 - self.size[1]
direction = 0 direction = 0
@ -132,10 +130,10 @@ class BmpImageFile(ImageFile.ImageFile):
if colors == 2: if colors == 2:
indices = (0, 255) indices = (0, 255)
else: else:
indices = range(colors) indices = list(range(colors))
for i in indices: for i in indices:
rgb = read(lutsize)[:3] rgb = read(lutsize)[:3]
if rgb != chr(i)*3: if rgb != o8(i)*3:
greyscale = 0 greyscale = 0
palette.append(rgb) palette.append(rgb)
if greyscale: if greyscale:
@ -146,7 +144,7 @@ class BmpImageFile(ImageFile.ImageFile):
else: else:
self.mode = "P" self.mode = "P"
self.palette = ImagePalette.raw( self.palette = ImagePalette.raw(
"BGR", string.join(palette, "") "BGR", b"".join(palette)
) )
if not offset: if not offset:
@ -163,7 +161,7 @@ class BmpImageFile(ImageFile.ImageFile):
# HEAD # HEAD
s = self.fp.read(14) s = self.fp.read(14)
if s[:2] != "BM": if s[:2] != b"BM":
raise SyntaxError("Not a BMP file") raise SyntaxError("Not a BMP file")
offset = i32(s[10:]) offset = i32(s[10:])
@ -182,12 +180,6 @@ class DibImageFile(BmpImageFile):
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Write BMP file # Write BMP file
def o16(i):
return chr(i&255) + chr(i>>8&255)
def o32(i):
return chr(i&255) + chr(i>>8&255) + chr(i>>16&255) + chr(i>>24&255)
SAVE = { SAVE = {
"1": ("1", 1, 2), "1": ("1", 1, 2),
"L": ("L", 8, 256), "L": ("L", 8, 256),
@ -205,13 +197,13 @@ def _save(im, fp, filename, check=0):
if check: if check:
return check return check
stride = ((im.size[0]*bits+7)/8+3)&(~3) stride = ((im.size[0]*bits+7)//8+3)&(~3)
header = 40 # or 64 for OS/2 version 2 header = 40 # or 64 for OS/2 version 2
offset = 14 + header + colors * 4 offset = 14 + header + colors * 4
image = stride * im.size[1] image = stride * im.size[1]
# bitmap header # bitmap header
fp.write("BM" + # file type (magic) fp.write(b"BM" + # file type (magic)
o32(offset+image) + # file size o32(offset+image) + # file size
o32(0) + # reserved o32(0) + # reserved
o32(offset)) # image data offset o32(offset)) # image data offset
@ -228,14 +220,14 @@ def _save(im, fp, filename, check=0):
o32(colors) + # colors used o32(colors) + # colors used
o32(colors)) # colors important o32(colors)) # colors important
fp.write("\000" * (header - 40)) # padding (for OS/2 format) fp.write(b"\0" * (header - 40)) # padding (for OS/2 format)
if im.mode == "1": if im.mode == "1":
for i in (0, 255): for i in (0, 255):
fp.write(chr(i) * 4) fp.write(o8(i) * 4)
elif im.mode == "L": elif im.mode == "L":
for i in range(256): for i in range(256):
fp.write(chr(i) * 4) fp.write(o8(i) * 4)
elif im.mode == "P": elif im.mode == "P":
fp.write(im.im.getpalette("RGB", "BGRX")) fp.write(im.im.getpalette("RGB", "BGRX"))

View File

@ -9,7 +9,7 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import Image, ImageFile from . import Image, ImageFile
_handler = None _handler = None
@ -26,7 +26,7 @@ def register_handler(handler):
# Image adapter # Image adapter
def _accept(prefix): def _accept(prefix):
return prefix[:4] == "BUFR" or prefix[:4] == "ZCZC" return prefix[:4] == b"BUFR" or prefix[:4] == b"ZCZC"
class BufrStubImageFile(ImageFile.StubImageFile): class BufrStubImageFile(ImageFile.StubImageFile):

View File

@ -92,7 +92,7 @@ class ContainerIO:
def readline(self): def readline(self):
s = "" s = ""
while 1: while True:
c = self.read(1) c = self.read(1)
if not c: if not c:
break break
@ -108,7 +108,7 @@ class ContainerIO:
def readlines(self): def readlines(self):
l = [] l = []
while 1: while True:
s = self.readline() s = self.readline()
if not s: if not s:
break break

View File

@ -19,21 +19,19 @@
__version__ = "0.1" __version__ = "0.1"
import Image, BmpImagePlugin from . import Image, BmpImagePlugin, _binary
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
def i16(c): i8 = _binary.i8
return ord(c[0]) + (ord(c[1])<<8) i16 = _binary.i16le
i32 = _binary.i32le
def i32(c):
return ord(c[0]) + (ord(c[1])<<8) + (ord(c[2])<<16) + (ord(c[3])<<24)
def _accept(prefix): def _accept(prefix):
return prefix[:4] == "\0\0\2\0" return prefix[:4] == b"\0\0\2\0"
## ##
# Image plugin for Windows Cursor files. # Image plugin for Windows Cursor files.
@ -50,20 +48,20 @@ class CurImageFile(BmpImagePlugin.BmpImageFile):
# check magic # check magic
s = self.fp.read(6) s = self.fp.read(6)
if not _accept(s): if not _accept(s):
raise SyntaxError, "not an CUR file" raise SyntaxError("not an CUR file")
# pick the largest cursor in the file # pick the largest cursor in the file
m = "" m = b""
for i in range(i16(s[4:])): for i in range(i16(s[4:])):
s = self.fp.read(16) s = self.fp.read(16)
if not m: if not m:
m = s m = s
elif ord(s[0]) > ord(m[0]) and ord(s[1]) > ord(m[1]): elif i8(s[0]) > i8(m[0]) and i8(s[1]) > i8(m[1]):
m = s m = s
#print "width", ord(s[0]) #print "width", i8(s[0])
#print "height", ord(s[1]) #print "height", i8(s[1])
#print "colors", ord(s[2]) #print "colors", i8(s[2])
#print "reserved", ord(s[3]) #print "reserved", i8(s[3])
#print "hotspot x", i16(s[4:]) #print "hotspot x", i16(s[4:])
#print "hotspot y", i16(s[6:]) #print "hotspot y", i16(s[6:])
#print "bytes", i32(s[8:]) #print "bytes", i32(s[8:])
@ -73,7 +71,7 @@ class CurImageFile(BmpImagePlugin.BmpImageFile):
self._bitmap(i32(m[12:]) + offset) self._bitmap(i32(m[12:]) + offset)
# patch up the bitmap height # patch up the bitmap height
self.size = self.size[0], self.size[1]/2 self.size = self.size[0], self.size[1]//2
d, e, o, a = self.tile[0] d, e, o, a = self.tile[0]
self.tile[0] = d, (0,0)+self.size, o, a self.tile[0] = d, (0,0)+self.size, o, a

View File

@ -23,14 +23,13 @@
__version__ = "0.2" __version__ = "0.2"
import Image from . import Image, _binary
from PcxImagePlugin import PcxImageFile from .PcxImagePlugin import PcxImageFile
MAGIC = 0x3ADE68B1 # QUIZ: what's this value, then? MAGIC = 0x3ADE68B1 # QUIZ: what's this value, then?
def i32(c): i32 = _binary.i32le
return ord(c[0]) + (ord(c[1])<<8) + (ord(c[2])<<16) + (ord(c[3])<<24)
def _accept(prefix): def _accept(prefix):
return i32(prefix) == MAGIC return i32(prefix) == MAGIC
@ -48,7 +47,7 @@ class DcxImageFile(PcxImageFile):
# Header # Header
s = self.fp.read(4) s = self.fp.read(4)
if i32(s) != MAGIC: if i32(s) != MAGIC:
raise SyntaxError, "not a DCX file" raise SyntaxError("not a DCX file")
# Component directory # Component directory
self._offset = [] self._offset = []

View File

@ -20,17 +20,15 @@
__version__ = "0.5" __version__ = "0.5"
import re, string import re
import Image, ImageFile import io
from . import Image, ImageFile, _binary
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
def i32(c): i32 = _binary.i32le
return ord(c[0]) + (ord(c[1])<<8) + (ord(c[2])<<16) + (ord(c[3])<<24) o32 = _binary.o32le
def o32(i):
return chr(i&255) + chr(i>>8&255) + chr(i>>16&255) + chr(i>>24&255)
split = re.compile(r"^%%([^:]*):[ \t]*(.*)[ \t]*$") split = re.compile(r"^%%([^:]*):[ \t]*(.*)[ \t]*$")
field = re.compile(r"^%[%!\w]([^:]*)[ \t]*$") field = re.compile(r"^%[%!\w]([^:]*)[ \t]*$")
@ -55,7 +53,7 @@ def Ghostscript(tile, size, fp):
"-sOutputFile=%s" % file,# output file "-sOutputFile=%s" % file,# output file
"- >/dev/null 2>/dev/null"] "- >/dev/null 2>/dev/null"]
command = string.join(command) command = " ".join(command)
# push data through ghostscript # push data through ghostscript
try: try:
@ -93,30 +91,32 @@ class PSFile:
def seek(self, offset, whence=0): def seek(self, offset, whence=0):
self.char = None self.char = None
self.fp.seek(offset, whence) self.fp.seek(offset, whence)
def read(self, count):
return self.fp.read(count).decode('latin-1')
def tell(self): def tell(self):
pos = self.fp.tell() pos = self.fp.tell()
if self.char: if self.char:
pos = pos - 1 pos = pos - 1
return pos return pos
def readline(self): def readline(self):
s = "" s = b""
if self.char: if self.char:
c = self.char c = self.char
self.char = None self.char = None
else: else:
c = self.fp.read(1) c = self.fp.read(1)
while c not in "\r\n": while c not in b"\r\n":
s = s + c s = s + c
c = self.fp.read(1) c = self.fp.read(1)
if c == "\r": if c == b"\r":
self.char = self.fp.read(1) self.char = self.fp.read(1)
if self.char == "\n": if self.char == b"\n":
self.char = None self.char = None
return s + "\n" return s.decode('latin-1') + "\n"
def _accept(prefix): def _accept(prefix):
return prefix[:4] == "%!PS" or i32(prefix) == 0xC6D3D0C5L return prefix[:4] == b"%!PS" or i32(prefix) == 0xC6D3D0C5
## ##
# Image plugin for Encapsulated Postscript. This plugin supports only # Image plugin for Encapsulated Postscript. This plugin supports only
@ -141,12 +141,12 @@ class EpsImageFile(ImageFile.ImageFile):
offset = 0 offset = 0
fp.seek(0, 2) fp.seek(0, 2)
length = fp.tell() length = fp.tell()
elif i32(s) == 0xC6D3D0C5L: elif i32(s) == 0xC6D3D0C5:
offset = i32(s[4:]) offset = i32(s[4:])
length = i32(s[8:]) length = i32(s[8:])
fp.seek(offset) fp.seek(offset)
else: else:
raise SyntaxError, "not an EPS file" raise SyntaxError("not an EPS file")
fp.seek(offset) fp.seek(offset)
@ -163,7 +163,7 @@ class EpsImageFile(ImageFile.ImageFile):
while s: while s:
if len(s) > 255: if len(s) > 255:
raise SyntaxError, "not an EPS file" raise SyntaxError("not an EPS file")
if s[-2:] == '\r\n': if s[-2:] == '\r\n':
s = s[:-2] s = s[:-2]
@ -172,8 +172,8 @@ class EpsImageFile(ImageFile.ImageFile):
try: try:
m = split.match(s) m = split.match(s)
except re.error, v: except re.error as v:
raise SyntaxError, "not an EPS file" raise SyntaxError("not an EPS file")
if m: if m:
k, v = m.group(1, 2) k, v = m.group(1, 2)
@ -183,7 +183,7 @@ class EpsImageFile(ImageFile.ImageFile):
# Note: The DSC spec says that BoundingBox # Note: The DSC spec says that BoundingBox
# fields should be integers, but some drivers # fields should be integers, but some drivers
# put floating point values there anyway. # put floating point values there anyway.
box = map(int, map(float, string.split(v))) box = [int(float(s)) for s in v.split()]
self.size = box[2] - box[0], box[3] - box[1] self.size = box[2] - box[0], box[3] - box[1]
self.tile = [("eps", (0,0) + self.size, offset, self.tile = [("eps", (0,0) + self.size, offset,
(length, box))] (length, box))]
@ -196,18 +196,19 @@ class EpsImageFile(ImageFile.ImageFile):
if m: if m:
k = m.group(1) k = m.group(1)
if k == "EndComments": if k == "EndComments":
break break
if k[:8] == "PS-Adobe": if k[:8] == "PS-Adobe":
self.info[k[:8]] = k[9:] self.info[k[:8]] = k[9:]
else: else:
self.info[k] = "" self.info[k] = ""
elif s[0] == '%': elif s[0:1] == '%':
# handle non-DSC Postscript comments that some # handle non-DSC Postscript comments that some
# tools mistakenly put in the Comments section # tools mistakenly put in the Comments section
pass pass
else: else:
raise IOError, "bad EPS header" raise IOError("bad EPS header")
s = fp.readline() s = fp.readline()
@ -221,7 +222,7 @@ class EpsImageFile(ImageFile.ImageFile):
while s[0] == "%": while s[0] == "%":
if len(s) > 255: if len(s) > 255:
raise SyntaxError, "not an EPS file" raise SyntaxError("not an EPS file")
if s[-2:] == '\r\n': if s[-2:] == '\r\n':
s = s[:-2] s = s[:-2]
@ -231,7 +232,7 @@ class EpsImageFile(ImageFile.ImageFile):
if s[:11] == "%ImageData:": if s[:11] == "%ImageData:":
[x, y, bi, mo, z3, z4, en, id] =\ [x, y, bi, mo, z3, z4, en, id] =\
string.split(s[11:], maxsplit=7) s[11:].split(None, 7)
x = int(x); y = int(y) x = int(x); y = int(y)
@ -261,7 +262,7 @@ class EpsImageFile(ImageFile.ImageFile):
id = id[1:-1] id = id[1:-1]
# Scan forward to the actual image data # Scan forward to the actual image data
while 1: while True:
s = fp.readline() s = fp.readline()
if not s: if not s:
break break
@ -278,7 +279,7 @@ class EpsImageFile(ImageFile.ImageFile):
break break
if not box: if not box:
raise IOError, "cannot determine EPS bounding box" raise IOError("cannot determine EPS bounding box")
def load(self): def load(self):
# Load EPS via Ghostscript # Load EPS via Ghostscript
@ -308,7 +309,18 @@ def _save(im, fp, filename, eps=1):
elif im.mode == "CMYK": elif im.mode == "CMYK":
operator = (8, 4, "false 4 colorimage") operator = (8, 4, "false 4 colorimage")
else: else:
raise ValueError, "image mode is not supported" raise ValueError("image mode is not supported")
class NoCloseStream:
def __init__(self, fp):
self.fp = fp
def __getattr__(self, name):
return getattr(self.fp, name)
def close(self):
pass
base_fp = fp
fp = io.TextIOWrapper(NoCloseStream(fp), encoding='latin-1')
if eps: if eps:
# #
@ -332,9 +344,10 @@ def _save(im, fp, filename, eps=1):
fp.write("%d %d 8\n" % im.size) # <= bits fp.write("%d %d 8\n" % im.size) # <= bits
fp.write("[%d 0 0 -%d 0 %d]\n" % (im.size[0], im.size[1], im.size[1])) fp.write("[%d 0 0 -%d 0 %d]\n" % (im.size[0], im.size[1], im.size[1]))
fp.write("{ currentfile buf readhexstring pop } bind\n") fp.write("{ currentfile buf readhexstring pop } bind\n")
fp.write("%s\n" % operator[2]) fp.write(operator[2] + "\n")
fp.flush()
ImageFile._save(im, fp, [("eps", (0,0)+im.size, 0, None)]) ImageFile._save(im, base_fp, [("eps", (0,0)+im.size, 0, None)])
fp.write("\n%%%%EndBinary\n") fp.write("\n%%%%EndBinary\n")
fp.write("grestore end\n") fp.write("grestore end\n")

View File

@ -9,7 +9,7 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import Image, ImageFile from . import Image, ImageFile
_handler = None _handler = None
@ -26,7 +26,7 @@ def register_handler(handler):
# Image adapter # Image adapter
def _accept(prefix): def _accept(prefix):
return prefix[:6] == "SIMPLE" return prefix[:6] == b"SIMPLE"
class FITSStubImageFile(ImageFile.StubImageFile): class FITSStubImageFile(ImageFile.StubImageFile):

View File

@ -18,15 +18,12 @@
__version__ = "0.2" __version__ = "0.2"
import Image, ImageFile, ImagePalette from . import Image, ImageFile, ImagePalette, _binary
import string
i8 = _binary.i8
def i16(c): i16 = _binary.i16le
return ord(c[0]) + (ord(c[1])<<8) i32 = _binary.i32le
o8 = _binary.o8
def i32(c):
return ord(c[0]) + (ord(c[1])<<8) + (ord(c[2])<<16) + (ord(c[3])<<24)
# #
# decoder # decoder
@ -51,7 +48,7 @@ class FliImageFile(ImageFile.ImageFile):
if not (magic in [0xAF11, 0xAF12] and if not (magic in [0xAF11, 0xAF12] and
i16(s[14:16]) in [0, 3] and # flags i16(s[14:16]) in [0, 3] and # flags
s[20:22] == '\x00\x00'): # reserved s[20:22] == '\x00\x00'): # reserved
raise SyntaxError, "not an FLI/FLC file" raise SyntaxError("not an FLI/FLC file")
# image characteristics # image characteristics
self.mode = "P" self.mode = "P"
@ -64,7 +61,7 @@ class FliImageFile(ImageFile.ImageFile):
self.info["duration"] = duration self.info["duration"] = duration
# look for palette # look for palette
palette = map(lambda a: (a,a,a), range(256)) palette = [(a,a,a) for a in range(256)]
s = self.fp.read(16) s = self.fp.read(16)
@ -83,8 +80,8 @@ class FliImageFile(ImageFile.ImageFile):
elif i16(s[4:6]) == 4: elif i16(s[4:6]) == 4:
self._palette(palette, 0) self._palette(palette, 0)
palette = map(lambda (r,g,b): chr(r)+chr(g)+chr(b), palette) palette = [o8(r)+o8(g)+o8(b) for (r,g,b) in palette]
self.palette = ImagePalette.raw("RGB", string.join(palette, "")) self.palette = ImagePalette.raw("RGB", b"".join(palette))
# set things up to decode first frame # set things up to decode first frame
self.frame = -1 self.frame = -1
@ -98,22 +95,22 @@ class FliImageFile(ImageFile.ImageFile):
i = 0 i = 0
for e in range(i16(self.fp.read(2))): for e in range(i16(self.fp.read(2))):
s = self.fp.read(2) s = self.fp.read(2)
i = i + ord(s[0]) i = i + i8(s[0])
n = ord(s[1]) n = i8(s[1])
if n == 0: if n == 0:
n = 256 n = 256
s = self.fp.read(n * 3) s = self.fp.read(n * 3)
for n in range(0, len(s), 3): for n in range(0, len(s), 3):
r = ord(s[n]) << shift r = i8(s[n]) << shift
g = ord(s[n+1]) << shift g = i8(s[n+1]) << shift
b = ord(s[n+2]) << shift b = i8(s[n+2]) << shift
palette[i] = (r, g, b) palette[i] = (r, g, b)
i = i + 1 i = i + 1
def seek(self, frame): def seek(self, frame):
if frame != self.frame + 1: if frame != self.frame + 1:
raise ValueError, "cannot seek to frame %d" % frame raise ValueError("cannot seek to frame %d" % frame)
self.frame = frame self.frame = frame
# move to next frame # move to next frame

View File

@ -15,7 +15,7 @@
# #
import os import os
import Image from . import Image, _binary
import marshal import marshal
@ -31,7 +31,7 @@ def puti16(fp, values):
for v in values: for v in values:
if v < 0: if v < 0:
v = v + 65536 v = v + 65536
fp.write(chr(v>>8&255) + chr(v&255)) fp.write(_binary.o16be(v))
## ##
# Base class for raster font file handlers. # Base class for raster font file handlers.
@ -106,9 +106,9 @@ class FontFile:
# font metrics # font metrics
fp = open(os.path.splitext(filename)[0] + ".pil", "wb") fp = open(os.path.splitext(filename)[0] + ".pil", "wb")
fp.write("PILfont\n") fp.write(b"PILfont\n")
fp.write(";;;;;;%d;\n" % self.ysize) # HACK!!! fp.write((";;;;;;%d;\n" % self.ysize).encode('ascii')) # HACK!!!
fp.write("DATA\n") fp.write(b"DATA\n")
for id in range(256): for id in range(256):
m = self.metrics[id] m = self.metrics[id]
if not m: if not m:
@ -128,13 +128,13 @@ class FontFile:
data = marshal.dumps((self.metrics, self.info)) data = marshal.dumps((self.metrics, self.info))
if zlib: if zlib:
data = "z" + zlib.compress(data, 9) data = b"z" + zlib.compress(data, 9)
else: else:
data = "u" + data data = b"u" + data
fp = open(os.path.splitext(filename)[0] + ".pil", "wb") fp = open(os.path.splitext(filename)[0] + ".pil", "wb")
fp.write("PILfont2\n" + self.name + "\n" + "DATA\n") fp.write(b"PILfont2\n" + self.name + "\n" + "DATA\n")
fp.write(data) fp.write(data)

View File

@ -19,8 +19,8 @@
__version__ = "0.1" __version__ = "0.1"
import Image, ImageFile from . import Image, ImageFile
from OleFileIO import * from .OleFileIO import *
# we map from colour field tuples to (mode, rawmode) descriptors # we map from colour field tuples to (mode, rawmode) descriptors
@ -60,10 +60,10 @@ class FpxImageFile(ImageFile.ImageFile):
try: try:
self.ole = OleFileIO(self.fp) self.ole = OleFileIO(self.fp)
except IOError: except IOError:
raise SyntaxError, "not an FPX file; invalid OLE file" raise SyntaxError("not an FPX file; invalid OLE file")
if self.ole.root.clsid != "56616700-C154-11CE-8553-00AA00A1F95B": if self.ole.root.clsid != "56616700-C154-11CE-8553-00AA00A1F95B":
raise SyntaxError, "not an FPX file; bad root CLSID" raise SyntaxError("not an FPX file; bad root CLSID")
self._open_index(1) self._open_index(1)
@ -108,7 +108,7 @@ class FpxImageFile(ImageFile.ImageFile):
self.jpeg = {} self.jpeg = {}
for i in range(256): for i in range(256):
id = 0x3000001|(i << 16) id = 0x3000001|(i << 16)
if prop.has_key(id): if id in prop:
self.jpeg[i] = prop[id] self.jpeg[i] = prop[id]
# print len(self.jpeg), "tables loaded" # print len(self.jpeg), "tables loaded"
@ -143,7 +143,7 @@ class FpxImageFile(ImageFile.ImageFile):
# print size, self.mode, self.rawmode # print size, self.mode, self.rawmode
if size != self.size: if size != self.size:
raise IOError, "subimage mismatch" raise IOError("subimage mismatch")
# get tile descriptors # get tile descriptors
fp.seek(28 + offset) fp.seek(28 + offset)
@ -170,8 +170,8 @@ class FpxImageFile(ImageFile.ImageFile):
elif compression == 2: elif compression == 2:
internal_color_conversion = ord(s[14]) internal_color_conversion = i8(s[14])
jpeg_tables = ord(s[15]) jpeg_tables = i8(s[15])
rawmode = self.rawmode rawmode = self.rawmode
if internal_color_conversion: if internal_color_conversion:
@ -198,7 +198,7 @@ class FpxImageFile(ImageFile.ImageFile):
self.tile_prefix = self.jpeg[jpeg_tables] self.tile_prefix = self.jpeg[jpeg_tables]
else: else:
raise IOError, "unknown/invalid compression" raise IOError("unknown/invalid compression")
x = x + xtile x = x + xtile
if x >= xsize: if x >= xsize:

View File

@ -13,10 +13,9 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import Image, ImageFile from . import Image, ImageFile, _binary
def i32(c): i32 = _binary.i32be
return ord(c[3]) + (ord(c[2])<<8) + (ord(c[1])<<16) + (ord(c[0])<<24L)
def _accept(prefix): def _accept(prefix):
return i32(prefix) >= 20 and i32(prefix[4:8]) == 1 return i32(prefix) >= 20 and i32(prefix[4:8]) == 1
@ -34,13 +33,13 @@ class GbrImageFile(ImageFile.ImageFile):
header_size = i32(self.fp.read(4)) header_size = i32(self.fp.read(4))
version = i32(self.fp.read(4)) version = i32(self.fp.read(4))
if header_size < 20 or version != 1: if header_size < 20 or version != 1:
raise SyntaxError, "not a GIMP brush" raise SyntaxError("not a GIMP brush")
width = i32(self.fp.read(4)) width = i32(self.fp.read(4))
height = i32(self.fp.read(4)) height = i32(self.fp.read(4))
bytes = i32(self.fp.read(4)) bytes = i32(self.fp.read(4))
if width <= 0 or height <= 0 or bytes != 1: if width <= 0 or height <= 0 or bytes != 1:
raise SyntaxError, "not a GIMP brush" raise SyntaxError("not a GIMP brush")
comment = self.fp.read(header_size - 20)[:-1] comment = self.fp.read(header_size - 20)[:-1]
@ -59,8 +58,8 @@ class GbrImageFile(ImageFile.ImageFile):
# create an image out of the brush data block # create an image out of the brush data block
self.im = Image.core.new(self.mode, self.size) self.im = Image.core.new(self.mode, self.size)
self.im.fromstring(self.data) self.im.frombytes(self.data)
self.data = "" self.data = b""
# #
# registry # registry

View File

@ -25,10 +25,15 @@
__version__ = "0.1" __version__ = "0.1"
import ImageFile, ImagePalette from . import ImageFile, ImagePalette, _binary
def i16(c): try:
return ord(c[1]) + (ord(c[0])<<8) import builtins
except ImportError:
import __builtin__
builtins = __builtin__
i16 = _binary.i16be
## ##
# Image plugin for the GD uncompressed format. Note that this format # Image plugin for the GD uncompressed format. Note that this format
@ -72,10 +77,9 @@ def open(fp, mode = "r"):
if mode != "r": if mode != "r":
raise ValueError("bad mode") raise ValueError("bad mode")
if type(fp) == type(""): if isinstance(fp, str):
import __builtin__
filename = fp filename = fp
fp = __builtin__.open(fp, "rb") fp = builtins.open(fp, "rb")
else: else:
filename = "" filename = ""

View File

@ -28,24 +28,23 @@
__version__ = "0.9" __version__ = "0.9"
import Image, ImageFile, ImagePalette from . import Image, ImageFile, ImagePalette, _binary
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Helpers # Helpers
def i16(c): i8 = _binary.i8
return ord(c[0]) + (ord(c[1])<<8) i16 = _binary.i16le
o8 = _binary.o8
def o16(i): o16 = _binary.o16le
return chr(i&255) + chr(i>>8&255)
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Identify/read GIF files # Identify/read GIF files
def _accept(prefix): def _accept(prefix):
return prefix[:6] in ["GIF87a", "GIF89a"] return prefix[:6] in [b"GIF87a", b"GIF89a"]
## ##
# Image plugin for GIF images. This plugin supports both GIF87 and # Image plugin for GIF images. This plugin supports both GIF87 and
@ -60,16 +59,16 @@ class GifImageFile(ImageFile.ImageFile):
def data(self): def data(self):
s = self.fp.read(1) s = self.fp.read(1)
if s and ord(s): if s and i8(s):
return self.fp.read(ord(s)) return self.fp.read(i8(s))
return None return None
def _open(self): def _open(self):
# Screen # Screen
s = self.fp.read(13) s = self.fp.read(13)
if s[:6] not in ["GIF87a", "GIF89a"]: if s[:6] not in [b"GIF87a", b"GIF89a"]:
raise SyntaxError, "not a GIF file" raise SyntaxError("not a GIF file")
self.info["version"] = s[:6] self.info["version"] = s[:6]
@ -77,17 +76,17 @@ class GifImageFile(ImageFile.ImageFile):
self.tile = [] self.tile = []
flags = ord(s[10]) flags = i8(s[10])
bits = (flags & 7) + 1 bits = (flags & 7) + 1
if flags & 128: if flags & 128:
# get global palette # get global palette
self.info["background"] = ord(s[11]) self.info["background"] = i8(s[11])
# check if palette contains colour indices # check if palette contains colour indices
p = self.fp.read(3<<bits) p = self.fp.read(3<<bits)
for i in range(0, len(p), 3): for i in range(0, len(p), 3):
if not (chr(i/3) == p[i] == p[i+1] == p[i+2]): if not (i//3 == i8(p[i]) == i8(p[i+1]) == i8(p[i+2])):
p = ImagePalette.raw("RGB", p) p = ImagePalette.raw("RGB", p)
self.global_palette = self.palette = p self.global_palette = self.palette = p
break break
@ -106,7 +105,7 @@ class GifImageFile(ImageFile.ImageFile):
self.__fp.seek(self.__rewind) self.__fp.seek(self.__rewind)
if frame != self.__frame + 1: if frame != self.__frame + 1:
raise ValueError, "cannot seek to frame %d" % frame raise ValueError("cannot seek to frame %d" % frame)
self.__frame = frame self.__frame = frame
self.tile = [] self.tile = []
@ -125,25 +124,25 @@ class GifImageFile(ImageFile.ImageFile):
self.palette = self.global_palette self.palette = self.global_palette
while 1: while True:
s = self.fp.read(1) s = self.fp.read(1)
if not s or s == ";": if not s or s == b";":
break break
elif s == "!": elif s == b"!":
# #
# extensions # extensions
# #
s = self.fp.read(1) s = self.fp.read(1)
block = self.data() block = self.data()
if ord(s) == 249: if i8(s) == 249:
# #
# graphic control extension # graphic control extension
# #
flags = ord(block[0]) flags = i8(block[0])
if flags & 1: if flags & 1:
self.info["transparency"] = ord(block[3]) self.info["transparency"] = i8(block[3])
self.info["duration"] = i16(block[1:3]) * 10 self.info["duration"] = i16(block[1:3]) * 10
try: try:
# disposal methods # disposal methods
@ -156,19 +155,19 @@ class GifImageFile(ImageFile.ImageFile):
self.dispose = self.im.copy() self.dispose = self.im.copy()
except (AttributeError, KeyError): except (AttributeError, KeyError):
pass pass
elif ord(s) == 255: elif i8(s) == 255:
# #
# application extension # application extension
# #
self.info["extension"] = block, self.fp.tell() self.info["extension"] = block, self.fp.tell()
if block[:11] == "NETSCAPE2.0": if block[:11] == b"NETSCAPE2.0":
block = self.data() block = self.data()
if len(block) >= 3 and ord(block[0]) == 1: if len(block) >= 3 and i8(block[0]) == 1:
self.info["loop"] = i16(block[1:3]) self.info["loop"] = i16(block[1:3])
while self.data(): while self.data():
pass pass
elif s == ",": elif s == b",":
# #
# local image # local image
# #
@ -177,7 +176,7 @@ class GifImageFile(ImageFile.ImageFile):
# extent # extent
x0, y0 = i16(s[0:]), i16(s[2:]) x0, y0 = i16(s[0:]), i16(s[2:])
x1, y1 = x0 + i16(s[4:]), y0 + i16(s[6:]) x1, y1 = x0 + i16(s[4:]), y0 + i16(s[6:])
flags = ord(s[8]) flags = i8(s[8])
interlace = (flags & 64) != 0 interlace = (flags & 64) != 0
@ -187,7 +186,7 @@ class GifImageFile(ImageFile.ImageFile):
ImagePalette.raw("RGB", self.fp.read(3<<bits)) ImagePalette.raw("RGB", self.fp.read(3<<bits))
# image data # image data
bits = ord(self.fp.read(1)) bits = i8(self.fp.read(1))
self.__offset = self.fp.tell() self.__offset = self.fp.tell()
self.tile = [("gif", self.tile = [("gif",
(x0, y0, x1, y1), (x0, y0, x1, y1),
@ -197,11 +196,11 @@ class GifImageFile(ImageFile.ImageFile):
else: else:
pass pass
# raise IOError, "illegal GIF tag `%x`" % ord(s) # raise IOError, "illegal GIF tag `%x`" % i8(s)
if not self.tile: if not self.tile:
# self.__fp = None # self.__fp = None
raise EOFError, "no more images in GIF file" raise EOFError("no more images in GIF file")
self.mode = "L" self.mode = "L"
if self.palette: if self.palette:
@ -272,29 +271,29 @@ def _save(im, fp, filename):
pass pass
else: else:
# transparency extension block # transparency extension block
fp.write("!" + fp.write(b"!" +
chr(249) + # extension intro o8(249) + # extension intro
chr(4) + # length o8(4) + # length
chr(1) + # transparency info present o8(1) + # transparency info present
o16(0) + # duration o16(0) + # duration
chr(int(transparency)) # transparency index o8(int(transparency)) # transparency index
+ chr(0)) + o8(0))
# local image header # local image header
fp.write("," + fp.write(b"," +
o16(0) + o16(0) + # bounding box o16(0) + o16(0) + # bounding box
o16(im.size[0]) + # size o16(im.size[0]) + # size
o16(im.size[1]) + o16(im.size[1]) +
chr(flags) + # flags o8(flags) + # flags
chr(8)) # bits o8(8)) # bits
imOut.encoderconfig = (8, interlace) imOut.encoderconfig = (8, interlace)
ImageFile._save(imOut, fp, [("gif", (0,0)+im.size, 0, rawmode)]) ImageFile._save(imOut, fp, [("gif", (0,0)+im.size, 0, rawmode)])
fp.write("\0") # end of image data fp.write(b"\0") # end of image data
fp.write(";") # end of file fp.write(b";") # end of file
try: try:
fp.flush() fp.flush()
@ -326,12 +325,12 @@ def getheader(im, info=None):
optimize = info and info.get("optimize", 0) optimize = info and info.get("optimize", 0)
s = [ s = [
"GIF87a" + # magic b"GIF87a" + # magic
o16(im.size[0]) + # size o16(im.size[0]) + # size
o16(im.size[1]) + o16(im.size[1]) +
chr(7 + 128) + # flags: bits + palette o8(7 + 128) + # flags: bits + palette
chr(0) + # background o8(0) + # background
chr(0) # reserved/aspect o8(0) # reserved/aspect
] ]
if optimize: if optimize:
@ -352,7 +351,7 @@ def getheader(im, info=None):
else: else:
# greyscale # greyscale
for i in range(maxcolor): for i in range(maxcolor):
s.append(chr(i) * 3) s.append(o8(i) * 3)
return s return s
@ -374,17 +373,17 @@ def getdata(im, offset = (0, 0), **params):
im.encoderinfo = params im.encoderinfo = params
# local image header # local image header
fp.write("," + fp.write(b"," +
o16(offset[0]) + # offset o16(offset[0]) + # offset
o16(offset[1]) + o16(offset[1]) +
o16(im.size[0]) + # size o16(im.size[0]) + # size
o16(im.size[1]) + o16(im.size[1]) +
chr(0) + # flags o8(0) + # flags
chr(8)) # bits o8(8)) # bits
ImageFile._save(im, fp, [("gif", (0,0)+im.size, 0, RAWMODE[im.mode])]) ImageFile._save(im, fp, [("gif", (0,0)+im.size, 0, RAWMODE[im.mode])])
fp.write("\0") # end of image data fp.write(b"\0") # end of image data
finally: finally:
del im.encoderinfo del im.encoderinfo

View File

@ -14,7 +14,7 @@
# #
from math import pi, log, sin, sqrt from math import pi, log, sin, sqrt
import string from ._binary import o8
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Stuff to translate curve segments to palette values (derived from # Stuff to translate curve segments to palette values (derived from
@ -79,15 +79,15 @@ class GradientFile:
scale = segment((xm - x0) / w, (x - x0) / w) scale = segment((xm - x0) / w, (x - x0) / w)
# expand to RGBA # expand to RGBA
r = chr(int(255 * ((rgb1[0] - rgb0[0]) * scale + rgb0[0]) + 0.5)) r = o8(int(255 * ((rgb1[0] - rgb0[0]) * scale + rgb0[0]) + 0.5))
g = chr(int(255 * ((rgb1[1] - rgb0[1]) * scale + rgb0[1]) + 0.5)) g = o8(int(255 * ((rgb1[1] - rgb0[1]) * scale + rgb0[1]) + 0.5))
b = chr(int(255 * ((rgb1[2] - rgb0[2]) * scale + rgb0[2]) + 0.5)) b = o8(int(255 * ((rgb1[2] - rgb0[2]) * scale + rgb0[2]) + 0.5))
a = chr(int(255 * ((rgb1[3] - rgb0[3]) * scale + rgb0[3]) + 0.5)) a = o8(int(255 * ((rgb1[3] - rgb0[3]) * scale + rgb0[3]) + 0.5))
# add to palette # add to palette
palette.append(r + g + b + a) palette.append(r + g + b + a)
return string.join(palette, ""), "RGBA" return b"".join(palette), "RGBA"
## ##
# File handler for GIMP's gradient format. # File handler for GIMP's gradient format.
@ -96,8 +96,8 @@ class GimpGradientFile(GradientFile):
def __init__(self, fp): def __init__(self, fp):
if fp.readline()[:13] != "GIMP Gradient": if fp.readline()[:13] != b"GIMP Gradient":
raise SyntaxError, "not a GIMP gradient file" raise SyntaxError("not a GIMP gradient file")
count = int(fp.readline()) count = int(fp.readline())
@ -105,8 +105,8 @@ class GimpGradientFile(GradientFile):
for i in range(count): for i in range(count):
s = string.split(fp.readline()) s = fp.readline().split()
w = map(float, s[:11]) w = [float(x) for x in s[:11]]
x0, x1 = w[0], w[2] x0, x1 = w[0], w[2]
xm = w[1] xm = w[1]
@ -117,7 +117,7 @@ class GimpGradientFile(GradientFile):
cspace = int(s[12]) cspace = int(s[12])
if cspace != 0: if cspace != 0:
raise IOError, "cannot handle HSV colour space" raise IOError("cannot handle HSV colour space")
gradient.append((x0, x1, xm, rgb0, rgb1, segment)) gradient.append((x0, x1, xm, rgb0, rgb1, segment))

View File

@ -14,7 +14,8 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import re, string import re
from ._binary import o8
## ##
# File handler for GIMP's palette format. # File handler for GIMP's palette format.
@ -25,10 +26,10 @@ class GimpPaletteFile:
def __init__(self, fp): def __init__(self, fp):
self.palette = map(lambda i: chr(i)*3, range(256)) self.palette = [o8(i)*3 for i in range(256)]
if fp.readline()[:12] != "GIMP Palette": if fp.readline()[:12] != b"GIMP Palette":
raise SyntaxError, "not a GIMP palette file" raise SyntaxError("not a GIMP palette file")
i = 0 i = 0
@ -39,21 +40,21 @@ class GimpPaletteFile:
if not s: if not s:
break break
# skip fields and comment lines # skip fields and comment lines
if re.match("\w+:|#", s): if re.match(b"\w+:|#", s):
continue continue
if len(s) > 100: if len(s) > 100:
raise SyntaxError, "bad palette file" raise SyntaxError("bad palette file")
v = tuple(map(int, string.split(s)[:3])) v = tuple(map(int, s.split()[:3]))
if len(v) != 3: if len(v) != 3:
raise ValueError, "bad palette entry" raise ValueError("bad palette entry")
if 0 <= i <= 255: if 0 <= i <= 255:
self.palette[i] = chr(v[0]) + chr(v[1]) + chr(v[2]) self.palette[i] = o8(v[0]) + o8(v[1]) + o8(v[2])
i = i + 1 i = i + 1
self.palette = string.join(self.palette, "") self.palette = b"".join(self.palette)
def getpalette(self): def getpalette(self):

View File

@ -9,7 +9,7 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import Image, ImageFile from . import Image, ImageFile
_handler = None _handler = None
@ -26,7 +26,7 @@ def register_handler(handler):
# Image adapter # Image adapter
def _accept(prefix): def _accept(prefix):
return prefix[0:4] == "GRIB" and prefix[7] == chr(1) return prefix[0:4] == b"GRIB" and prefix[7] == b'\x01'
class GribStubImageFile(ImageFile.StubImageFile): class GribStubImageFile(ImageFile.StubImageFile):

View File

@ -9,7 +9,7 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import Image, ImageFile from . import Image, ImageFile
_handler = None _handler = None
@ -26,7 +26,7 @@ def register_handler(handler):
# Image adapter # Image adapter
def _accept(prefix): def _accept(prefix):
return prefix[:8] == "\x89HDF\r\n\x1a\n" return prefix[:8] == b"\x89HDF\r\n\x1a\n"
class HDF5StubImageFile(ImageFile.StubImageFile): class HDF5StubImageFile(ImageFile.StubImageFile):

View File

@ -14,27 +14,31 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import Image, ImageFile from . import Image, ImageFile, _binary
import string, struct import struct
i8 = _binary.i8
HEADERSIZE = 8 HEADERSIZE = 8
def nextheader(fobj): def nextheader(fobj):
return struct.unpack('>4sI', fobj.read(HEADERSIZE)) return struct.unpack('>4sI', fobj.read(HEADERSIZE))
def read_32t(fobj, (start, length), (width, height)): def read_32t(fobj, start_length, size):
# The 128x128 icon seems to have an extra header for some reason. # The 128x128 icon seems to have an extra header for some reason.
(start, length) = start_length
fobj.seek(start) fobj.seek(start)
sig = fobj.read(4) sig = fobj.read(4)
if sig != '\x00\x00\x00\x00': if sig != b'\x00\x00\x00\x00':
raise SyntaxError, 'Unknown signature, expecting 0x00000000' raise SyntaxError('Unknown signature, expecting 0x00000000')
return read_32(fobj, (start + 4, length - 4), (width, height)) return read_32(fobj, (start + 4, length - 4), size)
def read_32(fobj, (start, length), size): def read_32(fobj, start_length, size):
""" """
Read a 32bit RGB icon resource. Seems to be either uncompressed or Read a 32bit RGB icon resource. Seems to be either uncompressed or
an RLE packbits-like scheme. an RLE packbits-like scheme.
""" """
(start, length) = start_length
fobj.seek(start) fobj.seek(start)
sizesq = size[0] * size[1] sizesq = size[0] * size[1]
if length == sizesq * 3: if length == sizesq * 3:
@ -51,7 +55,7 @@ def read_32(fobj, (start, length), size):
byte = fobj.read(1) byte = fobj.read(1)
if not byte: if not byte:
break break
byte = ord(byte) byte = i8(byte)
if byte & 0x80: if byte & 0x80:
blocksize = byte - 125 blocksize = byte - 125
byte = fobj.read(1) byte = fobj.read(1)
@ -68,13 +72,14 @@ def read_32(fobj, (start, length), size):
"Error reading channel [%r left]" % bytesleft "Error reading channel [%r left]" % bytesleft
) )
band = Image.frombuffer( band = Image.frombuffer(
"L", size, string.join(data, ""), "raw", "L", 0, 1 "L", size, b"".join(data), "raw", "L", 0, 1
) )
im.im.putband(band.im, band_ix) im.im.putband(band.im, band_ix)
return {"RGB": im} return {"RGB": im}
def read_mk(fobj, (start, length), size): def read_mk(fobj, start_length, size):
# Alpha masks seem to be uncompressed # Alpha masks seem to be uncompressed
(start, length) = start_length
fobj.seek(start) fobj.seek(start)
band = Image.frombuffer( band = Image.frombuffer(
"L", size, fobj.read(size[0]*size[1]), "raw", "L", 0, 1 "L", size, fobj.read(size[0]*size[1]), "raw", "L", 0, 1
@ -85,20 +90,20 @@ class IcnsFile:
SIZES = { SIZES = {
(128, 128): [ (128, 128): [
('it32', read_32t), (b'it32', read_32t),
('t8mk', read_mk), (b't8mk', read_mk),
], ],
(48, 48): [ (48, 48): [
('ih32', read_32), (b'ih32', read_32),
('h8mk', read_mk), (b'h8mk', read_mk),
], ],
(32, 32): [ (32, 32): [
('il32', read_32), (b'il32', read_32),
('l8mk', read_mk), (b'l8mk', read_mk),
], ],
(16, 16): [ (16, 16): [
('is32', read_32), (b'is32', read_32),
('s8mk', read_mk), (b's8mk', read_mk),
], ],
} }
@ -111,7 +116,7 @@ class IcnsFile:
self.fobj = fobj self.fobj = fobj
sig, filesize = nextheader(fobj) sig, filesize = nextheader(fobj)
if sig != 'icns': if sig != 'icns':
raise SyntaxError, 'not an icns file' raise SyntaxError('not an icns file')
i = HEADERSIZE i = HEADERSIZE
while i < filesize: while i < filesize:
sig, blocksize = nextheader(fobj) sig, blocksize = nextheader(fobj)
@ -125,7 +130,7 @@ class IcnsFile:
sizes = [] sizes = []
for size, fmts in self.SIZES.items(): for size, fmts in self.SIZES.items():
for (fmt, reader) in fmts: for (fmt, reader) in fmts:
if self.dct.has_key(fmt): if fmt in self.dct:
sizes.append(size) sizes.append(size)
break break
return sizes return sizes
@ -133,7 +138,7 @@ class IcnsFile:
def bestsize(self): def bestsize(self):
sizes = self.itersizes() sizes = self.itersizes()
if not sizes: if not sizes:
raise SyntaxError, "No 32bit icon resources found" raise SyntaxError("No 32bit icon resources found")
return max(sizes) return max(sizes)
def dataforsize(self, size): def dataforsize(self, size):
@ -201,7 +206,7 @@ class IcnsImageFile(ImageFile.ImageFile):
self.load_end() self.load_end()
Image.register_open("ICNS", IcnsImageFile, lambda x: x[:4] == 'icns') Image.register_open("ICNS", IcnsImageFile, lambda x: x[:4] == b'icns')
Image.register_extension("ICNS", '.icns') Image.register_extension("ICNS", '.icns')
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -19,21 +19,19 @@
__version__ = "0.1" __version__ = "0.1"
import Image, BmpImagePlugin from . import Image, BmpImagePlugin, _binary
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
def i16(c): i8 = _binary.i8
return ord(c[0]) + (ord(c[1])<<8) i16 = _binary.i16le
i32 = _binary.i32le
def i32(c):
return ord(c[0]) + (ord(c[1])<<8) + (ord(c[2])<<16) + (ord(c[3])<<24)
def _accept(prefix): def _accept(prefix):
return prefix[:4] == "\0\0\1\0" return prefix[:4] == b"\0\0\1\0"
## ##
# Image plugin for Windows Icon files. # Image plugin for Windows Icon files.
@ -48,20 +46,20 @@ class IcoImageFile(BmpImagePlugin.BmpImageFile):
# check magic # check magic
s = self.fp.read(6) s = self.fp.read(6)
if not _accept(s): if not _accept(s):
raise SyntaxError, "not an ICO file" raise SyntaxError("not an ICO file")
# pick the largest icon in the file # pick the largest icon in the file
m = "" m = b""
for i in range(i16(s[4:])): for i in range(i16(s[4:])):
s = self.fp.read(16) s = self.fp.read(16)
if not m: if not m:
m = s m = s
elif ord(s[0]) > ord(m[0]) and ord(s[1]) > ord(m[1]): elif i8(s[0]) > i8(m[0]) and i8(s[1]) > i8(m[1]):
m = s m = s
#print "width", ord(s[0]) #print "width", i8(s[0])
#print "height", ord(s[1]) #print "height", i8(s[1])
#print "colors", ord(s[2]) #print "colors", i8(s[2])
#print "reserved", ord(s[3]) #print "reserved", i8(s[3])
#print "planes", i16(s[4:]) #print "planes", i16(s[4:])
#print "bitcount", i16(s[6:]) #print "bitcount", i16(s[6:])
#print "bytes", i32(s[8:]) #print "bytes", i32(s[8:])
@ -71,7 +69,7 @@ class IcoImageFile(BmpImagePlugin.BmpImageFile):
self._bitmap(i32(m[12:])) self._bitmap(i32(m[12:]))
# patch up the bitmap height # patch up the bitmap height
self.size = self.size[0], self.size[1]/2 self.size = self.size[0], self.size[1]//2
d, e, o, a = self.tile[0] d, e, o, a = self.tile[0]
self.tile[0] = d, (0,0)+self.size, o, a self.tile[0] = d, (0,0)+self.size, o, a

View File

@ -28,8 +28,9 @@
__version__ = "0.7" __version__ = "0.7"
import re, string import re
import Image, ImageFile, ImagePalette from . import Image, ImageFile, ImagePalette
from ._binary import i8, o8
# -------------------------------------------------------------------- # --------------------------------------------------------------------
@ -91,7 +92,7 @@ for i in range(2, 33):
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Read IM directory # Read IM directory
split = re.compile(r"^([A-Za-z][^:]*):[ \t]*(.*)[ \t]*$") split = re.compile(br"^([A-Za-z][^:]*):[ \t]*(.*)[ \t]*$")
def number(s): def number(s):
try: try:
@ -112,8 +113,8 @@ class ImImageFile(ImageFile.ImageFile):
# Quick rejection: if there's not an LF among the first # Quick rejection: if there's not an LF among the first
# 100 bytes, this is (probably) not a text header. # 100 bytes, this is (probably) not a text header.
if not "\n" in self.fp.read(100): if not b"\n" in self.fp.read(100):
raise SyntaxError, "not an IM file" raise SyntaxError("not an IM file")
self.fp.seek(0) self.fp.seek(0)
n = 0 n = 0
@ -125,91 +126,96 @@ class ImImageFile(ImageFile.ImageFile):
self.rawmode = "L" self.rawmode = "L"
while 1: while True:
s = self.fp.read(1) s = self.fp.read(1)
# Some versions of IFUNC uses \n\r instead of \r\n... # Some versions of IFUNC uses \n\r instead of \r\n...
if s == "\r": if s == b"\r":
continue continue
if not s or s[0] == chr(0) or s[0] == chr(26): if not s or s == b'\0' or s == b'\x1A':
break break
# FIXME: this may read whole file if not a text file # FIXME: this may read whole file if not a text file
s = s + self.fp.readline() s = s + self.fp.readline()
if len(s) > 100: if len(s) > 100:
raise SyntaxError, "not an IM file" raise SyntaxError("not an IM file")
if s[-2:] == '\r\n': if s[-2:] == b'\r\n':
s = s[:-2] s = s[:-2]
elif s[-1:] == '\n': elif s[-1:] == b'\n':
s = s[:-1] s = s[:-1]
try: try:
m = split.match(s) m = split.match(s)
except re.error, v: except re.error as v:
raise SyntaxError, "not an IM file" raise SyntaxError("not an IM file")
if m: if m:
k, v = m.group(1,2) k, v = m.group(1,2)
# Don't know if this is the correct encoding, but a decent guess
# (I guess)
k = k.decode('latin-1', 'replace')
v = v.decode('latin-1', 'replace')
# Convert value as appropriate # Convert value as appropriate
if k in [FRAMES, SCALE, SIZE]: if k in [FRAMES, SCALE, SIZE]:
v = string.replace(v, "*", ",") v = v.replace("*", ",")
v = tuple(map(number, string.split(v, ","))) v = tuple(map(number, v.split(",")))
if len(v) == 1: if len(v) == 1:
v = v[0] v = v[0]
elif k == MODE and OPEN.has_key(v): elif k == MODE and v in OPEN:
v, self.rawmode = OPEN[v] v, self.rawmode = OPEN[v]
# Add to dictionary. Note that COMMENT tags are # Add to dictionary. Note that COMMENT tags are
# combined into a list of strings. # combined into a list of strings.
if k == COMMENT: if k == COMMENT:
if self.info.has_key(k): if k in self.info:
self.info[k].append(v) self.info[k].append(v)
else: else:
self.info[k] = [v] self.info[k] = [v]
else: else:
self.info[k] = v self.info[k] = v
if TAGS.has_key(k): if k in TAGS:
n = n + 1 n = n + 1
else: else:
raise SyntaxError, "Syntax error in IM header: " + s raise SyntaxError("Syntax error in IM header: " + s.decode('ascii', 'replace'))
if not n: if not n:
raise SyntaxError, "Not an IM file" raise SyntaxError("Not an IM file")
# Basic attributes # Basic attributes
self.size = self.info[SIZE] self.size = self.info[SIZE]
self.mode = self.info[MODE] self.mode = self.info[MODE]
# Skip forward to start of image data # Skip forward to start of image data
while s and s[0] != chr(26): while s and s[0:1] != b'\x1A':
s = self.fp.read(1) s = self.fp.read(1)
if not s: if not s:
raise SyntaxError, "File truncated" raise SyntaxError("File truncated")
if self.info.has_key(LUT): if LUT in self.info:
# convert lookup table to palette or lut attribute # convert lookup table to palette or lut attribute
palette = self.fp.read(768) palette = self.fp.read(768)
greyscale = 1 # greyscale palette greyscale = 1 # greyscale palette
linear = 1 # linear greyscale palette linear = 1 # linear greyscale palette
for i in range(256): for i in range(256):
if palette[i] == palette[i+256] == palette[i+512]: if palette[i] == palette[i+256] == palette[i+512]:
if palette[i] != chr(i): if i8(palette[i]) != i:
linear = 0 linear = 0
else: else:
greyscale = 0 greyscale = 0
if self.mode == "L" or self.mode == "LA": if self.mode == "L" or self.mode == "LA":
if greyscale: if greyscale:
if not linear: if not linear:
self.lut = map(ord, palette[:256]) self.lut = [i8(c) for c in palette[:256]]
else: else:
if self.mode == "L": if self.mode == "L":
self.mode = self.rawmode = "P" self.mode = self.rawmode = "P"
@ -218,7 +224,7 @@ class ImImageFile(ImageFile.ImageFile):
self.palette = ImagePalette.raw("RGB;L", palette) self.palette = ImagePalette.raw("RGB;L", palette)
elif self.mode == "RGB": elif self.mode == "RGB":
if not greyscale or not linear: if not greyscale or not linear:
self.lut = map(ord, palette) self.lut = [i8(c) for c in palette]
self.frame = 0 self.frame = 0
@ -253,7 +259,7 @@ class ImImageFile(ImageFile.ImageFile):
def seek(self, frame): def seek(self, frame):
if frame < 0 or frame >= self.info[FRAMES]: if frame < 0 or frame >= self.info[FRAMES]:
raise EOFError, "seek outside sequence" raise EOFError("seek outside sequence")
if self.frame == frame: if self.frame == frame:
return return
@ -265,7 +271,7 @@ class ImImageFile(ImageFile.ImageFile):
else: else:
bits = 8 * len(self.mode) bits = 8 * len(self.mode)
size = ((self.size[0] * bits + 7) / 8) * self.size[1] size = ((self.size[0] * bits + 7) // 8) * self.size[1]
offs = self.__offset + frame * size offs = self.__offset + frame * size
self.fp = self.__fp self.fp = self.__fp
@ -304,7 +310,7 @@ def _save(im, fp, filename, check=0):
try: try:
type, rawmode = SAVE[im.mode] type, rawmode = SAVE[im.mode]
except KeyError: except KeyError:
raise ValueError, "Cannot save %s images as IM" % im.mode raise ValueError("Cannot save %s images as IM" % im.mode)
try: try:
frames = im.encoderinfo["frames"] frames = im.encoderinfo["frames"]
@ -314,14 +320,14 @@ def _save(im, fp, filename, check=0):
if check: if check:
return check return check
fp.write("Image type: %s image\r\n" % type) fp.write(("Image type: %s image\r\n" % type).encode('ascii'))
if filename: if filename:
fp.write("Name: %s\r\n" % filename) fp.write(("Name: %s\r\n" % filename).encode('ascii'))
fp.write("Image size (x*y): %d*%d\r\n" % im.size) fp.write(("Image size (x*y): %d*%d\r\n" % im.size).encode('ascii'))
fp.write("File size (no of images): %d\r\n" % frames) fp.write(("File size (no of images): %d\r\n" % frames).encode('ascii'))
if im.mode == "P": if im.mode == "P":
fp.write("Lut: 1\r\n") fp.write(b"Lut: 1\r\n")
fp.write("\000" * (511-fp.tell()) + "\032") fp.write(b"\000" * (511-fp.tell()) + b"\032")
if im.mode == "P": if im.mode == "P":
fp.write(im.im.getpalette("RGB", "RGB;L")) # 768 bytes fp.write(im.im.getpalette("RGB", "RGB;L")) # 768 bytes
ImageFile._save(im, fp, [("raw", (0,0)+im.size, 0, (rawmode, 0, -1))]) ImageFile._save(im, fp, [("raw", (0,0)+im.size, 0, (rawmode, 0, -1))])

View File

@ -24,6 +24,8 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
from __future__ import print_function
VERSION = "1.1.7" VERSION = "1.1.7"
try: try:
@ -52,7 +54,7 @@ try:
# them. Note that other modules should not refer to _imaging # them. Note that other modules should not refer to _imaging
# directly; import Image and use the Image.core variable instead. # directly; import Image and use the Image.core variable instead.
import _imaging as core import _imaging as core
except ImportError, v: except ImportError as v:
core = _imaging_not_installed() core = _imaging_not_installed()
if str(v)[:20] == "Module use of python" and warnings: if str(v)[:20] == "Module use of python" and warnings:
# The _imaging C module is present, but not compiled for # The _imaging C module is present, but not compiled for
@ -64,31 +66,27 @@ except ImportError, v:
RuntimeWarning RuntimeWarning
) )
import ImageMode try:
import ImagePalette import builtins
except ImportError:
import __builtin__
builtins = __builtin__
import os, string, sys from . import ImageMode
from ._binary import i8, o8
import os, sys
# type stuff # type stuff
from types import IntType, StringType, TupleType import collections
import numbers
try: if bytes is str:
UnicodeStringType = type(unicode(""))
##
# (Internal) Checks if an object is a string. If the current
# Python version supports Unicode, this checks for both 8-bit
# and Unicode strings.
def isStringType(t): def isStringType(t):
return isinstance(t, StringType) or isinstance(t, UnicodeStringType) return isinstance(t, basestring)
except NameError: else:
def isStringType(t): def isStringType(t):
return isinstance(t, StringType) return isinstance(t, str)
##
# (Internal) Checks if an object is a tuple.
def isTupleType(t):
return isinstance(t, TupleType)
## ##
# (Internal) Checks if an object is an image object. # (Internal) Checks if an object is an image object.
@ -103,8 +101,6 @@ def isImageType(t):
def isDirectory(f): def isDirectory(f):
return isStringType(f) and os.path.isdir(f) return isStringType(f) and os.path.isdir(f)
from operator import isNumberType, isSequenceType
# #
# Debug level # Debug level
@ -186,16 +182,7 @@ _MODEINFO = {
} }
try: if sys.byteorder == 'little':
byteorder = sys.byteorder
except AttributeError:
import struct
if struct.unpack("h", "\0\1")[0] == 1:
byteorder = "big"
else:
byteorder = "little"
if byteorder == 'little':
_ENDIAN = '<' _ENDIAN = '<'
else: else:
_ENDIAN = '>' _ENDIAN = '>'
@ -223,8 +210,7 @@ def _conv_type_shape(im):
return shape+(extra,), typ return shape+(extra,), typ
MODES = _MODEINFO.keys() MODES = sorted(_MODEINFO.keys())
MODES.sort()
# raw modes that may be memory mapped. NOTE: if you change this, you # raw modes that may be memory mapped. NOTE: if you change this, you
# may have to modify the stride calculation in map.c too! # may have to modify the stride calculation in map.c too!
@ -293,23 +279,23 @@ def preinit():
return return
try: try:
import BmpImagePlugin from . import BmpImagePlugin
except ImportError: except ImportError:
pass pass
try: try:
import GifImagePlugin from . import GifImagePlugin
except ImportError: except ImportError:
pass pass
try: try:
import JpegImagePlugin from . import JpegImagePlugin
except ImportError: except ImportError:
pass pass
try: try:
import PpmImagePlugin from . import PpmImagePlugin
except ImportError: except ImportError:
pass pass
try: try:
import PngImagePlugin from . import PngImagePlugin
except ImportError: except ImportError:
pass pass
# try: # try:
@ -342,7 +328,7 @@ def init():
# only check directories (including current, if present in the path) # only check directories (including current, if present in the path)
for directory in filter(isDirectory, directories): for directory in filter(isDirectory, directories):
fullpath = os.path.abspath(directory) fullpath = os.path.abspath(directory)
if visited.has_key(fullpath): if fullpath in visited:
continue continue
for file in os.listdir(directory): for file in os.listdir(directory):
if file[-14:] == "ImagePlugin.py": if file[-14:] == "ImagePlugin.py":
@ -355,8 +341,8 @@ def init():
del sys.path[0] del sys.path[0]
except ImportError: except ImportError:
if DEBUG: if DEBUG:
print "Image: failed to import", print("Image: failed to import", end=' ')
print f, ":", sys.exc_value print(f, ":", sys.exc_info()[1])
visited[fullpath] = None visited[fullpath] = None
if OPEN or SAVE: if OPEN or SAVE:
@ -364,21 +350,21 @@ def init():
return 1 return 1
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Codec factories (used by tostring/fromstring and ImageFile.load) # Codec factories (used by tobytes/frombytes and ImageFile.load)
def _getdecoder(mode, decoder_name, args, extra=()): def _getdecoder(mode, decoder_name, args, extra=()):
# tweak arguments # tweak arguments
if args is None: if args is None:
args = () args = ()
elif not isTupleType(args): elif not isinstance(args, tuple):
args = (args,) args = (args,)
try: try:
# get decoder # get decoder
decoder = getattr(core, decoder_name + "_decoder") decoder = getattr(core, decoder_name + "_decoder")
# print decoder, (mode,) + args + extra # print(decoder, mode, args + extra)
return apply(decoder, (mode,) + args + extra) return decoder(mode, *args + extra)
except AttributeError: except AttributeError:
raise IOError("decoder %s not available" % decoder_name) raise IOError("decoder %s not available" % decoder_name)
@ -387,14 +373,14 @@ def _getencoder(mode, encoder_name, args, extra=()):
# tweak arguments # tweak arguments
if args is None: if args is None:
args = () args = ()
elif not isTupleType(args): elif not isinstance(args, tuple):
args = (args,) args = (args,)
try: try:
# get encoder # get encoder
encoder = getattr(core, encoder_name + "_encoder") encoder = getattr(core, encoder_name + "_encoder")
# print encoder, (mode,) + args + extra # print(encoder, mode, args + extra)
return apply(encoder, (mode,) + args + extra) return encoder(mode, *args + extra)
except AttributeError: except AttributeError:
raise IOError("encoder %s not available" % encoder_name) raise IOError("encoder %s not available" % encoder_name)
@ -402,26 +388,31 @@ def _getencoder(mode, encoder_name, args, extra=()):
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Simple expression analyzer # Simple expression analyzer
def coerce_e(value):
return value if isinstance(value, _E) else _E(value)
class _E: class _E:
def __init__(self, data): self.data = data def __init__(self, data):
def __coerce__(self, other): return self, _E(other) self.data = data
def __add__(self, other): return _E((self.data, "__add__", other.data)) def __add__(self, other):
def __mul__(self, other): return _E((self.data, "__mul__", other.data)) return _E((self.data, "__add__", coerce_e(other).data))
def __mul__(self, other):
return _E((self.data, "__mul__", coerce_e(other).data))
def _getscaleoffset(expr): def _getscaleoffset(expr):
stub = ["stub"] stub = ["stub"]
data = expr(_E(stub)).data data = expr(_E(stub)).data
try: try:
(a, b, c) = data # simplified syntax (a, b, c) = data # simplified syntax
if (a is stub and b == "__mul__" and isNumberType(c)): if (a is stub and b == "__mul__" and isinstance(c, numbers.Number)):
return c, 0.0 return c, 0.0
if (a is stub and b == "__add__" and isNumberType(c)): if (a is stub and b == "__add__" and isinstance(c, numbers.Number)):
return 1.0, c return 1.0, c
except TypeError: pass except TypeError: pass
try: try:
((a, b, c), d, e) = data # full syntax ((a, b, c), d, e) = data # full syntax
if (a is stub and b == "__mul__" and isNumberType(c) and if (a is stub and b == "__mul__" and isinstance(c, numbers.Number) and
d == "__add__" and isNumberType(e)): d == "__add__" and isinstance(e, numbers.Number)):
return c, e return c, e
except TypeError: pass except TypeError: pass
raise ValueError("illegal expression") raise ValueError("illegal expression")
@ -437,7 +428,7 @@ def _getscaleoffset(expr):
# #
# @see #open # @see #open
# @see #new # @see #new
# @see #fromstring # @see #frombytes
class Image: class Image:
@ -462,6 +453,7 @@ class Image:
new.size = im.size new.size = im.size
new.palette = self.palette new.palette = self.palette
if im.mode == "P": if im.mode == "P":
from . import ImagePalette
new.palette = ImagePalette.ImagePalette() new.palette = ImagePalette.ImagePalette()
try: try:
new.info = self.info.copy() new.info = self.info.copy()
@ -505,7 +497,7 @@ class Image:
shape, typestr = _conv_type_shape(self) shape, typestr = _conv_type_shape(self)
new['shape'] = shape new['shape'] = shape
new['typestr'] = typestr new['typestr'] = typestr
new['data'] = self.tostring() new['data'] = self.tobytes()
return new return new
raise AttributeError(name) raise AttributeError(name)
@ -515,13 +507,13 @@ class Image:
# @param encoder_name What encoder to use. The default is to # @param encoder_name What encoder to use. The default is to
# use the standard "raw" encoder. # use the standard "raw" encoder.
# @param *args Extra arguments to the encoder. # @param *args Extra arguments to the encoder.
# @return An 8-bit string. # @return A bytes object.
def tostring(self, encoder_name="raw", *args): def tobytes(self, encoder_name="raw", *args):
"Return image as a binary string" "Return image as a bytes object"
# may pass tuple instead of argument list # may pass tuple instead of argument list
if len(args) == 1 and isTupleType(args[0]): if len(args) == 1 and isinstance(args[0], tuple):
args = args[0] args = args[0]
if encoder_name == "raw" and args == (): if encoder_name == "raw" and args == ():
@ -536,15 +528,21 @@ class Image:
bufsize = max(65536, self.size[0] * 4) # see RawEncode.c bufsize = max(65536, self.size[0] * 4) # see RawEncode.c
data = [] data = []
while 1: while True:
l, s, d = e.encode(bufsize) l, s, d = e.encode(bufsize)
data.append(d) data.append(d)
if s: if s:
break break
if s < 0: if s < 0:
raise RuntimeError("encoder error %d in tostring" % s) raise RuntimeError("encoder error %d in tobytes" % s)
return string.join(data, "") return b"".join(data)
if bytes is str:
# Declare tostring as alias to tobytes
def tostring(self, *args, **kw):
warnings.warn('tostring() is deprecated. Please call tobytes() instead.', DeprecationWarning)
return self.tobytes(*args, **kw)
## ##
# Returns the image converted to an X11 bitmap. This method # Returns the image converted to an X11 bitmap. This method
@ -560,23 +558,23 @@ class Image:
self.load() self.load()
if self.mode != "1": if self.mode != "1":
raise ValueError("not a bitmap") raise ValueError("not a bitmap")
data = self.tostring("xbm") data = self.tobytes("xbm")
return string.join(["#define %s_width %d\n" % (name, self.size[0]), return b"".join([("#define %s_width %d\n" % (name, self.size[0])).encode('ascii'),
"#define %s_height %d\n"% (name, self.size[1]), ("#define %s_height %d\n"% (name, self.size[1])).encode('ascii'),
"static char %s_bits[] = {\n" % name, data, "};"], "") ("static char %s_bits[] = {\n" % name).encode('ascii'), data, b"};"])
## ##
# Loads this image with pixel data from a string. # Loads this image with pixel data from a bytes object.
# <p> # <p>
# This method is similar to the {@link #fromstring} function, but # This method is similar to the {@link #frombytes} function, but
# loads data into this image instead of creating a new image # loads data into this image instead of creating a new image
# object. # object.
def fromstring(self, data, decoder_name="raw", *args): def frombytes(self, data, decoder_name="raw", *args):
"Load data to image from binary string" "Load data to image from a bytes object"
# may pass tuple instead of argument list # may pass tuple instead of argument list
if len(args) == 1 and isTupleType(args[0]): if len(args) == 1 and isinstance(args[0], tuple):
args = args[0] args = args[0]
# default format # default format
@ -593,6 +591,12 @@ class Image:
if s[1] != 0: if s[1] != 0:
raise ValueError("cannot decode image data") raise ValueError("cannot decode image data")
if bytes is str:
# Declare fromstring as alias to frombytes
def fromstring(self, *args, **kw):
warnings.warn('fromstring() is deprecated. Please call frombytes() instead.', DeprecationWarning)
return self.frombytes(*args, **kw)
## ##
# Allocates storage for the image and loads the pixel data. In # Allocates storage for the image and loads the pixel data. In
# normal cases, you don't need to call this method, since the # normal cases, you don't need to call this method, since the
@ -605,11 +609,11 @@ class Image:
"Explicitly load pixel data." "Explicitly load pixel data."
if self.im and self.palette and self.palette.dirty: if self.im and self.palette and self.palette.dirty:
# realize palette # realize palette
apply(self.im.putpalette, self.palette.getdata()) self.im.putpalette(*self.palette.getdata())
self.palette.dirty = 0 self.palette.dirty = 0
self.palette.mode = "RGB" self.palette.mode = "RGB"
self.palette.rawmode = None self.palette.rawmode = None
if self.info.has_key("transparency"): if "transparency" in self.info:
self.im.putpalettealpha(self.info["transparency"], 0) self.im.putpalettealpha(self.info["transparency"], 0)
self.palette.mode = "RGBA" self.palette.mode = "RGBA"
if self.im: if self.im:
@ -802,7 +806,7 @@ class Image:
self.load() self.load()
if callable(filter): if isinstance(filter, collections.Callable):
filter = filter() filter = filter()
if not hasattr(filter, "filter"): if not hasattr(filter, "filter"):
raise TypeError("filter argument should be ImageFilter.Filter instance or class") raise TypeError("filter argument should be ImageFilter.Filter instance or class")
@ -907,12 +911,12 @@ class Image:
return self.im.getextrema() return self.im.getextrema()
## ##
# Returns a PyCObject that points to the internal image memory. # Returns a capsule that points to the internal image memory.
# #
# @return A PyCObject object. # @return A capsule object.
def getim(self): def getim(self):
"Get PyCObject pointer to internal image memory" "Get capsule pointer to internal image memory"
self.load() self.load()
return self.im.ptr return self.im.ptr
@ -929,7 +933,10 @@ class Image:
self.load() self.load()
try: try:
return map(ord, self.im.getpalette()) if bytes is str:
return [i8(c) for c in self.im.getpalette()]
else:
return list(self.im.getpalette())
except ValueError: except ValueError:
return None # no palette return None # no palette
@ -958,7 +965,7 @@ class Image:
self.load() self.load()
x, y = self.im.getprojection() x, y = self.im.getprojection()
return map(ord, x), map(ord, y) return [i8(c) for c in x], [i8(c) for c in y]
## ##
# Returns a histogram for the image. The histogram is returned as # Returns a histogram for the image. The histogram is returned as
@ -1012,7 +1019,7 @@ class Image:
"'offset' is deprecated; use 'ImageChops.offset' instead", "'offset' is deprecated; use 'ImageChops.offset' instead",
DeprecationWarning, stacklevel=2 DeprecationWarning, stacklevel=2
) )
import ImageChops from . import ImageChops
return ImageChops.offset(self, xoffset, yoffset) return ImageChops.offset(self, xoffset, yoffset)
## ##
@ -1079,7 +1086,7 @@ class Image:
box = box + (box[0]+size[0], box[1]+size[1]) box = box + (box[0]+size[0], box[1]+size[1])
if isStringType(im): if isStringType(im):
import ImageColor from . import ImageColor
im = ImageColor.getcolor(im, self.mode) im = ImageColor.getcolor(im, self.mode)
elif isImageType(im): elif isImageType(im):
@ -1121,14 +1128,14 @@ class Image:
if isinstance(lut, ImagePointHandler): if isinstance(lut, ImagePointHandler):
return lut.point(self) return lut.point(self)
if not isSequenceType(lut): if not isinstance(lut, collections.Sequence):
# if it isn't a list, it should be a function # if it isn't a list, it should be a function
if self.mode in ("I", "I;16", "F"): if self.mode in ("I", "I;16", "F"):
# check if the function can be used with point_transform # check if the function can be used with point_transform
scale, offset = _getscaleoffset(lut) scale, offset = _getscaleoffset(lut)
return self._new(self.im.point_transform(scale, offset)) return self._new(self.im.point_transform(scale, offset))
# for other modes, convert the function to a table # for other modes, convert the function to a table
lut = map(lut, range(256)) * self.im.bands lut = [lut(i) for i in range(256)] * self.im.bands
if self.mode == "F": if self.mode == "F":
# FIXME: _imaging returns a confusing error message for this case # FIXME: _imaging returns a confusing error message for this case
@ -1225,6 +1232,7 @@ class Image:
def putpalette(self, data, rawmode="RGB"): def putpalette(self, data, rawmode="RGB"):
"Put palette data into an image." "Put palette data into an image."
from . import ImagePalette
if self.mode not in ("L", "P"): if self.mode not in ("L", "P"):
raise ValueError("illegal image mode") raise ValueError("illegal image mode")
@ -1232,8 +1240,11 @@ class Image:
if isinstance(data, ImagePalette.ImagePalette): if isinstance(data, ImagePalette.ImagePalette):
palette = ImagePalette.raw(data.rawmode, data.palette) palette = ImagePalette.raw(data.rawmode, data.palette)
else: else:
if not isStringType(data): if not isinstance(data, bytes):
data = string.join(map(chr, data), "") if bytes is str:
data = "".join(chr(x) for x in data)
else:
data = bytes(data)
palette = ImagePalette.raw(rawmode, data) palette = ImagePalette.raw(rawmode, data)
self.mode = "P" self.mode = "P"
self.palette = palette self.palette = palette
@ -1330,7 +1341,8 @@ class Image:
math.cos(angle), math.sin(angle), 0.0, math.cos(angle), math.sin(angle), 0.0,
-math.sin(angle), math.cos(angle), 0.0 -math.sin(angle), math.cos(angle), 0.0
] ]
def transform(x, y, (a, b, c, d, e, f)=matrix): def transform(x, y, matrix=matrix):
(a, b, c, d, e, f) = matrix
return a*x + b*y + c, d*x + e*y + f return a*x + b*y + c, d*x + e*y + f
# calculate output size # calculate output size
@ -1408,7 +1420,7 @@ class Image:
preinit() preinit()
ext = string.lower(os.path.splitext(filename)[1]) ext = os.path.splitext(filename)[1].lower()
if not format: if not format:
try: try:
@ -1421,14 +1433,13 @@ class Image:
raise KeyError(ext) # unknown extension raise KeyError(ext) # unknown extension
try: try:
save_handler = SAVE[string.upper(format)] save_handler = SAVE[format.upper()]
except KeyError: except KeyError:
init() init()
save_handler = SAVE[string.upper(format)] # unknown format save_handler = SAVE[format.upper()] # unknown format
if isStringType(fp): if isStringType(fp):
import __builtin__ fp = builtins.open(fp, "wb")
fp = __builtin__.open(fp, "wb")
close = 1 close = 1
else: else:
close = 0 close = 0
@ -1755,13 +1766,13 @@ def new(mode, size, color=0):
if isStringType(color): if isStringType(color):
# css3-style specifier # css3-style specifier
import ImageColor from . import ImageColor
color = ImageColor.getcolor(color, mode) color = ImageColor.getcolor(color, mode)
return Image()._new(core.fill(mode, size, color)) return Image()._new(core.fill(mode, size, color))
## ##
# Creates an image memory from pixel data in a string. # Creates a copy of an image memory from pixel data in a buffer.
# <p> # <p>
# In its simplest form, this function takes three arguments # In its simplest form, this function takes three arguments
# (mode, size, and unpacked pixel data). # (mode, size, and unpacked pixel data).
@ -1772,34 +1783,40 @@ def new(mode, size, color=0):
# <p> # <p>
# Note that this function decodes pixel data only, not entire images. # Note that this function decodes pixel data only, not entire images.
# If you have an entire image in a string, wrap it in a # If you have an entire image in a string, wrap it in a
# <b>StringIO</b> object, and use {@link #open} to load it. # <b>BytesIO</b> object, and use {@link #open} to load it.
# #
# @param mode The image mode. # @param mode The image mode.
# @param size The image size. # @param size The image size.
# @param data An 8-bit string containing raw data for the given mode. # @param data A byte buffer containing raw data for the given mode.
# @param decoder_name What decoder to use. # @param decoder_name What decoder to use.
# @param *args Additional parameters for the given decoder. # @param *args Additional parameters for the given decoder.
# @return An Image object. # @return An Image object.
def fromstring(mode, size, data, decoder_name="raw", *args): def frombytes(mode, size, data, decoder_name="raw", *args):
"Load image from string" "Load image from byte buffer"
# may pass tuple instead of argument list # may pass tuple instead of argument list
if len(args) == 1 and isTupleType(args[0]): if len(args) == 1 and isinstance(args[0], tuple):
args = args[0] args = args[0]
if decoder_name == "raw" and args == (): if decoder_name == "raw" and args == ():
args = mode args = mode
im = new(mode, size) im = new(mode, size)
im.fromstring(data, decoder_name, args) im.frombytes(data, decoder_name, args)
return im return im
if bytes is str:
# Declare fromstring as an alias for frombytes
def fromstring(*args, **kw):
warnings.warn('fromstring() is deprecated. Please call frombytes() instead.', DeprecationWarning)
return frombytes(*args, **kw)
## ##
# (New in 1.1.4) Creates an image memory from pixel data in a string # (New in 1.1.4) Creates an image memory referencing pixel data in a
# or byte buffer. # byte buffer.
# <p> # <p>
# This function is similar to {@link #fromstring}, but uses data in # This function is similar to {@link #frombytes}, but uses data in
# the byte buffer, where possible. This means that changes to the # the byte buffer, where possible. This means that changes to the
# original buffer object are reflected in this image). Not all modes # original buffer object are reflected in this image). Not all modes
# can share memory; supported modes include "L", "RGBX", "RGBA", and # can share memory; supported modes include "L", "RGBX", "RGBA", and
@ -1807,7 +1824,7 @@ def fromstring(mode, size, data, decoder_name="raw", *args):
# <p> # <p>
# Note that this function decodes pixel data only, not entire images. # Note that this function decodes pixel data only, not entire images.
# If you have an entire image file in a string, wrap it in a # If you have an entire image file in a string, wrap it in a
# <b>StringIO</b> object, and use {@link #open} to load it. # <b>BytesIO</b> object, and use {@link #open} to load it.
# <p> # <p>
# In the current version, the default parameters used for the "raw" # In the current version, the default parameters used for the "raw"
# decoder differs from that used for {@link fromstring}. This is a # decoder differs from that used for {@link fromstring}. This is a
@ -1818,7 +1835,7 @@ def fromstring(mode, size, data, decoder_name="raw", *args):
# #
# @param mode The image mode. # @param mode The image mode.
# @param size The image size. # @param size The image size.
# @param data An 8-bit string or other buffer object containing raw # @param data A bytes or other buffer object containing raw
# data for the given mode. # data for the given mode.
# @param decoder_name What decoder to use. # @param decoder_name What decoder to use.
# @param *args Additional parameters for the given decoder. For the # @param *args Additional parameters for the given decoder. For the
@ -1829,10 +1846,10 @@ def fromstring(mode, size, data, decoder_name="raw", *args):
# @since 1.1.4 # @since 1.1.4
def frombuffer(mode, size, data, decoder_name="raw", *args): def frombuffer(mode, size, data, decoder_name="raw", *args):
"Load image from string or buffer" "Load image from bytes or buffer"
# may pass tuple instead of argument list # may pass tuple instead of argument list
if len(args) == 1 and isTupleType(args[0]): if len(args) == 1 and isinstance(args[0], tuple):
args = args[0] args = args[0]
if decoder_name == "raw": if decoder_name == "raw":
@ -1853,14 +1870,14 @@ def frombuffer(mode, size, data, decoder_name="raw", *args):
im.readonly = 1 im.readonly = 1
return im return im
return fromstring(mode, size, data, decoder_name, args) return frombytes(mode, size, data, decoder_name, args)
## ##
# (New in 1.1.6) Creates an image memory from an object exporting # (New in 1.1.6) Creates an image memory from an object exporting
# the array interface (using the buffer protocol). # the array interface (using the buffer protocol).
# #
# If obj is not contiguous, then the tostring method is called # If obj is not contiguous, then the tobytes method is called
# and {@link frombuffer} is used. # and {@link frombuffer} is used.
# #
# @param obj Object with array interface # @param obj Object with array interface
@ -1895,7 +1912,7 @@ def fromarray(obj, mode=None):
size = shape[1], shape[0] size = shape[1], shape[0]
if strides is not None: if strides is not None:
obj = obj.tostring() obj = obj.tobytes()
return frombuffer(mode, size, obj, "raw", rawmode, 0, 1) return frombuffer(mode, size, obj, "raw", rawmode, 0, 1)
@ -1945,9 +1962,8 @@ def open(fp, mode="r"):
raise ValueError("bad mode") raise ValueError("bad mode")
if isStringType(fp): if isStringType(fp):
import __builtin__
filename = fp filename = fp
fp = __builtin__.open(fp, "rb") fp = builtins.open(fp, "rb")
else: else:
filename = "" filename = ""
@ -1962,6 +1978,8 @@ def open(fp, mode="r"):
fp.seek(0) fp.seek(0)
return factory(fp, filename) return factory(fp, filename)
except (SyntaxError, IndexError, TypeError): except (SyntaxError, IndexError, TypeError):
#import traceback
#traceback.print_exc()
pass pass
if init(): if init():
@ -1973,6 +1991,8 @@ def open(fp, mode="r"):
fp.seek(0) fp.seek(0)
return factory(fp, filename) return factory(fp, filename)
except (SyntaxError, IndexError, TypeError): except (SyntaxError, IndexError, TypeError):
#import traceback
#traceback.print_exc()
pass pass
raise IOError("cannot identify image file") raise IOError("cannot identify image file")
@ -2093,7 +2113,7 @@ def merge(mode, bands):
# reject images having another format. # reject images having another format.
def register_open(id, factory, accept=None): def register_open(id, factory, accept=None):
id = string.upper(id) id = id.upper()
ID.append(id) ID.append(id)
OPEN[id] = factory, accept OPEN[id] = factory, accept
@ -2105,7 +2125,7 @@ def register_open(id, factory, accept=None):
# @param mimetype The image MIME type for this format. # @param mimetype The image MIME type for this format.
def register_mime(id, mimetype): def register_mime(id, mimetype):
MIME[string.upper(id)] = mimetype MIME[id.upper()] = mimetype
## ##
# Registers an image save function. This function should not be # Registers an image save function. This function should not be
@ -2115,7 +2135,7 @@ def register_mime(id, mimetype):
# @param driver A function to save images in this format. # @param driver A function to save images in this format.
def register_save(id, driver): def register_save(id, driver):
SAVE[string.upper(id)] = driver SAVE[id.upper()] = driver
## ##
# Registers an image extension. This function should not be # Registers an image extension. This function should not be
@ -2125,7 +2145,7 @@ def register_save(id, driver):
# @param extension An extension used for this format. # @param extension An extension used for this format.
def register_extension(id, extension): def register_extension(id, extension):
EXTENSION[string.lower(extension)] = string.upper(id) EXTENSION[extension.lower()] = id.upper()
# -------------------------------------------------------------------- # --------------------------------------------------------------------
@ -2133,8 +2153,8 @@ def register_extension(id, extension):
def _show(image, **options): def _show(image, **options):
# override me, as necessary # override me, as necessary
apply(_showxv, (image,), options) _showxv(image, **options)
def _showxv(image, title=None, **options): def _showxv(image, title=None, **options):
import ImageShow from . import ImageShow
apply(ImageShow.show, (image, title), options) ImageShow.show(image, title, **options)

View File

@ -15,7 +15,7 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import Image from . import Image
## ##
# The <b>ImageChops</b> module contains a number of arithmetical image # The <b>ImageChops</b> module contains a number of arithmetical image

View File

@ -15,6 +15,8 @@
# below for the original description. # below for the original description.
# #
from __future__ import print_function
DESCRIPTION = """ DESCRIPTION = """
pyCMS pyCMS
@ -79,7 +81,7 @@ VERSION = "0.1.0 pil"
# --------------------------------------------------------------------. # --------------------------------------------------------------------.
import Image from . import Image
import _imagingcms import _imagingcms
core = _imagingcms core = _imagingcms
@ -122,7 +124,7 @@ FLAGS = {
_MAX_FLAG = 0 _MAX_FLAG = 0
for flag in FLAGS.values(): for flag in FLAGS.values():
if isinstance(flag, type(0)): if isinstance(flag, int):
_MAX_FLAG = _MAX_FLAG | flag _MAX_FLAG = _MAX_FLAG | flag
# --------------------------------------------------------------------. # --------------------------------------------------------------------.
@ -140,7 +142,7 @@ class ImageCmsProfile:
if Image.isStringType(profile): if Image.isStringType(profile):
self._set(core.profile_open(profile), profile) self._set(core.profile_open(profile), profile)
elif hasattr(profile, "read"): elif hasattr(profile, "read"):
self._set(core.profile_fromstring(profile.read())) self._set(core.profile_frombytes(profile.read()))
else: else:
self._set(profile) # assume it's already a profile self._set(profile) # assume it's already a profile
@ -205,7 +207,7 @@ class ImageCmsTransform(Image.ImagePointHandler):
def get_display_profile(handle=None): def get_display_profile(handle=None):
import sys import sys
if sys.platform == "win32": if sys.platform == "win32":
import ImageWin from . import ImageWin
if isinstance(handle, ImageWin.HDC): if isinstance(handle, ImageWin.HDC):
profile = core.get_display_profile_win32(handle, 1) profile = core.get_display_profile_win32(handle, 1)
else: else:
@ -288,10 +290,10 @@ def profileToProfile(im, inputProfile, outputProfile, renderingIntent=INTENT_PER
if outputMode is None: if outputMode is None:
outputMode = im.mode outputMode = im.mode
if type(renderingIntent) != type(1) or not (0 <= renderingIntent <=3): if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <=3):
raise PyCMSError("renderingIntent must be an integer between 0 and 3") raise PyCMSError("renderingIntent must be an integer between 0 and 3")
if type(flags) != type(1) or not (0 <= flags <= _MAX_FLAG): if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG):
raise PyCMSError("flags must be an integer between 0 and %s" + _MAX_FLAG) raise PyCMSError("flags must be an integer between 0 and %s" + _MAX_FLAG)
try: try:
@ -307,7 +309,7 @@ def profileToProfile(im, inputProfile, outputProfile, renderingIntent=INTENT_PER
imOut = None imOut = None
else: else:
imOut = transform.apply(im) imOut = transform.apply(im)
except (IOError, TypeError, ValueError), v: except (IOError, TypeError, ValueError) as v:
raise PyCMSError(v) raise PyCMSError(v)
return imOut return imOut
@ -334,7 +336,7 @@ def getOpenProfile(profileFilename):
try: try:
return ImageCmsProfile(profileFilename) return ImageCmsProfile(profileFilename)
except (IOError, TypeError, ValueError), v: except (IOError, TypeError, ValueError) as v:
raise PyCMSError(v) raise PyCMSError(v)
## ##
@ -396,10 +398,10 @@ def buildTransform(inputProfile, outputProfile, inMode, outMode, renderingIntent
""" """
if type(renderingIntent) != type(1) or not (0 <= renderingIntent <=3): if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <=3):
raise PyCMSError("renderingIntent must be an integer between 0 and 3") raise PyCMSError("renderingIntent must be an integer between 0 and 3")
if type(flags) != type(1) or not (0 <= flags <= _MAX_FLAG): if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG):
raise PyCMSError("flags must be an integer between 0 and %s" + _MAX_FLAG) raise PyCMSError("flags must be an integer between 0 and %s" + _MAX_FLAG)
try: try:
@ -408,7 +410,7 @@ def buildTransform(inputProfile, outputProfile, inMode, outMode, renderingIntent
if not isinstance(outputProfile, ImageCmsProfile): if not isinstance(outputProfile, ImageCmsProfile):
outputProfile = ImageCmsProfile(outputProfile) outputProfile = ImageCmsProfile(outputProfile)
return ImageCmsTransform(inputProfile, outputProfile, inMode, outMode, renderingIntent, flags=flags) return ImageCmsTransform(inputProfile, outputProfile, inMode, outMode, renderingIntent, flags=flags)
except (IOError, TypeError, ValueError), v: except (IOError, TypeError, ValueError) as v:
raise PyCMSError(v) raise PyCMSError(v)
## ##
@ -487,10 +489,10 @@ def buildProofTransform(inputProfile, outputProfile, proofProfile, inMode, outMo
""" """
if type(renderingIntent) != type(1) or not (0 <= renderingIntent <=3): if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <=3):
raise PyCMSError("renderingIntent must be an integer between 0 and 3") raise PyCMSError("renderingIntent must be an integer between 0 and 3")
if type(flags) != type(1) or not (0 <= flags <= _MAX_FLAG): if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG):
raise PyCMSError("flags must be an integer between 0 and %s" + _MAX_FLAG) raise PyCMSError("flags must be an integer between 0 and %s" + _MAX_FLAG)
try: try:
@ -501,7 +503,7 @@ def buildProofTransform(inputProfile, outputProfile, proofProfile, inMode, outMo
if not isinstance(proofProfile, ImageCmsProfile): if not isinstance(proofProfile, ImageCmsProfile):
proofProfile = ImageCmsProfile(proofProfile) proofProfile = ImageCmsProfile(proofProfile)
return ImageCmsTransform(inputProfile, outputProfile, inMode, outMode, renderingIntent, proofProfile, proofRenderingIntent, flags) return ImageCmsTransform(inputProfile, outputProfile, inMode, outMode, renderingIntent, proofProfile, proofRenderingIntent, flags)
except (IOError, TypeError, ValueError), v: except (IOError, TypeError, ValueError) as v:
raise PyCMSError(v) raise PyCMSError(v)
buildTransformFromOpenProfiles = buildTransform buildTransformFromOpenProfiles = buildTransform
@ -557,7 +559,7 @@ def applyTransform(im, transform, inPlace=0):
imOut = None imOut = None
else: else:
imOut = transform.apply(im) imOut = transform.apply(im)
except (TypeError, ValueError), v: except (TypeError, ValueError) as v:
raise PyCMSError(v) raise PyCMSError(v)
return imOut return imOut
@ -595,14 +597,14 @@ def createProfile(colorSpace, colorTemp=-1):
raise PyCMSError("Color space not supported for on-the-fly profile creation (%s)" % colorSpace) raise PyCMSError("Color space not supported for on-the-fly profile creation (%s)" % colorSpace)
if colorSpace == "LAB": if colorSpace == "LAB":
if type(colorTemp) == type(5000.0): if isinstance(colorTemp, float):
colorTemp = int(colorTemp + 0.5) colorTemp = int(colorTemp + 0.5)
if type (colorTemp) != type (5000): if not isinstance(colorTemp, int):
raise PyCMSError("Color temperature must be a positive integer, \"%s\" not valid" % colorTemp) raise PyCMSError("Color temperature must be a positive integer, \"%s\" not valid" % colorTemp)
try: try:
return core.createProfile(colorSpace, colorTemp) return core.createProfile(colorSpace, colorTemp)
except (TypeError, ValueError), v: except (TypeError, ValueError) as v:
raise PyCMSError(v) raise PyCMSError(v)
## ##
@ -633,7 +635,7 @@ def getProfileName(profile):
if not isinstance(profile, ImageCmsProfile): if not isinstance(profile, ImageCmsProfile):
profile = ImageCmsProfile(profile) profile = ImageCmsProfile(profile)
return profile.profile.product_name + "\n" return profile.profile.product_name + "\n"
except (AttributeError, IOError, TypeError, ValueError), v: except (AttributeError, IOError, TypeError, ValueError) as v:
raise PyCMSError(v) raise PyCMSError(v)
## ##
@ -665,7 +667,7 @@ def getProfileInfo(profile):
profile = ImageCmsProfile(profile) profile = ImageCmsProfile(profile)
# add an extra newline to preserve pyCMS compatibility # add an extra newline to preserve pyCMS compatibility
return profile.product_info + "\n" return profile.product_info + "\n"
except (AttributeError, IOError, TypeError, ValueError), v: except (AttributeError, IOError, TypeError, ValueError) as v:
raise PyCMSError(v) raise PyCMSError(v)
## ##
@ -703,7 +705,7 @@ def getDefaultIntent(profile):
if not isinstance(profile, ImageCmsProfile): if not isinstance(profile, ImageCmsProfile):
profile = ImageCmsProfile(profile) profile = ImageCmsProfile(profile)
return profile.profile.rendering_intent return profile.profile.rendering_intent
except (AttributeError, IOError, TypeError, ValueError), v: except (AttributeError, IOError, TypeError, ValueError) as v:
raise PyCMSError(v) raise PyCMSError(v)
## ##
@ -752,7 +754,7 @@ def isIntentSupported(profile, intent, direction):
return 1 return 1
else: else:
return -1 return -1
except (AttributeError, IOError, TypeError, ValueError), v: except (AttributeError, IOError, TypeError, ValueError) as v:
raise PyCMSError(v) raise PyCMSError(v)
## ##
@ -769,18 +771,17 @@ def versions():
if __name__ == "__main__": if __name__ == "__main__":
# create a cheap manual from the __doc__ strings for the functions above # create a cheap manual from the __doc__ strings for the functions above
import ImageCms from . import ImageCms
import string print(__doc__)
print __doc__
for f in dir(pyCMS): for f in dir(pyCMS):
print "="*80 print("="*80)
print "%s" %f print("%s" %f)
try: try:
exec ("doc = ImageCms.%s.__doc__" %(f)) exec ("doc = ImageCms.%s.__doc__" %(f))
if string.find(doc, "pyCMS") >= 0: if "pyCMS" in doc:
# so we don't get the __doc__ string for imported modules # so we don't get the __doc__ string for imported modules
print doc print(doc)
except AttributeError: except AttributeError:
pass pass

View File

@ -17,16 +17,9 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import Image from . import Image
import re, string import re
try:
x = int("a", 16)
except TypeError:
# python 1.5.2 doesn't support int(x,b)
str2int = string.atoi
else:
str2int = int
## ##
# Convert color string to RGB tuple. # Convert color string to RGB tuple.
@ -43,12 +36,12 @@ def getrgb(color):
except KeyError: except KeyError:
try: try:
# fall back on case-insensitive lookup # fall back on case-insensitive lookup
rgb = colormap[string.lower(color)] rgb = colormap[color.lower()]
except KeyError: except KeyError:
rgb = None rgb = None
# found color in cache # found color in cache
if rgb: if rgb:
if isinstance(rgb, type(())): if isinstance(rgb, tuple):
return rgb return rgb
colormap[color] = rgb = getrgb(rgb) colormap[color] = rgb = getrgb(rgb)
return rgb return rgb
@ -56,30 +49,30 @@ def getrgb(color):
m = re.match("#\w\w\w$", color) m = re.match("#\w\w\w$", color)
if m: if m:
return ( return (
str2int(color[1]*2, 16), int(color[1]*2, 16),
str2int(color[2]*2, 16), int(color[2]*2, 16),
str2int(color[3]*2, 16) int(color[3]*2, 16)
) )
m = re.match("#\w\w\w\w\w\w$", color) m = re.match("#\w\w\w\w\w\w$", color)
if m: if m:
return ( return (
str2int(color[1:3], 16), int(color[1:3], 16),
str2int(color[3:5], 16), int(color[3:5], 16),
str2int(color[5:7], 16) int(color[5:7], 16)
) )
m = re.match("rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$", color) m = re.match("rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$", color)
if m: if m:
return ( return (
str2int(m.group(1)), int(m.group(1)),
str2int(m.group(2)), int(m.group(2)),
str2int(m.group(3)) int(m.group(3))
) )
m = re.match("rgb\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)$", color) m = re.match("rgb\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)$", color)
if m: if m:
return ( return (
int((str2int(m.group(1)) * 255) / 100.0 + 0.5), int((int(m.group(1)) * 255) / 100.0 + 0.5),
int((str2int(m.group(2)) * 255) / 100.0 + 0.5), int((int(m.group(2)) * 255) / 100.0 + 0.5),
int((str2int(m.group(3)) * 255) / 100.0 + 0.5) int((int(m.group(3)) * 255) / 100.0 + 0.5)
) )
m = re.match("hsl\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)$", color) m = re.match("hsl\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)$", color)
if m: if m:
@ -106,7 +99,7 @@ def getcolor(color, mode):
return r, g, b, 255 return r, g, b, 255
if Image.getmodebase(mode) == "L": if Image.getmodebase(mode) == "L":
r, g, b = color r, g, b = color
return (r*299 + g*587 + b*114)/1000 return (r*299 + g*587 + b*114)//1000
return color return color
colormap = { colormap = {

View File

@ -30,7 +30,7 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import Image, ImageColor from . import Image, ImageColor
try: try:
import warnings import warnings
@ -127,7 +127,7 @@ class ImageDraw:
def getfont(self): def getfont(self):
if not self.font: if not self.font:
# FIXME: should add a font repository # FIXME: should add a font repository
import ImageFont from . import ImageFont
self.font = ImageFont.load_default() self.font = ImageFont.load_default()
return self.font return self.font
@ -318,7 +318,7 @@ def getdraw(im=None, hints=None):
except ImportError: except ImportError:
pass pass
if handler is None: if handler is None:
import ImageDraw2 from . import ImageDraw2
handler = ImageDraw2 handler = ImageDraw2
if im: if im:
im = handler.Draw(im) im = handler.Draw(im)

View File

@ -16,7 +16,7 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import Image, ImageColor, ImageDraw, ImageFont, ImagePath from . import Image, ImageColor, ImageDraw, ImageFont, ImagePath
class Pen: class Pen:
def __init__(self, color, width=1, opacity=255): def __init__(self, color, width=1, opacity=255):
@ -68,7 +68,8 @@ class Draw:
else: else:
getattr(self.draw, op)(xy, fill=fill, outline=outline) getattr(self.draw, op)(xy, fill=fill, outline=outline)
def settransform(self, (xoffset, yoffset)): def settransform(self, offset):
(xoffset, yoffset) = offset
self.transform = (1, 0, xoffset, 0, 1, yoffset) self.transform = (1, 0, xoffset, 0, 1, yoffset)
def arc(self, xy, start, end, *options): def arc(self, xy, start, end, *options):

View File

@ -18,7 +18,7 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import Image, ImageFilter, ImageStat from . import Image, ImageFilter, ImageStat
class _Enhance: class _Enhance:

View File

@ -27,8 +27,9 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import Image from . import Image
import traceback, string, os import traceback, os
import io
MAXBLOCK = 65536 MAXBLOCK = 65536
@ -55,9 +56,9 @@ def raise_ioerror(error):
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Helpers # Helpers
def _tilesort(t1, t2): def _tilesort(t):
# sort on offset # sort on offset
return cmp(t1[2], t2[2]) return t[2]
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
@ -89,25 +90,25 @@ class ImageFile(Image.Image):
try: try:
self._open() self._open()
except IndexError, v: # end of data except IndexError as v: # end of data
if Image.DEBUG > 1: if Image.DEBUG > 1:
traceback.print_exc() traceback.print_exc()
raise SyntaxError, v raise SyntaxError(v)
except TypeError, v: # end of data (ord) except TypeError as v: # end of data (ord)
if Image.DEBUG > 1: if Image.DEBUG > 1:
traceback.print_exc() traceback.print_exc()
raise SyntaxError, v raise SyntaxError(v)
except KeyError, v: # unsupported mode except KeyError as v: # unsupported mode
if Image.DEBUG > 1: if Image.DEBUG > 1:
traceback.print_exc() traceback.print_exc()
raise SyntaxError, v raise SyntaxError(v)
except EOFError, v: # got header but not the first frame except EOFError as v: # got header but not the first frame
if Image.DEBUG > 1: if Image.DEBUG > 1:
traceback.print_exc() traceback.print_exc()
raise SyntaxError, v raise SyntaxError(v)
if not self.mode or self.size[0] <= 0: if not self.mode or self.size[0] <= 0:
raise SyntaxError, "not identified by this driver" raise SyntaxError("not identified by this driver")
def draft(self, mode, size): def draft(self, mode, size):
"Set draft mode" "Set draft mode"
@ -177,13 +178,13 @@ class ImageFile(Image.Image):
if not self.map: if not self.map:
# sort tiles in file order # sort tiles in file order
self.tile.sort(_tilesort) self.tile.sort(key=_tilesort)
try: try:
# FIXME: This is a hack to handle TIFF's JpegTables tag. # FIXME: This is a hack to handle TIFF's JpegTables tag.
prefix = self.tile_prefix prefix = self.tile_prefix
except AttributeError: except AttributeError:
prefix = "" prefix = b""
for d, e, o, a in self.tile: for d, e, o, a in self.tile:
d = Image._getdecoder(self.mode, d, a, self.decoderconfig) d = Image._getdecoder(self.mode, d, a, self.decoderconfig)
@ -194,7 +195,7 @@ class ImageFile(Image.Image):
continue continue
b = prefix b = prefix
t = len(b) t = len(b)
while 1: while True:
s = read(self.decodermaxblock) s = read(self.decodermaxblock)
if not s: if not s:
self.tile = [] self.tile = []
@ -277,52 +278,6 @@ class StubImageFile(ImageFile):
"StubImageFile subclass must implement _load" "StubImageFile subclass must implement _load"
) )
##
# (Internal) Support class for the <b>Parser</b> file.
class _ParserFile:
# parser support class.
def __init__(self, data):
self.data = data
self.offset = 0
def close(self):
self.data = self.offset = None
def tell(self):
return self.offset
def seek(self, offset, whence=0):
if whence == 0:
self.offset = offset
elif whence == 1:
self.offset = self.offset + offset
else:
# force error in Image.open
raise IOError("illegal argument to seek")
def read(self, bytes=0):
pos = self.offset
if bytes:
data = self.data[pos:pos+bytes]
else:
data = self.data[pos:]
self.offset = pos + len(data)
return data
def readline(self):
# FIXME: this is slow!
s = ""
while 1:
c = self.read(1)
if not c:
break
s = s + c
if c == "\n":
break
return s
## ##
# Incremental image parser. This class implements the standard # Incremental image parser. This class implements the standard
# feed/close consumer interface. # feed/close consumer interface.
@ -398,11 +353,12 @@ class Parser:
# attempt to open this file # attempt to open this file
try: try:
try: try:
fp = _ParserFile(self.data) fp = io.BytesIO(self.data)
im = Image.open(fp) im = Image.open(fp)
finally: finally:
fp.close() # explicitly close the virtual file fp.close() # explicitly close the virtual file
except IOError: except IOError:
# traceback.print_exc()
pass # not enough data pass # not enough data
else: else:
flag = hasattr(im, "load_seek") or hasattr(im, "load_read") flag = hasattr(im, "load_seek") or hasattr(im, "load_read")
@ -437,7 +393,7 @@ class Parser:
# finish decoding # finish decoding
if self.decoder: if self.decoder:
# get rid of what's left in the buffers # get rid of what's left in the buffers
self.feed("") self.feed(b"")
self.data = self.decoder = None self.data = self.decoder = None
if not self.finished: if not self.finished:
raise IOError("image was incomplete") raise IOError("image was incomplete")
@ -447,7 +403,7 @@ class Parser:
# incremental parsing not possible; reopen the file # incremental parsing not possible; reopen the file
# not that we have all data # not that we have all data
try: try:
fp = _ParserFile(self.data) fp = io.BytesIO(self.data)
self.image = Image.open(fp) self.image = Image.open(fp)
finally: finally:
self.image.load() self.image.load()
@ -469,20 +425,20 @@ def _save(im, fp, tile):
im.load() im.load()
if not hasattr(im, "encoderconfig"): if not hasattr(im, "encoderconfig"):
im.encoderconfig = () im.encoderconfig = ()
tile.sort(_tilesort) tile.sort(key=_tilesort)
# FIXME: make MAXBLOCK a configuration parameter # FIXME: make MAXBLOCK a configuration parameter
bufsize = max(MAXBLOCK, im.size[0] * 4) # see RawEncode.c bufsize = max(MAXBLOCK, im.size[0] * 4) # see RawEncode.c
try: try:
fh = fp.fileno() fh = fp.fileno()
fp.flush() fp.flush()
except AttributeError: except (AttributeError, io.UnsupportedOperation):
# compress to Python file-compatible object # compress to Python file-compatible object
for e, b, o, a in tile: for e, b, o, a in tile:
e = Image._getencoder(im.mode, e, a, im.encoderconfig) e = Image._getencoder(im.mode, e, a, im.encoderconfig)
if o > 0: if o > 0:
fp.seek(o, 0) fp.seek(o, 0)
e.setimage(im.im, b) e.setimage(im.im, b)
while 1: while True:
l, s, d = e.encode(bufsize) l, s, d = e.encode(bufsize)
fp.write(d) fp.write(d)
if s: if s:
@ -515,7 +471,7 @@ def _save(im, fp, tile):
def _safe_read(fp, size): def _safe_read(fp, size):
if size <= 0: if size <= 0:
return "" return b""
if size <= SAFEBLOCK: if size <= SAFEBLOCK:
return fp.read(size) return fp.read(size)
data = [] data = []
@ -525,4 +481,4 @@ def _safe_read(fp, size):
break break
data.append(block) data.append(block)
size = size - len(block) size = size - len(block)
return string.join(data, "") return b"".join(data)

View File

@ -12,7 +12,7 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
from StringIO import StringIO from io import BytesIO
## ##
# The <b>ImageFileIO</b> module can be used to read an image from a # The <b>ImageFileIO</b> module can be used to read an image from a
@ -23,7 +23,7 @@ from StringIO import StringIO
# #
# @see ImageFile#Parser # @see ImageFile#Parser
class ImageFileIO(StringIO): class ImageFileIO(BytesIO):
## ##
# Adds buffering to a stream file object, in order to # Adds buffering to a stream file object, in order to
@ -36,4 +36,4 @@ class ImageFileIO(StringIO):
def __init__(self, fp): def __init__(self, fp):
data = fp.read() data = fp.read()
StringIO.__init__(self, data) BytesIO.__init__(self, data)

View File

@ -15,6 +15,8 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
from functools import reduce
class Filter: class Filter:
pass pass
@ -52,7 +54,7 @@ class Kernel(Filter):
def filter(self, image): def filter(self, image):
if image.mode == "P": if image.mode == "P":
raise ValueError("cannot filter palette images") raise ValueError("cannot filter palette images")
return apply(image.filter, self.filterargs) return image.filter(*self.filterargs)
class BuiltinFilter(Kernel): class BuiltinFilter(Kernel):
def __init__(self): def __init__(self):
@ -80,7 +82,7 @@ class RankFilter(Filter):
def filter(self, image): def filter(self, image):
if image.mode == "P": if image.mode == "P":
raise ValueError("cannot filter palette images") raise ValueError("cannot filter palette images")
image = image.expand(self.size/2, self.size/2) image = image.expand(self.size//2, self.size//2)
return image.rankfilter(self.size, self.rank) return image.rankfilter(self.size, self.rank)
## ##
@ -97,7 +99,7 @@ class MedianFilter(RankFilter):
def __init__(self, size=3): def __init__(self, size=3):
self.size = size self.size = size
self.rank = size*size/2 self.rank = size*size//2
## ##
# Min filter. Picks the lowest pixel value in a window with the given # Min filter. Picks the lowest pixel value in a window with the given

View File

@ -25,8 +25,10 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import Image from __future__ import print_function
import os, string, sys
from . import Image
import os, sys
class _imagingft_not_installed: class _imagingft_not_installed:
# module placeholder # module placeholder
@ -97,13 +99,13 @@ class ImageFont:
def _load_pilfont_data(self, file, image): def _load_pilfont_data(self, file, image):
# read PILfont header # read PILfont header
if file.readline() != "PILfont\n": if file.readline() != b"PILfont\n":
raise SyntaxError("Not a PILfont file") raise SyntaxError("Not a PILfont file")
d = string.split(file.readline(), ";") d = file.readline().split(b";")
self.info = [] # FIXME: should be a dictionary self.info = [] # FIXME: should be a dictionary
while True: while True:
s = file.readline() s = file.readline()
if not s or s == "DATA\n": if not s or s == b"DATA\n":
break break
self.info.append(s) self.info.append(s)
@ -253,12 +255,12 @@ def load_path(filename):
def load_default(): def load_default():
"Load a default font." "Load a default font."
from StringIO import StringIO from io import BytesIO
import base64 import base64
f = ImageFont() f = ImageFont()
f._load_pilfont_data( f._load_pilfont_data(
# courB08 # courB08
StringIO(base64.decodestring(''' BytesIO(base64.decodestring(b'''
UElMZm9udAo7Ozs7OzsxMDsKREFUQQoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA UElMZm9udAo7Ozs7OzsxMDsKREFUQQoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
@ -350,7 +352,7 @@ AJsAEQAGAAAAAP/6AAX//wCbAAoAoAAPAAYAAAAA//oABQABAKAACgClABEABgAA////+AAGAAAA
pQAKAKwAEgAGAAD////4AAYAAACsAAoAswASAAYAAP////gABgAAALMACgC6ABIABgAA////+QAG pQAKAKwAEgAGAAD////4AAYAAACsAAoAswASAAYAAP////gABgAAALMACgC6ABIABgAA////+QAG
AAAAugAKAMEAEQAGAAD////4AAYAAgDBAAoAyAAUAAYAAP////kABQACAMgACgDOABMABgAA//// AAAAugAKAMEAEQAGAAD////4AAYAAgDBAAoAyAAUAAYAAP////kABQACAMgACgDOABMABgAA////
+QAGAAIAzgAKANUAEw== +QAGAAIAzgAKANUAEw==
''')), Image.open(StringIO(base64.decodestring(''' ''')), Image.open(BytesIO(base64.decodestring(b'''
iVBORw0KGgoAAAANSUhEUgAAAx4AAAAUAQAAAAArMtZoAAAEwElEQVR4nABlAJr/AHVE4czCI/4u iVBORw0KGgoAAAANSUhEUgAAAx4AAAAUAQAAAAArMtZoAAAEwElEQVR4nABlAJr/AHVE4czCI/4u
Mc4b7vuds/xzjz5/3/7u/n9vMe7vnfH/9++vPn/xyf5zhxzjt8GHw8+2d83u8x27199/nxuQ6Od9 Mc4b7vuds/xzjz5/3/7u/n9vMe7vnfH/9++vPn/xyf5zhxzjt8GHw8+2d83u8x27199/nxuQ6Od9
M43/5z2I+9n9ZtmDBwMQECDRQw/eQIQohJXxpBCNVE6QCCAAAAD//wBlAJr/AgALyj1t/wINwq0g M43/5z2I+9n9ZtmDBwMQECDRQw/eQIQohJXxpBCNVE6QCCAAAAD//wBlAJr/AgALyj1t/wINwq0g
@ -381,10 +383,10 @@ if __name__ == "__main__":
# create font data chunk for embedding # create font data chunk for embedding
import base64, os, sys import base64, os, sys
font = "../Images/courB08" font = "../Images/courB08"
print " f._load_pilfont_data(" print(" f._load_pilfont_data(")
print " # %s" % os.path.basename(font) print(" # %s" % os.path.basename(font))
print " StringIO(base64.decodestring('''" print(" BytesIO(base64.decodestring(b'''")
base64.encode(open(font + ".pil", "rb"), sys.stdout) base64.encode(open(font + ".pil", "rb"), sys.stdout)
print "''')), Image.open(StringIO(base64.decodestring('''" print("''')), Image.open(BytesIO(base64.decodestring(b'''")
base64.encode(open(font + ".pbm", "rb"), sys.stdout) base64.encode(open(font + ".pbm", "rb"), sys.stdout)
print "'''))))" print("'''))))")

View File

@ -15,7 +15,7 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import Image from . import Image
## ##
# (New in 1.1.3) The <b>ImageGrab</b> module can be used to copy # (New in 1.1.3) The <b>ImageGrab</b> module can be used to copy
@ -45,7 +45,7 @@ except AttributeError:
def grab(bbox=None): def grab(bbox=None):
size, data = grabber() size, data = grabber()
im = Image.fromstring( im = Image.frombytes(
"RGB", size, data, "RGB", size, data,
# RGB, 32-bit line padding, origo in lower left corner # RGB, 32-bit line padding, origo in lower left corner
"raw", "BGR", (size[0]*3 + 3) & -4, -1 "raw", "BGR", (size[0]*3 + 3) & -4, -1
@ -65,7 +65,8 @@ def grab(bbox=None):
def grabclipboard(): def grabclipboard():
debug = 0 # temporary interface debug = 0 # temporary interface
data = Image.core.grabclipboard(debug) data = Image.core.grabclipboard(debug)
if Image.isStringType(data): if isinstance(data, bytes):
import BmpImagePlugin, StringIO from . import BmpImagePlugin
return BmpImagePlugin.DibImageFile(StringIO.StringIO(data)) import io
return BmpImagePlugin.DibImageFile(io.BytesIO(data))
return data return data

View File

@ -15,13 +15,20 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import Image from . import Image
import _imagingmath import _imagingmath
import sys
try:
import builtins
except ImportError:
import __builtin__
builtins = __builtin__
VERBOSE = 0 VERBOSE = 0
def _isconstant(v): def _isconstant(v):
return isinstance(v, type(0)) or isinstance(v, type(0.0)) return isinstance(v, int) or isinstance(v, float)
class _Operand: class _Operand:
# wraps an image operand, providing standard operators # wraps an image operand, providing standard operators
@ -38,7 +45,7 @@ class _Operand:
elif im1.im.mode in ("I", "F"): elif im1.im.mode in ("I", "F"):
return im1.im return im1.im
else: else:
raise ValueError, "unsupported mode: %s" % im1.im.mode raise ValueError("unsupported mode: %s" % im1.im.mode)
else: else:
# argument was a constant # argument was a constant
if _isconstant(im1) and self.im.mode in ("1", "L", "I"): if _isconstant(im1) and self.im.mode in ("1", "L", "I"):
@ -55,7 +62,7 @@ class _Operand:
try: try:
op = getattr(_imagingmath, op+"_"+im1.mode) op = getattr(_imagingmath, op+"_"+im1.mode)
except AttributeError: except AttributeError:
raise TypeError, "bad operand type for '%s'" % op raise TypeError("bad operand type for '%s'" % op)
_imagingmath.unop(op, out.im.id, im1.im.id) _imagingmath.unop(op, out.im.id, im1.im.id)
else: else:
# binary operation # binary operation
@ -65,7 +72,7 @@ class _Operand:
if im1.mode != "F": im1 = im1.convert("F") if im1.mode != "F": im1 = im1.convert("F")
if im2.mode != "F": im2 = im2.convert("F") if im2.mode != "F": im2 = im2.convert("F")
if im1.mode != im2.mode: if im1.mode != im2.mode:
raise ValueError, "mode mismatch" raise ValueError("mode mismatch")
if im1.size != im2.size: if im1.size != im2.size:
# crop both arguments to a common size # crop both arguments to a common size
size = (min(im1.size[0], im2.size[0]), size = (min(im1.size[0], im2.size[0]),
@ -79,14 +86,20 @@ class _Operand:
try: try:
op = getattr(_imagingmath, op+"_"+im1.mode) op = getattr(_imagingmath, op+"_"+im1.mode)
except AttributeError: except AttributeError:
raise TypeError, "bad operand type for '%s'" % op raise TypeError("bad operand type for '%s'" % op)
_imagingmath.binop(op, out.im.id, im1.im.id, im2.im.id) _imagingmath.binop(op, out.im.id, im1.im.id, im2.im.id)
return _Operand(out) return _Operand(out)
# unary operators # unary operators
def __nonzero__(self): def __bool__(self):
# an image is "true" if it contains at least one non-zero pixel # an image is "true" if it contains at least one non-zero pixel
return self.im.getbbox() is not None return self.im.getbbox() is not None
if bytes is str:
# Provide __nonzero__ for pre-Py3k
__nonzero__ = __bool__
del __bool__
def __abs__(self): def __abs__(self):
return self.apply("abs", self) return self.apply("abs", self)
def __pos__(self): def __pos__(self):
@ -107,9 +120,9 @@ class _Operand:
return self.apply("mul", self, other) return self.apply("mul", self, other)
def __rmul__(self, other): def __rmul__(self, other):
return self.apply("mul", other, self) return self.apply("mul", other, self)
def __div__(self, other): def __truediv__(self, other):
return self.apply("div", self, other) return self.apply("div", self, other)
def __rdiv__(self, other): def __rtruediv__(self, other):
return self.apply("div", other, self) return self.apply("div", other, self)
def __mod__(self, other): def __mod__(self, other):
return self.apply("mod", self, other) return self.apply("mod", self, other)
@ -120,6 +133,13 @@ class _Operand:
def __rpow__(self, other): def __rpow__(self, other):
return self.apply("pow", other, self) return self.apply("pow", other, self)
if bytes is str:
# Provide __div__ and __rdiv__ for pre-Py3k
__div__ = __truediv__
__rdiv__ = __rtruediv__
del __truediv__
del __rtruediv__
# bitwise # bitwise
def __invert__(self): def __invert__(self):
return self.apply("invert", self) return self.apply("invert", self)
@ -175,7 +195,7 @@ def imagemath_convert(self, mode):
return _Operand(self.im.convert(mode)) return _Operand(self.im.convert(mode))
ops = {} ops = {}
for k, v in globals().items(): for k, v in list(globals().items()):
if k[:10] == "imagemath_": if k[:10] == "imagemath_":
ops[k[10:]] = v ops[k[10:]] = v
@ -195,12 +215,11 @@ def eval(expression, _dict={}, **kw):
args = ops.copy() args = ops.copy()
args.update(_dict) args.update(_dict)
args.update(kw) args.update(kw)
for k, v in args.items(): for k, v in list(args.items()):
if hasattr(v, "im"): if hasattr(v, "im"):
args[k] = _Operand(v) args[k] = _Operand(v)
import __builtin__ out = builtins.eval(expression, args)
out =__builtin__.eval(expression, args)
try: try:
return out.im return out.im
except AttributeError: except AttributeError:

View File

@ -36,7 +36,7 @@ class ModeDescriptor:
def getmode(mode): def getmode(mode):
if not _modes: if not _modes:
# initialize mode cache # initialize mode cache
import Image from . import Image
# core modes # core modes
for m, (basemode, basetype, bands) in Image._MODEINFO.items(): for m, (basemode, basetype, bands) in Image._MODEINFO.items():
_modes[m] = ModeDescriptor(m, bands, basemode, basetype) _modes[m] = ModeDescriptor(m, bands, basemode, basetype)

View File

@ -17,8 +17,9 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import Image from . import Image
import operator import operator
from functools import reduce
## ##
# (New in 1.1.3) The <b>ImageOps</b> module contains a number of # (New in 1.1.3) The <b>ImageOps</b> module contains a number of
@ -32,7 +33,7 @@ import operator
# helpers # helpers
def _border(border): def _border(border):
if type(border) is type(()): if isinstance(border, tuple):
if len(border) == 2: if len(border) == 2:
left, top = right, bottom = border left, top = right, bottom = border
elif len(border) == 4: elif len(border) == 4:
@ -43,7 +44,7 @@ def _border(border):
def _color(color, mode): def _color(color, mode):
if Image.isStringType(color): if Image.isStringType(color):
import ImageColor from . import ImageColor
color = ImageColor.getcolor(color, mode) color = ImageColor.getcolor(color, mode)
return color return color
@ -56,7 +57,7 @@ def _lut(image, lut):
lut = lut + lut + lut lut = lut + lut + lut
return image.point(lut) return image.point(lut)
else: else:
raise IOError, "not supported for this image mode" raise IOError("not supported for this image mode")
# #
# actions # actions
@ -94,7 +95,7 @@ def autocontrast(image, cutoff=0, ignore=None):
for ix in range(256): for ix in range(256):
n = n + h[ix] n = n + h[ix]
# remove cutoff% pixels from the low end # remove cutoff% pixels from the low end
cut = n * cutoff / 100 cut = n * cutoff // 100
for lo in range(256): for lo in range(256):
if cut > h[lo]: if cut > h[lo]:
cut = cut - h[lo] cut = cut - h[lo]
@ -105,7 +106,7 @@ def autocontrast(image, cutoff=0, ignore=None):
if cut <= 0: if cut <= 0:
break break
# remove cutoff% samples from the hi end # remove cutoff% samples from the hi end
cut = n * cutoff / 100 cut = n * cutoff // 100
for hi in range(255, -1, -1): for hi in range(255, -1, -1):
if cut > h[hi]: if cut > h[hi]:
cut = cut - h[hi] cut = cut - h[hi]
@ -124,7 +125,7 @@ def autocontrast(image, cutoff=0, ignore=None):
break break
if hi <= lo: if hi <= lo:
# don't bother # don't bother
lut.extend(range(256)) lut.extend(list(range(256)))
else: else:
scale = 255.0 / (hi - lo) scale = 255.0 / (hi - lo)
offset = -lo * scale offset = -lo * scale
@ -155,9 +156,9 @@ def colorize(image, black, white):
white = _color(white, "RGB") white = _color(white, "RGB")
red = []; green = []; blue = [] red = []; green = []; blue = []
for i in range(256): for i in range(256):
red.append(black[0]+i*(white[0]-black[0])/255) red.append(black[0]+i*(white[0]-black[0])//255)
green.append(black[1]+i*(white[1]-black[1])/255) green.append(black[1]+i*(white[1]-black[1])//255)
blue.append(black[2]+i*(white[2]-black[2])/255) blue.append(black[2]+i*(white[2]-black[2])//255)
image = image.convert("RGB") image = image.convert("RGB")
return _lut(image, red + green + blue) return _lut(image, red + green + blue)
@ -209,17 +210,17 @@ def equalize(image, mask=None):
h = image.histogram(mask) h = image.histogram(mask)
lut = [] lut = []
for b in range(0, len(h), 256): for b in range(0, len(h), 256):
histo = filter(None, h[b:b+256]) histo = [_f for _f in h[b:b+256] if _f]
if len(histo) <= 1: if len(histo) <= 1:
lut.extend(range(256)) lut.extend(list(range(256)))
else: else:
step = (reduce(operator.add, histo) - histo[-1]) / 255 step = (reduce(operator.add, histo) - histo[-1]) // 255
if not step: if not step:
lut.extend(range(256)) lut.extend(list(range(256)))
else: else:
n = step / 2 n = step // 2
for i in range(256): for i in range(256):
lut.append(n / step) lut.append(n // step)
n = n + h[i+b] n = n + h[i+b]
return _lut(image, lut) return _lut(image, lut)
@ -274,7 +275,7 @@ def fit(image, size, method=Image.NEAREST, bleed=0.0, centering=(0.5, 0.5)):
# http://www.cazabon.com # http://www.cazabon.com
# ensure inputs are valid # ensure inputs are valid
if type(centering) != type([]): if not isinstance(centering, list):
centering = [centering[0], centering[1]] centering = [centering[0], centering[1]]
if centering[0] > 1.0 or centering[0] < 0.0: if centering[0] > 1.0 or centering[0] < 0.0:

View File

@ -17,7 +17,7 @@
# #
import array import array
import Image, ImageColor from . import Image, ImageColor
## ##
# Colour palette wrapper for palette mapped images. # Colour palette wrapper for palette mapped images.
@ -28,38 +28,42 @@ class ImagePalette:
def __init__(self, mode = "RGB", palette = None): def __init__(self, mode = "RGB", palette = None):
self.mode = mode self.mode = mode
self.rawmode = None # if set, palette contains raw data self.rawmode = None # if set, palette contains raw data
self.palette = palette or range(256)*len(self.mode) self.palette = palette or list(range(256))*len(self.mode)
self.colors = {} self.colors = {}
self.dirty = None self.dirty = None
if len(self.mode)*256 != len(self.palette): if len(self.mode)*256 != len(self.palette):
raise ValueError, "wrong palette size" raise ValueError("wrong palette size")
def getdata(self): def getdata(self):
# experimental: get palette contents in format suitable # experimental: get palette contents in format suitable
# for the low-level im.putpalette primitive # for the low-level im.putpalette primitive
if self.rawmode: if self.rawmode:
return self.rawmode, self.palette return self.rawmode, self.palette
return self.mode + ";L", self.tostring() return self.mode + ";L", self.tobytes()
def tostring(self): def tobytes(self):
# experimental: convert palette to string # experimental: convert palette to bytes
if self.rawmode: if self.rawmode:
raise ValueError("palette contains raw palette data") raise ValueError("palette contains raw palette data")
if Image.isStringType(self.palette): if isinstance(self.palette, bytes):
return self.palette return self.palette
return array.array("B", self.palette).tostring() return array.array("B", self.palette).tostring()
if bytes is str:
# Declare tostring as an alias for tobytes
tostring = tobytes
def getcolor(self, color): def getcolor(self, color):
# experimental: given an rgb tuple, allocate palette entry # experimental: given an rgb tuple, allocate palette entry
if self.rawmode: if self.rawmode:
raise ValueError("palette contains raw palette data") raise ValueError("palette contains raw palette data")
if Image.isTupleType(color): if isinstance(color, tuple):
try: try:
return self.colors[color] return self.colors[color]
except KeyError: except KeyError:
# allocate new color slot # allocate new color slot
if Image.isStringType(self.palette): if isinstance(self.palette, bytes):
self.palette = map(int, self.palette) self.palette = [int(x) for x in self.palette]
index = len(self.colors) index = len(self.colors)
if index >= 256: if index >= 256:
raise ValueError("cannot allocate more than 256 colors") raise ValueError("cannot allocate more than 256 colors")
@ -76,7 +80,7 @@ class ImagePalette:
# (experimental) save palette to text file # (experimental) save palette to text file
if self.rawmode: if self.rawmode:
raise ValueError("palette contains raw palette data") raise ValueError("palette contains raw palette data")
if type(fp) == type(""): if isinstance(fp, str):
fp = open(fp, "w") fp = open(fp, "w")
fp.write("# Palette\n") fp.write("# Palette\n")
fp.write("# Mode: %s\n" % self.mode) fp.write("# Mode: %s\n" % self.mode)
@ -104,7 +108,7 @@ def _make_linear_lut(black, white):
lut = [] lut = []
if black == 0: if black == 0:
for i in range(256): for i in range(256):
lut.append(white*i/255) lut.append(white*i//255)
else: else:
raise NotImplementedError # FIXME raise NotImplementedError # FIXME
return lut return lut
@ -119,7 +123,7 @@ def new(mode, data):
return Image.core.new_palette(mode, data) return Image.core.new_palette(mode, data)
def negative(mode="RGB"): def negative(mode="RGB"):
palette = range(256) palette = list(range(256))
palette.reverse() palette.reverse()
return ImagePalette(mode, palette * len(mode)) return ImagePalette(mode, palette * len(mode))
@ -138,7 +142,7 @@ def sepia(white="#fff0c0"):
return ImagePalette("RGB", r + g + b) return ImagePalette("RGB", r + g + b)
def wedge(mode="RGB"): def wedge(mode="RGB"):
return ImagePalette(mode, range(256) * len(mode)) return ImagePalette(mode, list(range(256)) * len(mode))
def load(filename): def load(filename):
@ -150,33 +154,39 @@ def load(filename):
if not lut: if not lut:
try: try:
import GimpPaletteFile from . import GimpPaletteFile
fp.seek(0) fp.seek(0)
p = GimpPaletteFile.GimpPaletteFile(fp) p = GimpPaletteFile.GimpPaletteFile(fp)
lut = p.getpalette() lut = p.getpalette()
except (SyntaxError, ValueError): except (SyntaxError, ValueError):
#import traceback
#traceback.print_exc()
pass pass
if not lut: if not lut:
try: try:
import GimpGradientFile from . import GimpGradientFile
fp.seek(0) fp.seek(0)
p = GimpGradientFile.GimpGradientFile(fp) p = GimpGradientFile.GimpGradientFile(fp)
lut = p.getpalette() lut = p.getpalette()
except (SyntaxError, ValueError): except (SyntaxError, ValueError):
#import traceback
#traceback.print_exc()
pass pass
if not lut: if not lut:
try: try:
import PaletteFile from . import PaletteFile
fp.seek(0) fp.seek(0)
p = PaletteFile.PaletteFile(fp) p = PaletteFile.PaletteFile(fp)
lut = p.getpalette() lut = p.getpalette()
except (SyntaxError, ValueError): except (SyntaxError, ValueError):
import traceback
traceback.print_exc()
pass pass
if not lut: if not lut:
raise IOError, "cannot load palette" raise IOError("cannot load palette")
return lut # data, rawmode return lut # data, rawmode

View File

@ -14,7 +14,7 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import Image from . import Image
## ##
# Path wrapper. # Path wrapper.

View File

@ -15,7 +15,7 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import Image from . import Image
from PyQt4.QtGui import QImage, qRgb from PyQt4.QtGui import QImage, qRgb
@ -62,11 +62,11 @@ class ImageQt(QImage):
for i in range(0, len(palette), 3): for i in range(0, len(palette), 3):
colortable.append(rgb(*palette[i:i+3])) colortable.append(rgb(*palette[i:i+3]))
elif im.mode == "RGB": elif im.mode == "RGB":
data = im.tostring("raw", "BGRX") data = im.tobytes("raw", "BGRX")
format = QImage.Format_RGB32 format = QImage.Format_RGB32
elif im.mode == "RGBA": elif im.mode == "RGBA":
try: try:
data = im.tostring("raw", "BGRA") data = im.tobytes("raw", "BGRA")
except SystemError: except SystemError:
# workaround for earlier versions # workaround for earlier versions
r, g, b, a = im.split() r, g, b, a = im.split()
@ -76,7 +76,7 @@ class ImageQt(QImage):
raise ValueError("unsupported image mode %r" % im.mode) raise ValueError("unsupported image mode %r" % im.mode)
# must keep a reference, or Qt will crash! # must keep a reference, or Qt will crash!
self.__data = data or im.tostring() self.__data = data or im.tobytes()
QImage.__init__(self, self.__data, im.size[0], im.size[1], format) QImage.__init__(self, self.__data, im.size[0], im.size[1], format)

View File

@ -12,7 +12,9 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import Image from __future__ import print_function
from . import Image
import os, sys import os, sys
_viewers = [] _viewers = []
@ -160,4 +162,4 @@ else:
if __name__ == "__main__": if __name__ == "__main__":
# usage: python ImageShow.py imagefile [title] # usage: python ImageShow.py imagefile [title]
print show(Image.open(sys.argv[1]), *sys.argv[2:]) print(show(Image.open(sys.argv[1]), *sys.argv[2:]))

View File

@ -21,8 +21,9 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import Image from . import Image
import operator, math import operator, math
from functools import reduce
## ##
# The <b>ImageStat</b> module calculates global statistics for an # The <b>ImageStat</b> module calculates global statistics for an
@ -52,14 +53,14 @@ class Stat:
self.h = image_or_list.histogram() self.h = image_or_list.histogram()
except AttributeError: except AttributeError:
self.h = image_or_list # assume it to be a histogram list self.h = image_or_list # assume it to be a histogram list
if type(self.h) != type([]): if not isinstance(self.h, list):
raise TypeError, "first argument must be image or list" raise TypeError("first argument must be image or list")
self.bands = range(len(self.h) / 256) self.bands = list(range(len(self.h) // 256))
def __getattr__(self, id): def __getattr__(self, id):
"Calculate missing attribute" "Calculate missing attribute"
if id[:4] == "_get": if id[:4] == "_get":
raise AttributeError, id raise AttributeError(id)
# calculate missing attribute # calculate missing attribute
v = getattr(self, "_get" + id)() v = getattr(self, "_get" + id)()
setattr(self, id, v) setattr(self, id, v)
@ -126,7 +127,7 @@ class Stat:
v = [] v = []
for i in self.bands: for i in self.bands:
s = 0 s = 0
l = self.count[i]/2 l = self.count[i]//2
b = i * 256 b = i * 256
for j in range(256): for j in range(256):
s = s + self.h[b+j] s = s + self.h[b+j]

View File

@ -25,7 +25,14 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import Tkinter, Image try:
import tkinter
except ImportError:
import Tkinter
tkinter = Tkinter
del Tkinter
from . import Image
## ##
# The <b>ImageTk</b> module contains support to create and modify # The <b>ImageTk</b> module contains support to create and modify
@ -45,9 +52,9 @@ def _pilbitmap_check():
if _pilbitmap_ok is None: if _pilbitmap_ok is None:
try: try:
im = Image.new("1", (1,1)) im = Image.new("1", (1,1))
Tkinter.BitmapImage(data="PIL:%d" % im.im.id) tkinter.BitmapImage(data="PIL:%d" % im.im.id)
_pilbitmap_ok = 1 _pilbitmap_ok = 1
except Tkinter.TclError: except tkinter.TclError:
_pilbitmap_ok = 0 _pilbitmap_ok = 0
return _pilbitmap_ok return _pilbitmap_ok
@ -81,12 +88,12 @@ class PhotoImage:
# Tk compatibility: file or data # Tk compatibility: file or data
if image is None: if image is None:
if kw.has_key("file"): if "file" in kw:
image = Image.open(kw["file"]) image = Image.open(kw["file"])
del kw["file"] del kw["file"]
elif kw.has_key("data"): elif "data" in kw:
from StringIO import StringIO from io import BytesIO
image = Image.open(StringIO(kw["data"])) image = Image.open(BytesIO(kw["data"]))
del kw["data"] del kw["data"]
if hasattr(image, "mode") and hasattr(image, "size"): if hasattr(image, "mode") and hasattr(image, "size"):
@ -110,7 +117,7 @@ class PhotoImage:
self.__mode = mode self.__mode = mode
self.__size = size self.__size = size
self.__photo = apply(Tkinter.PhotoImage, (), kw) self.__photo = tkinter.PhotoImage(**kw)
self.tk = self.__photo.tk self.tk = self.__photo.tk
if image: if image:
self.paste(image) self.paste(image)
@ -175,7 +182,7 @@ class PhotoImage:
try: try:
tk.call("PyImagingPhoto", self.__photo, block.id) tk.call("PyImagingPhoto", self.__photo, block.id)
except Tkinter.TclError, v: except tkinter.TclError as v:
# activate Tkinter hook # activate Tkinter hook
try: try:
import _imagingtk import _imagingtk
@ -184,7 +191,7 @@ class PhotoImage:
except AttributeError: except AttributeError:
_imagingtk.tkinit(id(tk), 0) _imagingtk.tkinit(id(tk), 0)
tk.call("PyImagingPhoto", self.__photo, block.id) tk.call("PyImagingPhoto", self.__photo, block.id)
except (ImportError, AttributeError, Tkinter.TclError): except (ImportError, AttributeError, tkinter.TclError):
raise # configuration problem; cannot attach to Tkinter raise # configuration problem; cannot attach to Tkinter
# -------------------------------------------------------------------- # --------------------------------------------------------------------
@ -213,12 +220,12 @@ class BitmapImage:
# Tk compatibility: file or data # Tk compatibility: file or data
if image is None: if image is None:
if kw.has_key("file"): if "file" in kw:
image = Image.open(kw["file"]) image = Image.open(kw["file"])
del kw["file"] del kw["file"]
elif kw.has_key("data"): elif "data" in kw:
from StringIO import StringIO from io import BytesIO
image = Image.open(StringIO(kw["data"])) image = Image.open(BytesIO(kw["data"]))
del kw["data"] del kw["data"]
self.__mode = image.mode self.__mode = image.mode
@ -232,7 +239,7 @@ class BitmapImage:
else: else:
# slow but safe way # slow but safe way
kw["data"] = image.tobitmap() kw["data"] = image.tobitmap()
self.__photo = apply(Tkinter.BitmapImage, (), kw) self.__photo = tkinter.BitmapImage(**kw)
def __del__(self): def __del__(self):
name = self.__photo.name name = self.__photo.name
@ -279,18 +286,18 @@ def getimage(photo):
def _show(image, title): def _show(image, title):
class UI(Tkinter.Label): class UI(tkinter.Label):
def __init__(self, master, im): def __init__(self, master, im):
if im.mode == "1": if im.mode == "1":
self.image = BitmapImage(im, foreground="white", master=master) self.image = BitmapImage(im, foreground="white", master=master)
else: else:
self.image = PhotoImage(im, master=master) self.image = PhotoImage(im, master=master)
Tkinter.Label.__init__(self, master, image=self.image, tkinter.Label.__init__(self, master, image=self.image,
bg="black", bd=0) bg="black", bd=0)
if not Tkinter._default_root: if not tkinter._default_root:
raise IOError, "tkinter not initialized" raise IOError("tkinter not initialized")
top = Tkinter.Toplevel() top = tkinter.Toplevel()
if title: if title:
top.title(title) top.title(title)
UI(top, image).pack() UI(top, image).pack()

View File

@ -13,7 +13,7 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import Image from . import Image
class Transform(Image.ImageTransformHandler): class Transform(Image.ImageTransformHandler):
def __init__(self, data): def __init__(self, data):

View File

@ -17,7 +17,7 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import Image from . import Image
## ##
# The <b>ImageWin</b> module contains support to create and display # The <b>ImageWin</b> module contains support to create and display
@ -151,22 +151,25 @@ class Dib:
self.image.paste(im.im) self.image.paste(im.im)
## ##
# Load display memory contents from string buffer. # Load display memory contents from byte data.
# #
# @param buffer A string buffer containing display data (usually # @param buffer A buffer containing display data (usually
# data returned from <b>tostring</b>) # data returned from <b>tobytes</b>)
def fromstring(self, buffer): def frombytes(self, buffer):
return self.image.fromstring(buffer) return self.image.frombytes(buffer)
## ##
# Copy display memory contents to string buffer. # Copy display memory contents to bytes object.
# #
# @return A string buffer containing display data. # @return A bytes object containing display data.
def tostring(self): def tobytes(self):
return self.image.tostring() return self.image.tobytes()
if bytes is str:
tostring = tobytes
fromstring = frombytes
## ##
# Create a Window with the given title size. # Create a Window with the given title size.
@ -179,7 +182,7 @@ class Window:
) )
def __dispatcher(self, action, *args): def __dispatcher(self, action, *args):
return apply(getattr(self, "ui_handle_" + action), args) return getattr(self, "ui_handle_" + action)(*args)
def ui_handle_clear(self, dc, x0, y0, x1, y1): def ui_handle_clear(self, dc, x0, y0, x1, y1):
pass pass

View File

@ -19,12 +19,12 @@ __version__ = "0.2"
import re import re
import Image, ImageFile from . import Image, ImageFile
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
field = re.compile(r"([a-z]*) ([^ \r\n]*)") field = re.compile(br"([a-z]*) ([^ \r\n]*)")
## ##
# Image plugin for IM Tools images. # Image plugin for IM Tools images.
@ -39,19 +39,19 @@ class ImtImageFile(ImageFile.ImageFile):
# Quick rejection: if there's not a LF among the first # Quick rejection: if there's not a LF among the first
# 100 bytes, this is (probably) not a text header. # 100 bytes, this is (probably) not a text header.
if not "\n" in self.fp.read(100): if not b"\n" in self.fp.read(100):
raise SyntaxError, "not an IM file" raise SyntaxError("not an IM file")
self.fp.seek(0) self.fp.seek(0)
xsize = ysize = 0 xsize = ysize = 0
while 1: while True:
s = self.fp.read(1) s = self.fp.read(1)
if not s: if not s:
break break
if s == chr(12): if s == b'\x0C':
# image data begins # image data begins
self.tile = [("raw", (0,0)+self.size, self.tile = [("raw", (0,0)+self.size,
@ -67,7 +67,7 @@ class ImtImageFile(ImageFile.ImageFile):
s = s + self.fp.readline() s = s + self.fp.readline()
if len(s) == 1 or len(s) > 100: if len(s) == 1 or len(s) > 100:
break break
if s[0] == "*": if s[0] == b"*":
continue # comment continue # comment
m = field.match(s) m = field.match(s)

View File

@ -15,37 +15,36 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
from __future__ import print_function
__version__ = "0.3" __version__ = "0.3"
import Image, ImageFile from . import Image, ImageFile, _binary
import os, tempfile import os, tempfile
i8 = _binary.i8
i16 = _binary.i16be
i32 = _binary.i32be
o8 = _binary.o8
COMPRESSION = { COMPRESSION = {
1: "raw", 1: "raw",
5: "jpeg" 5: "jpeg"
} }
PAD = chr(0) * 4 PAD = o8(0) * 4
# #
# Helpers # Helpers
def i16(c):
return ord(c[1]) + (ord(c[0])<<8)
def i32(c):
return ord(c[3]) + (ord(c[2])<<8) + (ord(c[1])<<16) + (ord(c[0])<<24)
def i(c): def i(c):
return i32((PAD + c)[-4:]) return i32((PAD + c)[-4:])
def dump(c): def dump(c):
for i in c: for i in c:
print "%02x" % ord(i), print("%02x" % i8(i), end=' ')
print print()
## ##
# Image plugin for IPTC/NAA datastreams. To read IPTC/NAA fields # Image plugin for IPTC/NAA datastreams. To read IPTC/NAA fields
@ -66,16 +65,16 @@ class IptcImageFile(ImageFile.ImageFile):
if not len(s): if not len(s):
return None, 0 return None, 0
tag = ord(s[1]), ord(s[2]) tag = i8(s[1]), i8(s[2])
# syntax # syntax
if ord(s[0]) != 0x1C or tag[0] < 1 or tag[0] > 9: if i8(s[0]) != 0x1C or tag[0] < 1 or tag[0] > 9:
raise SyntaxError, "invalid IPTC/NAA file" raise SyntaxError("invalid IPTC/NAA file")
# field size # field size
size = ord(s[3]) size = i8(s[3])
if size > 132: if size > 132:
raise IOError, "illegal field length in IPTC/NAA file" raise IOError("illegal field length in IPTC/NAA file")
elif size == 128: elif size == 128:
size = 0 size = 0
elif size > 128: elif size > 128:
@ -97,7 +96,7 @@ class IptcImageFile(ImageFile.ImageFile):
if sz != size[0]: if sz != size[0]:
return 0 return 0
y = 1 y = 1
while 1: while True:
self.fp.seek(sz, 1) self.fp.seek(sz, 1)
t, s = self.field() t, s = self.field()
if t != (8, 10): if t != (8, 10):
@ -110,7 +109,7 @@ class IptcImageFile(ImageFile.ImageFile):
def _open(self): def _open(self):
# load descriptive fields # load descriptive fields
while 1: while True:
offset = self.fp.tell() offset = self.fp.tell()
tag, size = self.field() tag, size = self.field()
if not tag or tag == (8,10): if not tag or tag == (8,10):
@ -119,7 +118,7 @@ class IptcImageFile(ImageFile.ImageFile):
tagdata = self.fp.read(size) tagdata = self.fp.read(size)
else: else:
tagdata = None tagdata = None
if tag in self.info.keys(): if tag in list(self.info.keys()):
if isinstance(self.info[tag], list): if isinstance(self.info[tag], list):
self.info[tag].append(tagdata) self.info[tag].append(tagdata)
else: else:
@ -130,10 +129,10 @@ class IptcImageFile(ImageFile.ImageFile):
# print tag, self.info[tag] # print tag, self.info[tag]
# mode # mode
layers = ord(self.info[(3,60)][0]) layers = i8(self.info[(3,60)][0])
component = ord(self.info[(3,60)][1]) component = i8(self.info[(3,60)][1])
if self.info.has_key((3,65)): if (3,65) in self.info:
id = ord(self.info[(3,65)][0])-1 id = i8(self.info[(3,65)][0])-1
else: else:
id = 0 id = 0
if layers == 1 and not component: if layers == 1 and not component:
@ -150,7 +149,7 @@ class IptcImageFile(ImageFile.ImageFile):
try: try:
compression = COMPRESSION[self.getint((3,120))] compression = COMPRESSION[self.getint((3,120))]
except KeyError: except KeyError:
raise IOError, "Unknown IPTC image compression" raise IOError("Unknown IPTC image compression")
# tile # tile
if tag == (8,10): if tag == (8,10):
@ -179,7 +178,7 @@ class IptcImageFile(ImageFile.ImageFile):
# To simplify access to the extracted file, # To simplify access to the extracted file,
# prepend a PPM header # prepend a PPM header
o.write("P5\n%d %d\n255\n" % self.size) o.write("P5\n%d %d\n255\n" % self.size)
while 1: while True:
type, size = self.field() type, size = self.field()
if type != (8, 10): if type != (8, 10):
break break
@ -218,8 +217,8 @@ Image.register_extension("IPTC", ".iim")
def getiptcinfo(im): def getiptcinfo(im):
import TiffImagePlugin, JpegImagePlugin from . import TiffImagePlugin, JpegImagePlugin
import StringIO import io
data = None data = None
@ -241,7 +240,7 @@ def getiptcinfo(im):
code = JpegImagePlugin.i16(app, offset) code = JpegImagePlugin.i16(app, offset)
offset = offset + 2 offset = offset + 2
# resource name (usually empty) # resource name (usually empty)
name_len = ord(app[offset]) name_len = i8(app[offset])
name = app[offset+1:offset+1+name_len] name = app[offset+1:offset+1+name_len]
offset = 1 + offset + name_len offset = 1 + offset + name_len
if offset & 1: if offset & 1:
@ -278,7 +277,7 @@ def getiptcinfo(im):
# parse the IPTC information chunk # parse the IPTC information chunk
im.info = {} im.info = {}
im.fp = StringIO.StringIO(data) im.fp = io.BytesIO(data)
try: try:
im._open() im._open()

View File

@ -35,14 +35,12 @@
__version__ = "0.6" __version__ = "0.6"
import array, struct import array, struct
import string from . import Image, ImageFile, _binary
import Image, ImageFile
def i16(c,o=0): i8 = _binary.i8
return ord(c[o+1]) + (ord(c[o])<<8) o8 = _binary.o8
i16 = _binary.i16be
def i32(c,o=0): i32 = _binary.i32be
return ord(c[o+3]) + (ord(c[o+2])<<8) + (ord(c[o+1])<<16) + (ord(c[o])<<24)
# #
# Parser # Parser
@ -64,13 +62,13 @@ def APP(self, marker):
self.app[app] = s # compatibility self.app[app] = s # compatibility
self.applist.append((app, s)) self.applist.append((app, s))
if marker == 0xFFE0 and s[:4] == "JFIF": if marker == 0xFFE0 and s[:4] == b"JFIF":
# extract JFIF information # extract JFIF information
self.info["jfif"] = version = i16(s, 5) # version self.info["jfif"] = version = i16(s, 5) # version
self.info["jfif_version"] = divmod(version, 256) self.info["jfif_version"] = divmod(version, 256)
# extract JFIF properties # extract JFIF properties
try: try:
jfif_unit = ord(s[7]) jfif_unit = i8(s[7])
jfif_density = i16(s, 8), i16(s, 10) jfif_density = i16(s, 8), i16(s, 10)
except: except:
pass pass
@ -79,13 +77,13 @@ def APP(self, marker):
self.info["dpi"] = jfif_density self.info["dpi"] = jfif_density
self.info["jfif_unit"] = jfif_unit self.info["jfif_unit"] = jfif_unit
self.info["jfif_density"] = jfif_density self.info["jfif_density"] = jfif_density
elif marker == 0xFFE1 and s[:5] == "Exif\0": elif marker == 0xFFE1 and s[:5] == b"Exif\0":
# extract Exif information (incomplete) # extract Exif information (incomplete)
self.info["exif"] = s # FIXME: value will change self.info["exif"] = s # FIXME: value will change
elif marker == 0xFFE2 and s[:5] == "FPXR\0": elif marker == 0xFFE2 and s[:5] == b"FPXR\0":
# extract FlashPix information (incomplete) # extract FlashPix information (incomplete)
self.info["flashpix"] = s # FIXME: value will change self.info["flashpix"] = s # FIXME: value will change
elif marker == 0xFFE2 and s[:12] == "ICC_PROFILE\0": elif marker == 0xFFE2 and s[:12] == b"ICC_PROFILE\0":
# Since an ICC profile can be larger than the maximum size of # Since an ICC profile can be larger than the maximum size of
# a JPEG marker (64K), we need provisions to split it into # a JPEG marker (64K), we need provisions to split it into
# multiple markers. The format defined by the ICC specifies # multiple markers. The format defined by the ICC specifies
@ -98,11 +96,11 @@ def APP(self, marker):
# reassemble the profile, rather than assuming that the APP2 # reassemble the profile, rather than assuming that the APP2
# markers appear in the correct sequence. # markers appear in the correct sequence.
self.icclist.append(s) self.icclist.append(s)
elif marker == 0xFFEE and s[:5] == "Adobe": elif marker == 0xFFEE and s[:5] == b"Adobe":
self.info["adobe"] = i16(s, 5) self.info["adobe"] = i16(s, 5)
# extract Adobe custom properties # extract Adobe custom properties
try: try:
adobe_transform = ord(s[1]) adobe_transform = i8(s[1])
except: except:
pass pass
else: else:
@ -130,11 +128,11 @@ def SOF(self, marker):
s = ImageFile._safe_read(self.fp, n) s = ImageFile._safe_read(self.fp, n)
self.size = i16(s[3:]), i16(s[1:]) self.size = i16(s[3:]), i16(s[1:])
self.bits = ord(s[0]) self.bits = i8(s[0])
if self.bits != 8: if self.bits != 8:
raise SyntaxError("cannot handle %d-bit layers" % self.bits) raise SyntaxError("cannot handle %d-bit layers" % self.bits)
self.layers = ord(s[5]) self.layers = i8(s[5])
if self.layers == 1: if self.layers == 1:
self.mode = "L" self.mode = "L"
elif self.layers == 3: elif self.layers == 3:
@ -150,11 +148,11 @@ def SOF(self, marker):
if self.icclist: if self.icclist:
# fixup icc profile # fixup icc profile
self.icclist.sort() # sort by sequence number self.icclist.sort() # sort by sequence number
if ord(self.icclist[0][13]) == len(self.icclist): if i8(self.icclist[0][13]) == len(self.icclist):
profile = [] profile = []
for p in self.icclist: for p in self.icclist:
profile.append(p[14:]) profile.append(p[14:])
icc_profile = string.join(profile, "") icc_profile = b"".join(profile)
else: else:
icc_profile = None # wrong number of fragments icc_profile = None # wrong number of fragments
self.info["icc_profile"] = icc_profile self.info["icc_profile"] = icc_profile
@ -163,7 +161,7 @@ def SOF(self, marker):
for i in range(6, len(s), 3): for i in range(6, len(s), 3):
t = s[i:i+3] t = s[i:i+3]
# 4-tuples: id, vsamp, hsamp, qtable # 4-tuples: id, vsamp, hsamp, qtable
self.layer.append((t[0], ord(t[1])/16, ord(t[1])&15, ord(t[2]))) self.layer.append((t[0], i8(t[1])//16, i8(t[1])&15, i8(t[2])))
def DQT(self, marker): def DQT(self, marker):
# #
@ -179,8 +177,8 @@ def DQT(self, marker):
while len(s): while len(s):
if len(s) < 65: if len(s) < 65:
raise SyntaxError("bad quantization table marker") raise SyntaxError("bad quantization table marker")
v = ord(s[0]) v = i8(s[0])
if v/16 == 0: if v//16 == 0:
self.quantization[v&15] = array.array("b", s[1:65]) self.quantization[v&15] = array.array("b", s[1:65])
s = s[65:] s = s[65:]
else: else:
@ -259,7 +257,7 @@ MARKER = {
def _accept(prefix): def _accept(prefix):
return prefix[0] == "\377" return prefix[0:1] == b"\377"
## ##
# Image plugin for JPEG and JFIF images. # Image plugin for JPEG and JFIF images.
@ -273,7 +271,7 @@ class JpegImageFile(ImageFile.ImageFile):
s = self.fp.read(1) s = self.fp.read(1)
if ord(s[0]) != 255: if i8(s[0]) != 255:
raise SyntaxError("not a JPEG file") raise SyntaxError("not a JPEG file")
# Create attributes # Create attributes
@ -288,13 +286,13 @@ class JpegImageFile(ImageFile.ImageFile):
self.applist = [] self.applist = []
self.icclist = [] self.icclist = []
while 1: while True:
s = s + self.fp.read(1) s = s + self.fp.read(1)
i = i16(s) i = i16(s)
if MARKER.has_key(i): if i in MARKER:
name, description, handler = MARKER[i] name, description, handler = MARKER[i]
# print hex(i), name, description # print hex(i), name, description
if handler is not None: if handler is not None:
@ -326,12 +324,12 @@ class JpegImageFile(ImageFile.ImageFile):
a = mode, "" a = mode, ""
if size: if size:
scale = max(self.size[0] / size[0], self.size[1] / size[1]) scale = max(self.size[0] // size[0], self.size[1] // size[1])
for s in [8, 4, 2, 1]: for s in [8, 4, 2, 1]:
if scale >= s: if scale >= s:
break break
e = e[0], e[1], (e[2]-e[0]+s-1)/s+e[0], (e[3]-e[1]+s-1)/s+e[1] e = e[0], e[1], (e[2]-e[0]+s-1)//s+e[0], (e[3]-e[1]+s-1)//s+e[1]
self.size = ((self.size[0]+s-1)/s, (self.size[1]+s-1)/s) self.size = ((self.size[0]+s-1)//s, (self.size[1]+s-1)//s)
scale = s scale = s
self.tile = [(d, e, o, a)] self.tile = [(d, e, o, a)]
@ -362,7 +360,8 @@ class JpegImageFile(ImageFile.ImageFile):
# Extract EXIF information. This method is highly experimental, # Extract EXIF information. This method is highly experimental,
# and is likely to be replaced with something better in a future # and is likely to be replaced with something better in a future
# version. # version.
import TiffImagePlugin, StringIO from . import TiffImagePlugin
import io
def fixup(value): def fixup(value):
if len(value) == 1: if len(value) == 1:
return value[0] return value[0]
@ -373,7 +372,7 @@ class JpegImageFile(ImageFile.ImageFile):
data = self.info["exif"] data = self.info["exif"]
except KeyError: except KeyError:
return None return None
file = StringIO.StringIO(data[6:]) file = io.BytesIO(data[6:])
head = file.read(8) head = file.read(8)
exif = {} exif = {}
# process dictionary # process dictionary
@ -436,7 +435,7 @@ def _save(im, fp, filename):
elif subsampling == "4:1:1": elif subsampling == "4:1:1":
subsampling = 2 subsampling = 2
extra = "" extra = b""
icc_profile = info.get("icc_profile") icc_profile = info.get("icc_profile")
if icc_profile: if icc_profile:
@ -450,7 +449,7 @@ def _save(im, fp, filename):
i = 1 i = 1
for marker in markers: for marker in markers:
size = struct.pack(">H", 2 + ICC_OVERHEAD_LEN + len(marker)) size = struct.pack(">H", 2 + ICC_OVERHEAD_LEN + len(marker))
extra = extra + ("\xFF\xE2" + size + "ICC_PROFILE\0" + chr(i) + chr(len(markers)) + marker) extra = extra + (b"\xFF\xE2" + size + b"ICC_PROFILE\0" + o8(i) + o8(len(markers)) + marker)
i = i + 1 i = i + 1
# get keyword arguments # get keyword arguments
@ -459,9 +458,9 @@ def _save(im, fp, filename):
# "progressive" is the official name, but older documentation # "progressive" is the official name, but older documentation
# says "progression" # says "progression"
# FIXME: issue a warning if the wrong form is used (post-1.1.7) # FIXME: issue a warning if the wrong form is used (post-1.1.7)
info.has_key("progressive") or info.has_key("progression"), "progressive" in info or "progression" in info,
info.get("smooth", 0), info.get("smooth", 0),
info.has_key("optimize"), "optimize" in info,
info.get("streamtype", 0), info.get("streamtype", 0),
dpi[0], dpi[1], dpi[0], dpi[1],
subsampling, subsampling,

View File

@ -19,10 +19,10 @@
__version__ = "0.2" __version__ = "0.2"
import struct import struct
import Image, ImageFile from . import Image, ImageFile
def _accept(s): def _accept(s):
return s[:8] == "\x00\x00\x00\x00\x00\x00\x00\x04" return s[:8] == b"\x00\x00\x00\x00\x00\x00\x00\x04"
## ##
# Image plugin for McIdas area images. # Image plugin for McIdas area images.

View File

@ -20,8 +20,8 @@
__version__ = "0.1" __version__ = "0.1"
import Image, TiffImagePlugin from . import Image, TiffImagePlugin
from OleFileIO import * from .OleFileIO import *
# #
@ -47,7 +47,7 @@ class MicImageFile(TiffImagePlugin.TiffImageFile):
try: try:
self.ole = OleFileIO(self.fp) self.ole = OleFileIO(self.fp)
except IOError: except IOError:
raise SyntaxError, "not an MIC file; invalid OLE file" raise SyntaxError("not an MIC file; invalid OLE file")
# find ACI subfiles with Image members (maybe not the # find ACI subfiles with Image members (maybe not the
# best way to identify MIC files, but what the... ;-) # best way to identify MIC files, but what the... ;-)
@ -60,7 +60,7 @@ class MicImageFile(TiffImagePlugin.TiffImageFile):
# if we didn't find any images, this is probably not # if we didn't find any images, this is probably not
# an MIC file. # an MIC file.
if not self.images: if not self.images:
raise SyntaxError, "not an MIC file; no image entries" raise SyntaxError("not an MIC file; no image entries")
self.__fp = self.fp self.__fp = self.fp
self.frame = 0 self.frame = 0
@ -75,7 +75,7 @@ class MicImageFile(TiffImagePlugin.TiffImageFile):
try: try:
filename = self.images[frame] filename = self.images[frame]
except IndexError: except IndexError:
raise EOFError, "no such frame" raise EOFError("no such frame")
self.fp = self.ole.openstream(filename) self.fp = self.ole.openstream(filename)

View File

@ -15,7 +15,8 @@
__version__ = "0.1" __version__ = "0.1"
import Image, ImageFile from . import Image, ImageFile
from ._binary import i8
# #
# Bitstream parser # Bitstream parser
@ -28,7 +29,7 @@ class BitStream:
self.bitbuffer = 0 self.bitbuffer = 0
def next(self): def next(self):
return ord(self.fp.read(1)) return i8(self.fp.read(1))
def peek(self, bits): def peek(self, bits):
while self.bits < bits: while self.bits < bits:
@ -38,11 +39,11 @@ class BitStream:
continue continue
self.bitbuffer = (self.bitbuffer << 8) + c self.bitbuffer = (self.bitbuffer << 8) + c
self.bits = self.bits + 8 self.bits = self.bits + 8
return self.bitbuffer >> (self.bits - bits) & (1L << bits) - 1 return self.bitbuffer >> (self.bits - bits) & (1 << bits) - 1
def skip(self, bits): def skip(self, bits):
while self.bits < bits: while self.bits < bits:
self.bitbuffer = (self.bitbuffer << 8) + ord(self.fp.read(1)) self.bitbuffer = (self.bitbuffer << 8) + i8(self.fp.read(1))
self.bits = self.bits + 8 self.bits = self.bits + 8
self.bits = self.bits - bits self.bits = self.bits - bits
@ -65,7 +66,7 @@ class MpegImageFile(ImageFile.ImageFile):
s = BitStream(self.fp) s = BitStream(self.fp)
if s.read(32) != 0x1B3: if s.read(32) != 0x1B3:
raise SyntaxError, "not an MPEG file" raise SyntaxError("not an MPEG file")
self.mode = "RGB" self.mode = "RGB"
self.size = s.read(12), s.read(12) self.size = s.read(12), s.read(12)

View File

@ -19,17 +19,16 @@
__version__ = "0.1" __version__ = "0.1"
import Image, ImageFile from . import Image, ImageFile, _binary
# #
# read MSP files # read MSP files
def i16(c): i16 = _binary.i16le
return ord(c[0]) + (ord(c[1])<<8)
def _accept(prefix): def _accept(prefix):
return prefix[:4] in ["DanM", "LinS"] return prefix[:4] in [b"DanM", b"LinS"]
## ##
# Image plugin for Windows MSP images. This plugin supports both # Image plugin for Windows MSP images. This plugin supports both
@ -44,20 +43,20 @@ class MspImageFile(ImageFile.ImageFile):
# Header # Header
s = self.fp.read(32) s = self.fp.read(32)
if s[:4] not in ["DanM", "LinS"]: if s[:4] not in [b"DanM", b"LinS"]:
raise SyntaxError, "not an MSP file" raise SyntaxError("not an MSP file")
# Header checksum # Header checksum
sum = 0 sum = 0
for i in range(0, 32, 2): for i in range(0, 32, 2):
sum = sum ^ i16(s[i:i+2]) sum = sum ^ i16(s[i:i+2])
if sum != 0: if sum != 0:
raise SyntaxError, "bad MSP checksum" raise SyntaxError("bad MSP checksum")
self.mode = "1" self.mode = "1"
self.size = i16(s[4:]), i16(s[6:]) self.size = i16(s[4:]), i16(s[6:])
if s[:4] == "DanM": if s[:4] == b"DanM":
self.tile = [("raw", (0,0)+self.size, 32, ("1", 0, 1))] self.tile = [("raw", (0,0)+self.size, 32, ("1", 0, 1))]
else: else:
self.tile = [("msp", (0,0)+self.size, 32+2*self.size[1], None)] self.tile = [("msp", (0,0)+self.size, 32+2*self.size[1], None)]
@ -65,18 +64,17 @@ class MspImageFile(ImageFile.ImageFile):
# #
# write MSP files (uncompressed only) # write MSP files (uncompressed only)
def o16(i): o16 = _binary.o16le
return chr(i&255) + chr(i>>8&255)
def _save(im, fp, filename): def _save(im, fp, filename):
if im.mode != "1": if im.mode != "1":
raise IOError, "cannot write mode %s as MSP" % im.mode raise IOError("cannot write mode %s as MSP" % im.mode)
# create MSP header # create MSP header
header = [0] * 16 header = [0] * 16
header[0], header[1] = i16("Da"), i16("nM") # version 1 header[0], header[1] = i16(b"Da"), i16(b"nM") # version 1
header[2], header[3] = im.size header[2], header[3] = im.size
header[4], header[5] = 1, 1 header[4], header[5] = 1, 1
header[6], header[7] = 1, 1 header[6], header[7] = 1, 1

View File

@ -36,17 +36,21 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import string, StringIO from __future__ import print_function
import io
import sys
from . import _binary
if str is not bytes:
long = int
i8 = _binary.i8
i16 = _binary.i16le
i32 = _binary.i32le
def i16(c, o = 0): MAGIC = b'\320\317\021\340\241\261\032\341'
return ord(c[o])+(ord(c[o+1])<<8)
def i32(c, o = 0):
return ord(c[o])+(ord(c[o+1])<<8)+(ord(c[o+2])<<16)+(ord(c[o+3])<<24)
MAGIC = '\320\317\021\340\241\261\032\341'
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
@ -65,7 +69,7 @@ VT_VECTOR=0x1000;
# map property id to name (for debugging purposes) # map property id to name (for debugging purposes)
VT = {} VT = {}
for k, v in vars().items(): for k, v in list(vars().items()):
if k[:3] == "VT_": if k[:3] == "VT_":
VT[v] = k VT[v] = k
@ -79,7 +83,7 @@ WORD_CLSID = "00020900-0000-0000-C000-000000000046"
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
class _OleStream(StringIO.StringIO): class _OleStream(io.BytesIO):
"""OLE2 Stream """OLE2 Stream
@ -105,11 +109,11 @@ class _OleStream(StringIO.StringIO):
data.append(fp.read(sectorsize)) data.append(fp.read(sectorsize))
sect = fat[sect] sect = fat[sect]
data = string.join(data, "") data = b"".join(data)
# print len(data), size # print len(data), size
StringIO.StringIO.__init__(self, data[:size]) io.BytesIO.__init__(self, data[:size])
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
@ -173,7 +177,7 @@ class _OleDirectoryEntry:
if right != -1: # 0xFFFFFFFFL: if right != -1: # 0xFFFFFFFFL:
# and then back to the left # and then back to the left
sid = right sid = right
while 1: while True:
left, right, child = sidlist[sid][4] left, right, child = sidlist[sid][4]
if left == -1: # 0xFFFFFFFFL: if left == -1: # 0xFFFFFFFFL:
break break
@ -181,7 +185,7 @@ class _OleDirectoryEntry:
sid = left sid = left
else: else:
# couldn't move right; move up instead # couldn't move right; move up instead
while 1: while True:
ptr = stack[-1] ptr = stack[-1]
del stack[-1] del stack[-1]
left, right, child = sidlist[ptr][4] left, right, child = sidlist[ptr][4]
@ -208,12 +212,12 @@ class _OleDirectoryEntry:
TYPES = ["(invalid)", "(storage)", "(stream)", "(lockbytes)", TYPES = ["(invalid)", "(storage)", "(stream)", "(lockbytes)",
"(property)", "(root)"] "(property)", "(root)"]
print " "*tab + repr(self.name), TYPES[self.type], print(" "*tab + repr(self.name), TYPES[self.type], end=' ')
if self.type in (2, 5): if self.type in (2, 5):
print self.size, "bytes", print(self.size, "bytes", end=' ')
print print()
if self.type in (1, 5) and self.clsid: if self.type in (1, 5) and self.clsid:
print " "*tab + "{%s}" % self.clsid print(" "*tab + "{%s}" % self.clsid)
for kid in self.kids: for kid in self.kids:
kid.dump(tab + 2) kid.dump(tab + 2)
@ -265,7 +269,7 @@ class OleFileIO:
def open(self, filename): def open(self, filename):
"""Open an OLE2 file""" """Open an OLE2 file"""
if type(filename) == type(""): if isinstance(filename, str):
self.fp = open(filename, "rb") self.fp = open(filename, "rb")
else: else:
self.fp = filename self.fp = filename
@ -273,7 +277,7 @@ class OleFileIO:
header = self.fp.read(512) header = self.fp.read(512)
if len(header) != 512 or header[:8] != MAGIC: if len(header) != 512 or header[:8] != MAGIC:
raise IOError, "not an OLE2 structured storage file" raise IOError("not an OLE2 structured storage file")
# file clsid (probably never used, so we don't store it) # file clsid (probably never used, so we don't store it)
clsid = self._clsid(header[8:24]) clsid = self._clsid(header[8:24])
@ -307,7 +311,7 @@ class OleFileIO:
if ix == -2 or ix == -1: # ix == 0xFFFFFFFEL or ix == 0xFFFFFFFFL: if ix == -2 or ix == -1: # ix == 0xFFFFFFFEL or ix == 0xFFFFFFFFL:
break break
s = self.getsect(ix) s = self.getsect(ix)
fat = fat + map(lambda i, s=s: i32(s, i), range(0, len(s), 4)) fat = fat + [i32(s, i) for i in range(0, len(s), 4)]
self.fat = fat self.fat = fat
def loadminifat(self): def loadminifat(self):
@ -316,7 +320,7 @@ class OleFileIO:
s = self._open(self.minifatsect).read() s = self._open(self.minifatsect).read()
self.minifat = map(lambda i, s=s: i32(s, i), range(0, len(s), 4)) self.minifat = [i32(s, i) for i in range(0, len(s), 4)]
def getsect(self, sect): def getsect(self, sect):
# Read given sector # Read given sector
@ -327,9 +331,12 @@ class OleFileIO:
def _unicode(self, s): def _unicode(self, s):
# Map unicode string to Latin 1 # Map unicode string to Latin 1
# FIXME: some day, Python will provide an official way to handle if bytes is str:
# Unicode strings, but until then, this will have to do... # Old version tried to produce a Latin-1 str
return filter(ord, s) return s.decode('utf-16').encode('latin-1', 'replace')
else:
# Provide actual Unicode string
return s.decode('utf-16')
def loaddirectory(self, sect): def loaddirectory(self, sect):
# Load the directory. The directory is stored in a standard # Load the directory. The directory is stored in a standard
@ -340,11 +347,11 @@ class OleFileIO:
# create list of sid entries # create list of sid entries
self.sidlist = [] self.sidlist = []
while 1: while True:
entry = fp.read(128) entry = fp.read(128)
if not entry: if not entry:
break break
type = ord(entry[66]) type = i8(entry[66])
name = self._unicode(entry[0:0+i16(entry, 64)]) name = self._unicode(entry[0:0+i16(entry, 64)])
ptrs = i32(entry, 68), i32(entry, 72), i32(entry, 76) ptrs = i32(entry, 68), i32(entry, 72), i32(entry, 76)
sect, size = i32(entry, 116), i32(entry, 120) sect, size = i32(entry, 116), i32(entry, 120)
@ -364,7 +371,7 @@ class OleFileIO:
return "" return ""
return (("%08X-%04X-%04X-%02X%02X-" + "%02X" * 6) % return (("%08X-%04X-%04X-%02X%02X-" + "%02X" * 6) %
((i32(clsid, 0), i16(clsid, 4), i16(clsid, 6)) + ((i32(clsid, 0), i16(clsid, 4), i16(clsid, 6)) +
tuple(map(ord, clsid[8:16])))) tuple(map(i8, clsid[8:16]))))
def _list(self, files, prefix, node): def _list(self, files, prefix, node):
# listdir helper # listdir helper
@ -385,7 +392,7 @@ class OleFileIO:
if kid.name == name: if kid.name == name:
break break
else: else:
raise IOError, "file not found" raise IOError("file not found")
node = kid node = kid
return node.sid return node.sid
@ -423,7 +430,7 @@ class OleFileIO:
slot = self._find(filename) slot = self._find(filename)
name, type, sect, size, sids, clsid = self.sidlist[slot] name, type, sect, size, sids, clsid = self.sidlist[slot]
if type != 2: if type != 2:
raise IOError, "this file is not a stream" raise IOError("this file is not a stream")
return self._open(sect, size) return self._open(sect, size)
## ##
@ -480,9 +487,9 @@ class OleFileIO:
value = long(i32(s, offset+4)) + (long(i32(s, offset+8))<<32) value = long(i32(s, offset+4)) + (long(i32(s, offset+8))<<32)
# FIXME: this is a 64-bit int: "number of 100ns periods # FIXME: this is a 64-bit int: "number of 100ns periods
# since Jan 1,1601". Should map this to Python time # since Jan 1,1601". Should map this to Python time
value = value / 10000000L # seconds value = value // 10000000 # seconds
elif type == VT_UI1: elif type == VT_UI1:
value = ord(s[offset+4]) value = i8(s[offset+4])
elif type == VT_CLSID: elif type == VT_CLSID:
value = self._clsid(s[offset+4:offset+20]) value = self._clsid(s[offset+4:offset+20])
elif type == VT_CF: elif type == VT_CF:
@ -512,17 +519,16 @@ if __name__ == "__main__":
for file in sys.argv[1:]: for file in sys.argv[1:]:
try: try:
ole = OleFileIO(file) ole = OleFileIO(file)
print "-" * 68 print("-" * 68)
print file print(file)
print "-" * 68 print("-" * 68)
ole.dumpdirectory() ole.dumpdirectory()
for file in ole.listdir(): for file in ole.listdir():
if file[-1][0] == "\005": if file[-1][0] == "\005":
print file print(file)
props = ole.getproperties(file) props = ole.getproperties(file)
props = props.items() props = sorted(props.items())
props.sort()
for k, v in props: for k, v in props:
print " ", k, v print(" ", k, v)
except IOError, v: except IOError as v:
print "***", "cannot read", file, "-", v print("***", "cannot read", file, "-", v)

View File

@ -15,8 +15,9 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import EpsImagePlugin from __future__ import print_function
import string
from . import EpsImagePlugin
## ##
# Simple Postscript graphics interface. # Simple Postscript graphics interface.
@ -52,7 +53,7 @@ class PSDraw:
self.fp.flush() self.fp.flush()
def setfont(self, font, size): def setfont(self, font, size):
if not self.isofont.has_key(font): if font not in self.isofont:
# reencode font # reencode font
self.fp.write("/PSDraw-%s ISOLatin1Encoding /%s E\n" %\ self.fp.write("/PSDraw-%s ISOLatin1Encoding /%s E\n" %\
(font, font)) (font, font))
@ -61,7 +62,7 @@ class PSDraw:
self.fp.write("/F0 %d /PSDraw-%s F\n" % (size, font)) self.fp.write("/F0 %d /PSDraw-%s F\n" % (size, font))
def setink(self, ink): def setink(self, ink):
print "*** NOT YET IMPLEMENTED ***" print("*** NOT YET IMPLEMENTED ***")
def line(self, xy0, xy1): def line(self, xy0, xy1):
xy = xy0 + xy1 xy = xy0 + xy1
@ -71,8 +72,8 @@ class PSDraw:
self.fp.write("%d %d M %d %d 0 Vr\n" % box) self.fp.write("%d %d M %d %d 0 Vr\n" % box)
def text(self, xy, text): def text(self, xy, text):
text = string.joinfields(string.splitfields(text, "("), "\\(") text = "\\(".join(text.split("("))
text = string.joinfields(string.splitfields(text, ")"), "\\)") text = "\\)".join(text.split(")"))
xy = xy + (text,) xy = xy + (text,)
self.fp.write("%d %d M (%s) S\n" % xy) self.fp.write("%d %d M (%s) S\n" % xy)

View File

@ -13,7 +13,7 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import string from ._binary import o8
## ##
# File handler for Teragon-style palette files. # File handler for Teragon-style palette files.
@ -24,20 +24,20 @@ class PaletteFile:
def __init__(self, fp): def __init__(self, fp):
self.palette = map(lambda i: (i, i, i), range(256)) self.palette = [(i, i, i) for i in range(256)]
while 1: while True:
s = fp.readline() s = fp.readline()
if not s: if not s:
break break
if s[0] == "#": if s[0:1] == b"#":
continue continue
if len(s) > 100: if len(s) > 100:
raise SyntaxError, "bad palette file" raise SyntaxError("bad palette file")
v = map(int, string.split(s)) v = [int(x) for x in s.split()]
try: try:
[i, r, g, b] = v [i, r, g, b] = v
except ValueError: except ValueError:
@ -45,9 +45,9 @@ class PaletteFile:
g = b = r g = b = r
if 0 <= i <= 255: if 0 <= i <= 255:
self.palette[i] = chr(r) + chr(g) + chr(b) self.palette[i] = o8(r) + o8(g) + o8(b)
self.palette = string.join(self.palette, "") self.palette = b"".join(self.palette)
def getpalette(self): def getpalette(self):

View File

@ -9,7 +9,7 @@
__version__ = "1.0" __version__ = "1.0"
import Image, ImageFile from . import Image, ImageFile, _binary
_Palm8BitColormapValues = ( _Palm8BitColormapValues = (
( 255, 255, 255 ), ( 255, 204, 255 ), ( 255, 153, 255 ), ( 255, 102, 255 ), ( 255, 255, 255 ), ( 255, 204, 255 ), ( 255, 153, 255 ), ( 255, 102, 255 ),
@ -80,7 +80,7 @@ _Palm8BitColormapValues = (
# so build a prototype image to be used for palette resampling # so build a prototype image to be used for palette resampling
def build_prototype_image(): def build_prototype_image():
image = Image.new("L", (1,len(_Palm8BitColormapValues),)) image = Image.new("L", (1,len(_Palm8BitColormapValues),))
image.putdata(range(len(_Palm8BitColormapValues))) image.putdata(list(range(len(_Palm8BitColormapValues))))
palettedata = () palettedata = ()
for i in range(len(_Palm8BitColormapValues)): for i in range(len(_Palm8BitColormapValues)):
palettedata = palettedata + _Palm8BitColormapValues[i] palettedata = palettedata + _Palm8BitColormapValues[i]
@ -107,8 +107,8 @@ _COMPRESSION_TYPES = {
"scanline": 0x00, "scanline": 0x00,
} }
def o16b(i): o8 = _binary.o8
return chr(i>>8&255) + chr(i&255) o16b = _binary.o16be
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
@ -127,7 +127,7 @@ def _save(im, fp, filename, check=0):
bpp = 8 bpp = 8
version = 1 version = 1
elif im.mode == "L" and im.encoderinfo.has_key("bpp") and im.encoderinfo["bpp"] in (1, 2, 4): elif im.mode == "L" and "bpp" in im.encoderinfo and im.encoderinfo["bpp"] in (1, 2, 4):
# this is 8-bit grayscale, so we shift it to get the high-order bits, and invert it because # this is 8-bit grayscale, so we shift it to get the high-order bits, and invert it because
# Palm does greyscale from white (0) to black (1) # Palm does greyscale from white (0) to black (1)
@ -138,7 +138,7 @@ def _save(im, fp, filename, check=0):
rawmode = "P;" + str(bpp) rawmode = "P;" + str(bpp)
version = 1 version = 1
elif im.mode == "L" and im.info.has_key("bpp") and im.info["bpp"] in (1, 2, 4): elif im.mode == "L" and "bpp" in im.info and im.info["bpp"] in (1, 2, 4):
# here we assume that even though the inherent mode is 8-bit grayscale, only # here we assume that even though the inherent mode is 8-bit grayscale, only
# the lower bpp bits are significant. We invert them to match the Palm. # the lower bpp bits are significant. We invert them to match the Palm.
@ -158,7 +158,7 @@ def _save(im, fp, filename, check=0):
else: else:
raise IOError, "cannot write mode %s as Palm" % im.mode raise IOError("cannot write mode %s as Palm" % im.mode)
if check: if check:
return check return check
@ -172,12 +172,12 @@ def _save(im, fp, filename, check=0):
cols = im.size[0] cols = im.size[0]
rows = im.size[1] rows = im.size[1]
rowbytes = ((cols + (16/bpp - 1)) / (16 / bpp)) * 2; rowbytes = ((cols + (16//bpp - 1)) / (16 // bpp)) * 2;
transparent_index = 0 transparent_index = 0
compression_type = _COMPRESSION_TYPES["none"] compression_type = _COMPRESSION_TYPES["none"]
flags = 0; flags = 0;
if im.mode == "P" and im.info.has_key("custom-colormap"): if im.mode == "P" and "custom-colormap" in im.info:
flags = flags & _FLAGS["custom-colormap"] flags = flags & _FLAGS["custom-colormap"]
colormapsize = 4 * 256 + 2; colormapsize = 4 * 256 + 2;
colormapmode = im.palette.mode colormapmode = im.palette.mode
@ -185,17 +185,17 @@ def _save(im, fp, filename, check=0):
else: else:
colormapsize = 0 colormapsize = 0
if im.info.has_key("offset"): if "offset" in im.info:
offset = (rowbytes * rows + 16 + 3 + colormapsize) / 4; offset = (rowbytes * rows + 16 + 3 + colormapsize) // 4;
else: else:
offset = 0 offset = 0
fp.write(o16b(cols) + o16b(rows) + o16b(rowbytes) + o16b(flags)) fp.write(o16b(cols) + o16b(rows) + o16b(rowbytes) + o16b(flags))
fp.write(chr(bpp)) fp.write(o8(bpp))
fp.write(chr(version)) fp.write(o8(version))
fp.write(o16b(offset)) fp.write(o16b(offset))
fp.write(chr(transparent_index)) fp.write(o8(transparent_index))
fp.write(chr(compression_type)) fp.write(o8(compression_type))
fp.write(o16b(0)) # reserved by Palm fp.write(o16b(0)) # reserved by Palm
# now write colormap if necessary # now write colormap if necessary
@ -203,11 +203,11 @@ def _save(im, fp, filename, check=0):
if colormapsize > 0: if colormapsize > 0:
fp.write(o16b(256)) fp.write(o16b(256))
for i in range(256): for i in range(256):
fp.write(chr(i)) fp.write(o8(i))
if colormapmode == 'RGB': if colormapmode == 'RGB':
fp.write(chr(colormap[3 * i]) + chr(colormap[3 * i + 1]) + chr(colormap[3 * i + 2])) fp.write(o8(colormap[3 * i]) + o8(colormap[3 * i + 1]) + o8(colormap[3 * i + 2]))
elif colormapmode == 'RGBA': elif colormapmode == 'RGBA':
fp.write(chr(colormap[4 * i]) + chr(colormap[4 * i + 1]) + chr(colormap[4 * i + 2])) fp.write(o8(colormap[4 * i]) + o8(colormap[4 * i + 1]) + o8(colormap[4 * i + 2]))
# now convert data to raw form # now convert data to raw form
ImageFile._save(im, fp, [("raw", (0,0)+im.size, 0, (rawmode, rowbytes, 1))]) ImageFile._save(im, fp, [("raw", (0,0)+im.size, 0, (rawmode, rowbytes, 1))])

View File

@ -18,7 +18,9 @@
__version__ = "0.1" __version__ = "0.1"
import Image, ImageFile from . import Image, ImageFile, _binary
i8 = _binary.i8
## ##
# Image plugin for PhotoCD images. This plugin only reads the 768x512 # Image plugin for PhotoCD images. This plugin only reads the 768x512
@ -36,10 +38,10 @@ class PcdImageFile(ImageFile.ImageFile):
self.fp.seek(2048) self.fp.seek(2048)
s = self.fp.read(2048) s = self.fp.read(2048)
if s[:4] != "PCD_": if s[:4] != b"PCD_":
raise SyntaxError, "not a PCD file" raise SyntaxError("not a PCD file")
orientation = ord(s[1538]) & 3 orientation = i8(s[1538]) & 3
if orientation == 1: if orientation == 1:
self.tile_post_rotate = 90 # hack self.tile_post_rotate = 90 # hack
elif orientation == 3: elif orientation == 3:

View File

@ -16,10 +16,9 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import Image from . import Image
import FontFile from . import FontFile
from . import _binary
import string
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# declarations # declarations
@ -43,19 +42,14 @@ BYTES_PER_ROW = [
lambda bits: ((bits+63) >> 3) & ~7, lambda bits: ((bits+63) >> 3) & ~7,
] ]
i8 = _binary.i8
def l16(c): l16 = _binary.i16le
return ord(c[0]) + (ord(c[1])<<8) l32 = _binary.i32le
def l32(c): b16 = _binary.i16be
return ord(c[0]) + (ord(c[1])<<8) + (ord(c[2])<<16) + (ord(c[3])<<24) b32 = _binary.i32be
def b16(c):
return ord(c[1]) + (ord(c[0])<<8)
def b32(c):
return ord(c[3]) + (ord(c[2])<<8) + (ord(c[1])<<16) + (ord(c[0])<<24)
def sz(s, o): def sz(s, o):
return s[o:string.index(s, "\0", o)] return s[o:s.index(b"\0", o)]
## ##
# Font file plugin for the X11 PCF format. # Font file plugin for the X11 PCF format.
@ -68,7 +62,7 @@ class PcfFontFile(FontFile.FontFile):
magic = l32(fp.read(4)) magic = l32(fp.read(4))
if magic != PCF_MAGIC: if magic != PCF_MAGIC:
raise SyntaxError, "not a PCF file" raise SyntaxError("not a PCF file")
FontFile.FontFile.__init__(self) FontFile.FontFile.__init__(self)
@ -126,7 +120,7 @@ class PcfFontFile(FontFile.FontFile):
# read property description # read property description
p = [] p = []
for i in range(nprops): for i in range(nprops):
p.append((i32(fp.read(4)), ord(fp.read(1)), i32(fp.read(4)))) p.append((i32(fp.read(4)), i8(fp.read(1)), i32(fp.read(4))))
if nprops & 3: if nprops & 3:
fp.seek(4 - (nprops & 3), 1) # pad fp.seek(4 - (nprops & 3), 1) # pad
@ -155,11 +149,11 @@ class PcfFontFile(FontFile.FontFile):
# "compressed" metrics # "compressed" metrics
for i in range(i16(fp.read(2))): for i in range(i16(fp.read(2))):
left = ord(fp.read(1)) - 128 left = i8(fp.read(1)) - 128
right = ord(fp.read(1)) - 128 right = i8(fp.read(1)) - 128
width = ord(fp.read(1)) - 128 width = i8(fp.read(1)) - 128
ascent = ord(fp.read(1)) - 128 ascent = i8(fp.read(1)) - 128
descent = ord(fp.read(1)) - 128 descent = i8(fp.read(1)) - 128
xsize = right - left xsize = right - left
ysize = ascent + descent ysize = ascent + descent
append( append(
@ -198,7 +192,7 @@ class PcfFontFile(FontFile.FontFile):
nbitmaps = i32(fp.read(4)) nbitmaps = i32(fp.read(4))
if nbitmaps != len(metrics): if nbitmaps != len(metrics):
raise IOError, "Wrong number of bitmaps" raise IOError("Wrong number of bitmaps")
offsets = [] offsets = []
for i in range(nbitmaps): for i in range(nbitmaps):
@ -226,7 +220,7 @@ class PcfFontFile(FontFile.FontFile):
x, y, l, r, w, a, d, f = metrics[i] x, y, l, r, w, a, d, f = metrics[i]
b, e = offsets[i], offsets[i+1] b, e = offsets[i], offsets[i+1]
bitmaps.append( bitmaps.append(
Image.fromstring("1", (x, y), data[b:e], "raw", mode, pad(x)) Image.frombytes("1", (x, y), data[b:e], "raw", mode, pad(x))
) )
return bitmaps return bitmaps

View File

@ -27,13 +27,14 @@
__version__ = "0.6" __version__ = "0.6"
import Image, ImageFile, ImagePalette from . import Image, ImageFile, ImagePalette, _binary
def i16(c,o): i8 = _binary.i8
return ord(c[o]) + (ord(c[o+1])<<8) i16 = _binary.i16le
o8 = _binary.o8
def _accept(prefix): def _accept(prefix):
return ord(prefix[0]) == 10 and ord(prefix[1]) in [0, 2, 3, 5] return i8(prefix[0]) == 10 and i8(prefix[1]) in [0, 2, 3, 5]
## ##
# Image plugin for Paintbrush images. # Image plugin for Paintbrush images.
@ -48,17 +49,17 @@ class PcxImageFile(ImageFile.ImageFile):
# header # header
s = self.fp.read(128) s = self.fp.read(128)
if not _accept(s): if not _accept(s):
raise SyntaxError, "not a PCX file" raise SyntaxError("not a PCX file")
# image # image
bbox = i16(s,4), i16(s,6), i16(s,8)+1, i16(s,10)+1 bbox = i16(s,4), i16(s,6), i16(s,8)+1, i16(s,10)+1
if bbox[2] <= bbox[0] or bbox[3] <= bbox[1]: if bbox[2] <= bbox[0] or bbox[3] <= bbox[1]:
raise SyntaxError, "bad PCX image size" raise SyntaxError("bad PCX image size")
# format # format
version = ord(s[1]) version = i8(s[1])
bits = ord(s[3]) bits = i8(s[3])
planes = ord(s[65]) planes = i8(s[65])
stride = i16(s,66) stride = i16(s,66)
self.info["dpi"] = i16(s,12), i16(s,14) self.info["dpi"] = i16(s,12), i16(s,14)
@ -76,10 +77,10 @@ class PcxImageFile(ImageFile.ImageFile):
# FIXME: hey, this doesn't work with the incremental loader !!! # FIXME: hey, this doesn't work with the incremental loader !!!
self.fp.seek(-769, 2) self.fp.seek(-769, 2)
s = self.fp.read(769) s = self.fp.read(769)
if len(s) == 769 and ord(s[0]) == 12: if len(s) == 769 and i8(s[0]) == 12:
# check if the palette is linear greyscale # check if the palette is linear greyscale
for i in range(256): for i in range(256):
if s[i*3+1:i*3+4] != chr(i)*3: if s[i*3+1:i*3+4] != o8(i)*3:
mode = rawmode = "P" mode = rawmode = "P"
break break
if mode == "P": if mode == "P":
@ -91,7 +92,7 @@ class PcxImageFile(ImageFile.ImageFile):
rawmode = "RGB;L" rawmode = "RGB;L"
else: else:
raise IOError, "unknown PCX mode" raise IOError("unknown PCX mode")
self.mode = mode self.mode = mode
self.size = bbox[2]-bbox[0], bbox[3]-bbox[1] self.size = bbox[2]-bbox[0], bbox[3]-bbox[1]
@ -111,21 +112,20 @@ SAVE = {
"RGB": (5, 8, 3, "RGB;L"), "RGB": (5, 8, 3, "RGB;L"),
} }
def o16(i): o16 = _binary.o16le
return chr(i&255) + chr(i>>8&255)
def _save(im, fp, filename, check=0): def _save(im, fp, filename, check=0):
try: try:
version, bits, planes, rawmode = SAVE[im.mode] version, bits, planes, rawmode = SAVE[im.mode]
except KeyError: except KeyError:
raise ValueError, "Cannot save %s images as PCX" % im.mode raise ValueError("Cannot save %s images as PCX" % im.mode)
if check: if check:
return check return check
# bytes per plane # bytes per plane
stride = (im.size[0] * bits + 7) / 8 stride = (im.size[0] * bits + 7) // 8
# under windows, we could determine the current screen size with # under windows, we could determine the current screen size with
# "Image.core.display_mode()[1]", but I think that's overkill... # "Image.core.display_mode()[1]", but I think that's overkill...
@ -136,11 +136,11 @@ def _save(im, fp, filename, check=0):
# PCX header # PCX header
fp.write( fp.write(
chr(10) + chr(version) + chr(1) + chr(bits) + o16(0) + o8(10) + o8(version) + o8(1) + o8(bits) + o16(0) +
o16(0) + o16(im.size[0]-1) + o16(im.size[1]-1) + o16(dpi[0]) + o16(0) + o16(im.size[0]-1) + o16(im.size[1]-1) + o16(dpi[0]) +
o16(dpi[1]) + chr(0)*24 + chr(255)*24 + chr(0) + chr(planes) + o16(dpi[1]) + b"\0"*24 + b"\xFF"*24 + b"\0" + o8(planes) +
o16(stride) + o16(1) + o16(screen[0]) + o16(screen[1]) + o16(stride) + o16(1) + o16(screen[0]) + o16(screen[1]) +
chr(0)*54 b"\0"*54
) )
assert fp.tell() == 128 assert fp.tell() == 128
@ -150,13 +150,13 @@ def _save(im, fp, filename, check=0):
if im.mode == "P": if im.mode == "P":
# colour palette # colour palette
fp.write(chr(12)) fp.write(o8(12))
fp.write(im.im.getpalette("RGB", "RGB")) # 768 bytes fp.write(im.im.getpalette("RGB", "RGB")) # 768 bytes
elif im.mode == "L": elif im.mode == "L":
# greyscale palette # greyscale palette
fp.write(chr(12)) fp.write(o8(12))
for i in range(256): for i in range(256):
fp.write(chr(i)*3) fp.write(o8(i)*3)
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# registry # registry

View File

@ -22,8 +22,9 @@
__version__ = "0.4" __version__ = "0.4"
import Image, ImageFile from . import Image, ImageFile
import StringIO from ._binary import i8
import io
# #
@ -60,6 +61,16 @@ def _save(im, fp, filename):
xref = [0]*(5+1) # placeholders xref = [0]*(5+1) # placeholders
class TextWriter:
def __init__(self, fp):
self.fp = fp
def __getattr__(self, name):
return getattr(self.fp, name)
def write(self, value):
self.fp.write(value.encode('latin-1'))
fp = TextWriter(fp)
fp.write("%PDF-1.2\n") fp.write("%PDF-1.2\n")
fp.write("% created by PIL PDF driver " + __version__ + "\n") fp.write("% created by PIL PDF driver " + __version__ + "\n")
@ -90,11 +101,11 @@ def _save(im, fp, filename):
colorspace = "[ /Indexed /DeviceRGB 255 <" colorspace = "[ /Indexed /DeviceRGB 255 <"
palette = im.im.getpalette("RGB") palette = im.im.getpalette("RGB")
for i in range(256): for i in range(256):
r = ord(palette[i*3]) r = i8(palette[i*3])
g = ord(palette[i*3+1]) g = i8(palette[i*3+1])
b = ord(palette[i*3+2]) b = i8(palette[i*3+2])
colorspace = colorspace + "%02x%02x%02x " % (r, g, b) colorspace = colorspace + "%02x%02x%02x " % (r, g, b)
colorspace = colorspace + "> ]" colorspace = colorspace + b"> ]"
procset = "/ImageI" # indexed color procset = "/ImageI" # indexed color
elif im.mode == "RGB": elif im.mode == "RGB":
filter = "/DCTDecode" filter = "/DCTDecode"
@ -127,7 +138,7 @@ def _save(im, fp, filename):
# #
# image # image
op = StringIO.StringIO() op = io.BytesIO()
if filter == "/ASCIIHexDecode": if filter == "/ASCIIHexDecode":
if bits == 1: if bits == 1:
@ -158,7 +169,7 @@ def _save(im, fp, filename):
ColorSpace = colorspace) ColorSpace = colorspace)
fp.write("stream\n") fp.write("stream\n")
fp.write(op.getvalue()) fp.fp.write(op.getvalue())
fp.write("\nendstream\n") fp.write("\nendstream\n")
_endobj(fp) _endobj(fp)
@ -178,15 +189,15 @@ def _save(im, fp, filename):
# #
# page contents # page contents
op = StringIO.StringIO() op = TextWriter(io.BytesIO())
op.write("q %d 0 0 %d 0 0 cm /image Do Q\n" % (int(width * 72.0 / resolution), int(height * 72.0 / resolution))) op.write("q %d 0 0 %d 0 0 cm /image Do Q\n" % (int(width * 72.0 / resolution), int(height * 72.0 / resolution)))
xref[5] = fp.tell() xref[5] = fp.tell()
_obj(fp, 5, Length = len(op.getvalue())) _obj(fp, 5, Length = len(op.fp.getvalue()))
fp.write("stream\n") fp.write("stream\n")
fp.write(op.getvalue()) fp.fp.write(op.fp.getvalue())
fp.write("\nendstream\n") fp.write("\nendstream\n")
_endobj(fp) _endobj(fp)

View File

@ -21,16 +21,13 @@
__version__ = "0.1" __version__ = "0.1"
import Image, ImageFile from . import Image, ImageFile, _binary
# #
# helpers # helpers
def i16(c): i16 = _binary.i16le
return ord(c[0]) + (ord(c[1])<<8) i32 = _binary.i32le
def i32(c):
return ord(c[0]) + (ord(c[1])<<8) + (ord(c[2])<<16) + (ord(c[3])<<24)
## ##
# Image plugin for PIXAR raster images. # Image plugin for PIXAR raster images.
@ -44,8 +41,8 @@ class PixarImageFile(ImageFile.ImageFile):
# assuming a 4-byte magic label (FIXME: add "_accept" hook) # assuming a 4-byte magic label (FIXME: add "_accept" hook)
s = self.fp.read(4) s = self.fp.read(4)
if s != "\200\350\000\000": if s != b"\200\350\000\000":
raise SyntaxError, "not a PIXAR file" raise SyntaxError("not a PIXAR file")
# read rest of header # read rest of header
s = s + self.fp.read(508) s = s + self.fp.read(508)

View File

@ -31,22 +31,23 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
from __future__ import print_function
__version__ = "0.9" __version__ = "0.9"
import re, string import re
import Image, ImageFile, ImagePalette, zlib from . import Image, ImageFile, ImagePalette, _binary
import zlib
i8 = _binary.i8
i16 = _binary.i16be
i32 = _binary.i32be
is_cid = re.compile(b"\w\w\w\w").match
def i16(c): _MAGIC = b"\211PNG\r\n\032\n"
return ord(c[1]) + (ord(c[0])<<8)
def i32(c):
return ord(c[3]) + (ord(c[2])<<8) + (ord(c[1])<<16) + (ord(c[0])<<24)
is_cid = re.compile("\w\w\w\w").match
_MAGIC = "\211PNG\r\n\032\n"
_MODES = { _MODES = {
@ -96,7 +97,7 @@ class ChunkStream:
len = i32(s) len = i32(s)
if not is_cid(cid): if not is_cid(cid):
raise SyntaxError, "broken PNG file (chunk %s)" % repr(cid) raise SyntaxError("broken PNG file (chunk %s)" % repr(cid))
return cid, pos, len return cid, pos, len
@ -111,8 +112,8 @@ class ChunkStream:
"Call the appropriate chunk handler" "Call the appropriate chunk handler"
if Image.DEBUG: if Image.DEBUG:
print "STREAM", cid, pos, len print("STREAM", cid, pos, len)
return getattr(self, "chunk_" + cid)(pos, len) return getattr(self, "chunk_" + cid.decode('ascii'))(pos, len)
def crc(self, cid, data): def crc(self, cid, data):
"Read and verify checksum" "Read and verify checksum"
@ -120,22 +121,22 @@ class ChunkStream:
crc1 = Image.core.crc32(data, Image.core.crc32(cid)) crc1 = Image.core.crc32(data, Image.core.crc32(cid))
crc2 = i16(self.fp.read(2)), i16(self.fp.read(2)) crc2 = i16(self.fp.read(2)), i16(self.fp.read(2))
if crc1 != crc2: if crc1 != crc2:
raise SyntaxError, "broken PNG file"\ raise SyntaxError("broken PNG file"\
"(bad header checksum in %s)" % cid "(bad header checksum in %s)" % cid)
def crc_skip(self, cid, data): def crc_skip(self, cid, data):
"Read checksum. Used if the C module is not present" "Read checksum. Used if the C module is not present"
self.fp.read(4) self.fp.read(4)
def verify(self, endchunk = "IEND"): def verify(self, endchunk = b"IEND"):
# Simple approach; just calculate checksum for all remaining # Simple approach; just calculate checksum for all remaining
# blocks. Must be called directly after open. # blocks. Must be called directly after open.
cids = [] cids = []
while 1: while True:
cid, pos, len = self.read() cid, pos, len = self.read()
if cid == endchunk: if cid == endchunk:
break break
@ -157,11 +158,18 @@ class PngInfo:
self.chunks.append((cid, data)) self.chunks.append((cid, data))
def add_text(self, key, value, zip=0): def add_text(self, key, value, zip=0):
# The tEXt chunk stores latin-1 text
if not isinstance(key, bytes):
key = key.encode('latin-1', 'strict')
if not isinstance(value, bytes):
value = value.encode('latin-1', 'replace')
if zip: if zip:
import zlib import zlib
self.add("zTXt", key + "\0\0" + zlib.compress(value)) self.add(b"zTXt", key + b"\0\0" + zlib.compress(value))
else: else:
self.add("tEXt", key + "\0" + value) self.add(b"tEXt", key + b"\0" + value)
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# PNG image stream (IHDR/IEND) # PNG image stream (IHDR/IEND)
@ -189,11 +197,11 @@ class PngStream(ChunkStream):
# Null separator 1 byte (null character) # Null separator 1 byte (null character)
# Compression method 1 byte (0) # Compression method 1 byte (0)
# Compressed profile n bytes (zlib with deflate compression) # Compressed profile n bytes (zlib with deflate compression)
i = string.find(s, chr(0)) i = s.find(b"\0")
if Image.DEBUG: if Image.DEBUG:
print "iCCP profile name", s[:i] print("iCCP profile name", s[:i])
print "Compression method", ord(s[i]) print("Compression method", i8(s[i]))
comp_method = ord(s[i]) comp_method = i8(s[i])
if comp_method != 0: if comp_method != 0:
raise SyntaxError("Unknown compression method %s in iCCP chunk" % comp_method) raise SyntaxError("Unknown compression method %s in iCCP chunk" % comp_method)
try: try:
@ -209,13 +217,13 @@ class PngStream(ChunkStream):
s = ImageFile._safe_read(self.fp, len) s = ImageFile._safe_read(self.fp, len)
self.im_size = i32(s), i32(s[4:]) self.im_size = i32(s), i32(s[4:])
try: try:
self.im_mode, self.im_rawmode = _MODES[(ord(s[8]), ord(s[9]))] self.im_mode, self.im_rawmode = _MODES[(i8(s[8]), i8(s[9]))]
except: except:
pass pass
if ord(s[12]): if i8(s[12]):
self.im_info["interlace"] = 1 self.im_info["interlace"] = 1
if ord(s[11]): if i8(s[11]):
raise SyntaxError, "unknown filter category" raise SyntaxError("unknown filter category")
return s return s
def chunk_IDAT(self, pos, len): def chunk_IDAT(self, pos, len):
@ -243,7 +251,7 @@ class PngStream(ChunkStream):
# transparency # transparency
s = ImageFile._safe_read(self.fp, len) s = ImageFile._safe_read(self.fp, len)
if self.im_mode == "P": if self.im_mode == "P":
i = string.find(s, chr(0)) i = s.find(b"\0")
if i >= 0: if i >= 0:
self.im_info["transparency"] = i self.im_info["transparency"] = i
elif self.im_mode == "L": elif self.im_mode == "L":
@ -264,7 +272,7 @@ class PngStream(ChunkStream):
# pixels per unit # pixels per unit
s = ImageFile._safe_read(self.fp, len) s = ImageFile._safe_read(self.fp, len)
px, py = i32(s), i32(s[4:]) px, py = i32(s), i32(s[4:])
unit = ord(s[8]) unit = i8(s[8])
if unit == 1: # meter if unit == 1: # meter
dpi = int(px * 0.0254 + 0.5), int(py * 0.0254 + 0.5) dpi = int(px * 0.0254 + 0.5), int(py * 0.0254 + 0.5)
self.im_info["dpi"] = dpi self.im_info["dpi"] = dpi
@ -277,10 +285,14 @@ class PngStream(ChunkStream):
# text # text
s = ImageFile._safe_read(self.fp, len) s = ImageFile._safe_read(self.fp, len)
try: try:
k, v = string.split(s, "\0", 1) k, v = s.split(b"\0", 1)
except ValueError: except ValueError:
k = s; v = "" # fallback for broken tEXt tags k = s; v = b"" # fallback for broken tEXt tags
if k: if k:
if bytes is not str:
k = k.decode('latin-1', 'strict')
v = v.decode('latin-1', 'replace')
self.im_info[k] = self.im_text[k] = v self.im_info[k] = self.im_text[k] = v
return s return s
@ -288,12 +300,18 @@ class PngStream(ChunkStream):
# compressed text # compressed text
s = ImageFile._safe_read(self.fp, len) s = ImageFile._safe_read(self.fp, len)
k, v = string.split(s, "\0", 1) k, v = s.split(b"\0", 1)
comp_method = ord(v[0]) comp_method = i8(v[0])
if comp_method != 0: if comp_method != 0:
raise SyntaxError("Unknown compression method %s in zTXt chunk" % comp_method) raise SyntaxError("Unknown compression method %s in zTXt chunk" % comp_method)
import zlib import zlib
self.im_info[k] = self.im_text[k] = zlib.decompress(v[1:]) v = zlib.decompress(v[1:])
if bytes is not str:
k = k.decode('latin-1', 'strict')
v = v.decode('latin-1', 'replace')
self.im_info[k] = self.im_text[k] = v
return s return s
# -------------------------------------------------------------------- # --------------------------------------------------------------------
@ -313,14 +331,14 @@ class PngImageFile(ImageFile.ImageFile):
def _open(self): def _open(self):
if self.fp.read(8) != _MAGIC: if self.fp.read(8) != _MAGIC:
raise SyntaxError, "not a PNG file" raise SyntaxError("not a PNG file")
# #
# Parse headers up to the first IDAT chunk # Parse headers up to the first IDAT chunk
self.png = PngStream(self.fp) self.png = PngStream(self.fp)
while 1: while True:
# #
# get next chunk # get next chunk
@ -333,7 +351,7 @@ class PngImageFile(ImageFile.ImageFile):
break break
except AttributeError: except AttributeError:
if Image.DEBUG: if Image.DEBUG:
print cid, pos, len, "(unknown)" print(cid, pos, len, "(unknown)")
s = ImageFile._safe_read(self.fp, len) s = ImageFile._safe_read(self.fp, len)
self.png.crc(cid, s) self.png.crc(cid, s)
@ -390,9 +408,9 @@ class PngImageFile(ImageFile.ImageFile):
cid, pos, len = self.png.read() cid, pos, len = self.png.read()
if cid not in ["IDAT", "DDAT"]: if cid not in [b"IDAT", b"DDAT"]:
self.png.push(cid, pos, len) self.png.push(cid, pos, len)
return "" return b""
self.__idat = len # empty chunks are allowed self.__idat = len # empty chunks are allowed
@ -417,33 +435,31 @@ class PngImageFile(ImageFile.ImageFile):
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# PNG writer # PNG writer
def o16(i): o8 = _binary.o8
return chr(i>>8&255) + chr(i&255) o16 = _binary.o16be
o32 = _binary.o32be
def o32(i):
return chr(i>>24&255) + chr(i>>16&255) + chr(i>>8&255) + chr(i&255)
_OUTMODES = { _OUTMODES = {
# supported PIL modes, and corresponding rawmodes/bits/color combinations # supported PIL modes, and corresponding rawmodes/bits/color combinations
"1": ("1", chr(1)+chr(0)), "1": ("1", b'\x01\x00'),
"L;1": ("L;1", chr(1)+chr(0)), "L;1": ("L;1", b'\x01\x00'),
"L;2": ("L;2", chr(2)+chr(0)), "L;2": ("L;2", b'\x02\x00'),
"L;4": ("L;4", chr(4)+chr(0)), "L;4": ("L;4", b'\x04\x00'),
"L": ("L", chr(8)+chr(0)), "L": ("L", b'\x08\x00'),
"LA": ("LA", chr(8)+chr(4)), "LA": ("LA", b'\x08\x04'),
"I": ("I;16B", chr(16)+chr(0)), "I": ("I;16B", b'\x10\x00'),
"P;1": ("P;1", chr(1)+chr(3)), "P;1": ("P;1", b'\x01\x03'),
"P;2": ("P;2", chr(2)+chr(3)), "P;2": ("P;2", b'\x02\x03'),
"P;4": ("P;4", chr(4)+chr(3)), "P;4": ("P;4", b'\x04\x03'),
"P": ("P", chr(8)+chr(3)), "P": ("P", b'\x08\x03'),
"RGB": ("RGB", chr(8)+chr(2)), "RGB": ("RGB", b'\x08\x02'),
"RGBA":("RGBA", chr(8)+chr(6)), "RGBA":("RGBA", b'\x08\x06'),
} }
def putchunk(fp, cid, *data): def putchunk(fp, cid, *data):
"Write a PNG chunk (including CRC field)" "Write a PNG chunk (including CRC field)"
data = string.join(data, "") data = b"".join(data)
fp.write(o32(len(data)) + cid) fp.write(o32(len(data)) + cid)
fp.write(data) fp.write(data)
@ -457,7 +473,7 @@ class _idat:
self.fp = fp self.fp = fp
self.chunk = chunk self.chunk = chunk
def write(self, data): def write(self, data):
self.chunk(self.fp, "IDAT", data) self.chunk(self.fp, b"IDAT", data)
def _save(im, fp, filename, chunk=putchunk, check=0): def _save(im, fp, filename, chunk=putchunk, check=0):
# save an image to disk (called by the save method) # save an image to disk (called by the save method)
@ -469,7 +485,7 @@ def _save(im, fp, filename, chunk=putchunk, check=0):
# #
# attempt to minimize storage requirements for palette images # attempt to minimize storage requirements for palette images
if im.encoderinfo.has_key("bits"): if "bits" in im.encoderinfo:
# number of bits specified by user # number of bits specified by user
n = 1 << im.encoderinfo["bits"] n = 1 << im.encoderinfo["bits"]
@ -492,18 +508,18 @@ def _save(im, fp, filename, chunk=putchunk, check=0):
mode = "%s;%d" % (mode, bits) mode = "%s;%d" % (mode, bits)
# encoder options # encoder options
if im.encoderinfo.has_key("dictionary"): if "dictionary" in im.encoderinfo:
dictionary = im.encoderinfo["dictionary"] dictionary = im.encoderinfo["dictionary"]
else: else:
dictionary = "" dictionary = b""
im.encoderconfig = (im.encoderinfo.has_key("optimize"), dictionary) im.encoderconfig = ("optimize" in im.encoderinfo, dictionary)
# get the corresponding PNG mode # get the corresponding PNG mode
try: try:
rawmode, mode = _OUTMODES[mode] rawmode, mode = _OUTMODES[mode]
except KeyError: except KeyError:
raise IOError, "cannot write mode %s as PNG" % mode raise IOError("cannot write mode %s as PNG" % mode)
if check: if check:
return check return check
@ -513,39 +529,39 @@ def _save(im, fp, filename, chunk=putchunk, check=0):
fp.write(_MAGIC) fp.write(_MAGIC)
chunk(fp, "IHDR", chunk(fp, b"IHDR",
o32(im.size[0]), o32(im.size[1]), # 0: size o32(im.size[0]), o32(im.size[1]), # 0: size
mode, # 8: depth/type mode, # 8: depth/type
chr(0), # 10: compression b'\0', # 10: compression
chr(0), # 11: filter category b'\0', # 11: filter category
chr(0)) # 12: interlace flag b'\0') # 12: interlace flag
if im.mode == "P": if im.mode == "P":
chunk(fp, "PLTE", im.im.getpalette("RGB")) chunk(fp, b"PLTE", im.im.getpalette("RGB"))
if im.encoderinfo.has_key("transparency"): if "transparency" in im.encoderinfo:
if im.mode == "P": if im.mode == "P":
transparency = max(0, min(255, im.encoderinfo["transparency"])) transparency = max(0, min(255, im.encoderinfo["transparency"]))
chunk(fp, "tRNS", chr(255) * transparency + chr(0)) chunk(fp, b"tRNS", b'\xFF' * transparency + b'\0')
elif im.mode == "L": elif im.mode == "L":
transparency = max(0, min(65535, im.encoderinfo["transparency"])) transparency = max(0, min(65535, im.encoderinfo["transparency"]))
chunk(fp, "tRNS", o16(transparency)) chunk(fp, b"tRNS", o16(transparency))
elif im.mode == "RGB": elif im.mode == "RGB":
red, green, blue = im.encoderinfo["transparency"] red, green, blue = im.encoderinfo["transparency"]
chunk(fp, "tRNS", o16(red) + o16(green) + o16(blue)) chunk(fp, b"tRNS", o16(red) + o16(green) + o16(blue))
else: else:
raise IOError("cannot use transparency for this mode") raise IOError("cannot use transparency for this mode")
if 0: if 0:
# FIXME: to be supported some day # FIXME: to be supported some day
chunk(fp, "gAMA", o32(int(gamma * 100000.0))) chunk(fp, b"gAMA", o32(int(gamma * 100000.0)))
dpi = im.encoderinfo.get("dpi") dpi = im.encoderinfo.get("dpi")
if dpi: if dpi:
chunk(fp, "pHYs", chunk(fp, b"pHYs",
o32(int(dpi[0] / 0.0254 + 0.5)), o32(int(dpi[0] / 0.0254 + 0.5)),
o32(int(dpi[1] / 0.0254 + 0.5)), o32(int(dpi[1] / 0.0254 + 0.5)),
chr(1)) b'\x01')
info = im.encoderinfo.get("pnginfo") info = im.encoderinfo.get("pnginfo")
if info: if info:
@ -553,7 +569,7 @@ def _save(im, fp, filename, chunk=putchunk, check=0):
chunk(fp, cid, data) chunk(fp, cid, data)
# ICC profile writing support -- 2008-06-06 Florian Hoech # ICC profile writing support -- 2008-06-06 Florian Hoech
if im.info.has_key("icc_profile"): if "icc_profile" in im.info:
# ICC profile # ICC profile
# according to PNG spec, the iCCP chunk contains: # according to PNG spec, the iCCP chunk contains:
# Profile name 1-79 bytes (character string) # Profile name 1-79 bytes (character string)
@ -565,13 +581,13 @@ def _save(im, fp, filename, chunk=putchunk, check=0):
p = ICCProfile.ICCProfile(im.info["icc_profile"]) p = ICCProfile.ICCProfile(im.info["icc_profile"])
name = p.tags.desc.get("ASCII", p.tags.desc.get("Unicode", p.tags.desc.get("Macintosh", p.tags.desc.get("en", {}).get("US", "ICC Profile")))).encode("latin1", "replace")[:79] name = p.tags.desc.get("ASCII", p.tags.desc.get("Unicode", p.tags.desc.get("Macintosh", p.tags.desc.get("en", {}).get("US", "ICC Profile")))).encode("latin1", "replace")[:79]
except ImportError: except ImportError:
name = "ICC Profile" name = b"ICC Profile"
data = name + "\0\0" + zlib.compress(im.info["icc_profile"]) data = name + b"\0\0" + zlib.compress(im.info["icc_profile"])
chunk(fp, "iCCP", data) chunk(fp, b"iCCP", data)
ImageFile._save(im, _idat(fp, chunk), [("zip", (0,0)+im.size, 0, rawmode)]) ImageFile._save(im, _idat(fp, chunk), [("zip", (0,0)+im.size, 0, rawmode)])
chunk(fp, "IEND", "") chunk(fp, b"IEND", b"")
try: try:
fp.flush() fp.flush()
@ -593,7 +609,7 @@ def getchunks(im, **params):
self.data.append(chunk) self.data.append(chunk)
def append(fp, cid, *data): def append(fp, cid, *data):
data = string.join(data, "") data = b"".join(data)
hi, lo = Image.core.crc32(data, Image.core.crc32(cid)) hi, lo = Image.core.crc32(data, Image.core.crc32(cid))
crc = o16(hi) + o16(lo) crc = o16(hi) + o16(lo)
fp.append((cid, data, crc)) fp.append((cid, data, crc))

View File

@ -19,26 +19,28 @@ __version__ = "0.2"
import string import string
import Image, ImageFile from . import Image, ImageFile
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
b_whitespace = string.whitespace.encode()
MODES = { MODES = {
# standard # standard
"P4": "1", b"P4": "1",
"P5": "L", b"P5": "L",
"P6": "RGB", b"P6": "RGB",
# extensions # extensions
"P0CMYK": "CMYK", b"P0CMYK": "CMYK",
# PIL extensions (for test purposes only) # PIL extensions (for test purposes only)
"PyP": "P", b"PyP": "P",
"PyRGBA": "RGBA", b"PyRGBA": "RGBA",
"PyCMYK": "CMYK" b"PyCMYK": "CMYK"
} }
def _accept(prefix): def _accept(prefix):
return prefix[0] == "P" and prefix[1] in "0456y" return prefix[0:1] == b"P" and prefix[1] in b"0456y"
## ##
# Image plugin for PBM, PGM, and PPM images. # Image plugin for PBM, PGM, and PPM images.
@ -48,10 +50,10 @@ class PpmImageFile(ImageFile.ImageFile):
format = "PPM" format = "PPM"
format_description = "Pbmplus image" format_description = "Pbmplus image"
def _token(self, s = ""): def _token(self, s = b""):
while 1: # read until next whitespace while True: # read until next whitespace
c = self.fp.read(1) c = self.fp.read(1)
if not c or c in string.whitespace: if not c or c in b_whitespace:
break break
s = s + c s = s + c
return s return s
@ -60,8 +62,8 @@ class PpmImageFile(ImageFile.ImageFile):
# check magic # check magic
s = self.fp.read(1) s = self.fp.read(1)
if s != "P": if s != b"P":
raise SyntaxError, "not a PPM file" raise SyntaxError("not a PPM file")
mode = MODES[self._token(s)] mode = MODES[self._token(s)]
if mode == "1": if mode == "1":
@ -71,12 +73,12 @@ class PpmImageFile(ImageFile.ImageFile):
self.mode = rawmode = mode self.mode = rawmode = mode
for ix in range(3): for ix in range(3):
while 1: while True:
while 1: while True:
s = self.fp.read(1) s = self.fp.read(1)
if s not in string.whitespace: if s not in b_whitespace:
break break
if s != "#": if s != b"#":
break break
s = self.fp.readline() s = self.fp.readline()
s = int(self._token(s)) s = int(self._token(s))
@ -103,18 +105,18 @@ class PpmImageFile(ImageFile.ImageFile):
def _save(im, fp, filename): def _save(im, fp, filename):
if im.mode == "1": if im.mode == "1":
rawmode, head = "1;I", "P4" rawmode, head = "1;I", b"P4"
elif im.mode == "L": elif im.mode == "L":
rawmode, head = "L", "P5" rawmode, head = "L", b"P5"
elif im.mode == "RGB": elif im.mode == "RGB":
rawmode, head = "RGB", "P6" rawmode, head = "RGB", b"P6"
elif im.mode == "RGBA": elif im.mode == "RGBA":
rawmode, head = "RGB", "P6" rawmode, head = "RGB", b"P6"
else: else:
raise IOError, "cannot write mode %s as PPM" % im.mode raise IOError("cannot write mode %s as PPM" % im.mode)
fp.write(head + "\n%d %d\n" % im.size) fp.write(head + ("\n%d %d\n" % im.size).encode('ascii'))
if head != "P4": if head != b"P4":
fp.write("255\n") fp.write(b"255\n")
ImageFile._save(im, fp, [("raw", (0,0)+im.size, 0, (rawmode, 0, 1))]) ImageFile._save(im, fp, [("raw", (0,0)+im.size, 0, (rawmode, 0, 1))])
# ALTERNATIVE: save via builtin debug function # ALTERNATIVE: save via builtin debug function

View File

@ -18,7 +18,7 @@
__version__ = "0.4" __version__ = "0.4"
import Image, ImageFile, ImagePalette from . import Image, ImageFile, ImagePalette, _binary
MODES = { MODES = {
# (photoshop mode, bits) -> (pil mode, required channels) # (photoshop mode, bits) -> (pil mode, required channels)
@ -36,17 +36,15 @@ MODES = {
# #
# helpers # helpers
def i16(c): i8 = _binary.i8
return ord(c[1]) + (ord(c[0])<<8) i16 = _binary.i16be
i32 = _binary.i32be
def i32(c):
return ord(c[3]) + (ord(c[2])<<8) + (ord(c[1])<<16) + (ord(c[0])<<24)
# --------------------------------------------------------------------. # --------------------------------------------------------------------.
# read PSD images # read PSD images
def _accept(prefix): def _accept(prefix):
return prefix[:4] == "8BPS" return prefix[:4] == b"8BPS"
## ##
# Image plugin for Photoshop images. # Image plugin for Photoshop images.
@ -64,8 +62,8 @@ class PsdImageFile(ImageFile.ImageFile):
# header # header
s = read(26) s = read(26)
if s[:4] != "8BPS" or i16(s[4:]) != 1: if s[:4] != b"8BPS" or i16(s[4:]) != 1:
raise SyntaxError, "not a PSD file" raise SyntaxError("not a PSD file")
psd_bits = i16(s[22:]) psd_bits = i16(s[22:])
psd_channels = i16(s[12:]) psd_channels = i16(s[12:])
@ -74,7 +72,7 @@ class PsdImageFile(ImageFile.ImageFile):
mode, channels = MODES[(psd_mode, psd_bits)] mode, channels = MODES[(psd_mode, psd_bits)]
if channels > psd_channels: if channels > psd_channels:
raise IOError, "not enough channels" raise IOError("not enough channels")
self.mode = mode self.mode = mode
self.size = i32(s[18:]), i32(s[14:]) self.size = i32(s[18:]), i32(s[14:])
@ -100,7 +98,7 @@ class PsdImageFile(ImageFile.ImageFile):
while self.fp.tell() < end: while self.fp.tell() < end:
signature = read(4) signature = read(4)
id = i16(read(2)) id = i16(read(2))
name = read(ord(read(1))) name = read(i8(read(1)))
if not (len(name) & 1): if not (len(name) & 1):
read(1) # padding read(1) # padding
data = read(i32(read(4))) data = read(i32(read(4)))
@ -146,7 +144,7 @@ class PsdImageFile(ImageFile.ImageFile):
self.fp = self._fp self.fp = self._fp
return name, bbox return name, bbox
except IndexError: except IndexError:
raise EOFError, "no such layer" raise EOFError("no such layer")
def tell(self): def tell(self):
# return layer number (0=image, 1..max=layers) # return layer number (0=image, 1..max=layers)
@ -174,7 +172,7 @@ def _layerinfo(file):
# image info # image info
info = [] info = []
mode = [] mode = []
types = range(i16(read(2))) types = list(range(i16(read(2))))
if len(types) > 4: if len(types) > 4:
continue continue
@ -219,9 +217,10 @@ def _layerinfo(file):
file.seek(length, 1) file.seek(length, 1)
combined += length + 4 combined += length + 4
length = ord(read(1)) length = i8(read(1))
if length: if length:
name = read(length) # Don't know the proper encoding, Latin-1 should be a good guess
name = read(length).decode('latin-1', 'replace')
combined += length + 1 combined += length + 1
file.seek(size - combined, 1) file.seek(size - combined, 1)

View File

@ -21,14 +21,11 @@
__version__ = "0.2" __version__ = "0.2"
import Image, ImageFile from . import Image, ImageFile, _binary
i8 = _binary.i8
def i16(c): i16 = _binary.i16be
return ord(c[1]) + (ord(c[0])<<8) i32 = _binary.i32be
def i32(c):
return ord(c[3]) + (ord(c[2])<<8) + (ord(c[1])<<16) + (ord(c[0])<<24)
def _accept(prefix): def _accept(prefix):
@ -50,10 +47,10 @@ class SgiImageFile(ImageFile.ImageFile):
raise SyntaxError("not an SGI image file") raise SyntaxError("not an SGI image file")
# relevant header entries # relevant header entries
compression = ord(s[2]) compression = i8(s[2])
# bytes, dimension, zsize # bytes, dimension, zsize
layout = ord(s[3]), i16(s[4:]), i16(s[10:]) layout = i8(s[3]), i16(s[4:]), i16(s[10:])
# determine mode from bytes/zsize # determine mode from bytes/zsize
if layout == (1, 2, 1) or layout == (1, 1, 1): if layout == (1, 2, 1) or layout == (1, 1, 1):

View File

@ -33,7 +33,9 @@
# http://www.wadsworth.org/spider_doc/spider/docs/image_doc.html # http://www.wadsworth.org/spider_doc/spider/docs/image_doc.html
# #
import Image, ImageFile from __future__ import print_function
from . import Image, ImageFile
import os, struct, sys import os, struct, sys
def isInt(f): def isInt(f):
@ -101,14 +103,14 @@ class SpiderImageFile(ImageFile.ImageFile):
t = struct.unpack('<27f',f) # little-endian t = struct.unpack('<27f',f) # little-endian
hdrlen = isSpiderHeader(t) hdrlen = isSpiderHeader(t)
if hdrlen == 0: if hdrlen == 0:
raise SyntaxError, "not a valid Spider file" raise SyntaxError("not a valid Spider file")
except struct.error: except struct.error:
raise SyntaxError, "not a valid Spider file" raise SyntaxError("not a valid Spider file")
h = (99,) + t # add 1 value : spider header index starts at 1 h = (99,) + t # add 1 value : spider header index starts at 1
iform = int(h[5]) iform = int(h[5])
if iform != 1: if iform != 1:
raise SyntaxError, "not a Spider 2D image" raise SyntaxError("not a Spider 2D image")
self.size = int(h[12]), int(h[2]) # size in pixels (width, height) self.size = int(h[12]), int(h[2]) # size in pixels (width, height)
self.istack = int(h[24]) self.istack = int(h[24])
@ -131,7 +133,7 @@ class SpiderImageFile(ImageFile.ImageFile):
offset = hdrlen + self.stkoffset offset = hdrlen + self.stkoffset
self.istack = 2 # So Image knows it's still a stack self.istack = 2 # So Image knows it's still a stack
else: else:
raise SyntaxError, "inconsistent stack header values" raise SyntaxError("inconsistent stack header values")
if self.bigendian: if self.bigendian:
self.rawmode = "F;32BF" self.rawmode = "F;32BF"
@ -154,7 +156,7 @@ class SpiderImageFile(ImageFile.ImageFile):
if self.istack == 0: if self.istack == 0:
return return
if frame >= self.nimages: if frame >= self.nimages:
raise EOFError, "attempt to seek past end of file" raise EOFError("attempt to seek past end of file")
self.stkoffset = self.hdrlen + frame * (self.hdrlen + self.imgbytes) self.stkoffset = self.hdrlen + frame * (self.hdrlen + self.imgbytes)
self.fp = self.__fp self.fp = self.__fp
self.fp.seek(self.stkoffset) self.fp.seek(self.stkoffset)
@ -171,7 +173,7 @@ class SpiderImageFile(ImageFile.ImageFile):
# returns a ImageTk.PhotoImage object, after rescaling to 0..255 # returns a ImageTk.PhotoImage object, after rescaling to 0..255
def tkPhotoImage(self): def tkPhotoImage(self):
import ImageTk from . import ImageTk
return ImageTk.PhotoImage(self.convert2byte(), palette=256) return ImageTk.PhotoImage(self.convert2byte(), palette=256)
# -------------------------------------------------------------------- # --------------------------------------------------------------------
@ -186,13 +188,13 @@ def loadImageSeries(filelist=None):
imglist = [] imglist = []
for img in filelist: for img in filelist:
if not os.path.exists(img): if not os.path.exists(img):
print "unable to find %s" % img print("unable to find %s" % img)
continue continue
try: try:
im = Image.open(img).convert2byte() im = Image.open(img).convert2byte()
except: except:
if not isSpiderImage(img): if not isSpiderImage(img):
print img + " is not a Spider image file" print(img + " is not a Spider image file")
continue continue
im.info['filename'] = img im.info['filename'] = img
imglist.append(im) imglist.append(im)
@ -239,13 +241,13 @@ def _save(im, fp, filename):
hdr = makeSpiderHeader(im) hdr = makeSpiderHeader(im)
if len(hdr) < 256: if len(hdr) < 256:
raise IOError, "Error creating Spider header" raise IOError("Error creating Spider header")
# write the SPIDER header # write the SPIDER header
try: try:
fp = open(filename, 'wb') fp = open(filename, 'wb')
except: except:
raise IOError, "Unable to open %s for writing" % filename raise IOError("Unable to open %s for writing" % filename)
fp.writelines(hdr) fp.writelines(hdr)
rawmode = "F;32NF" #32-bit native floating point rawmode = "F;32NF" #32-bit native floating point
@ -267,12 +269,12 @@ Image.register_save("SPIDER", _save_spider)
if __name__ == "__main__": if __name__ == "__main__":
if not sys.argv[1:]: if not sys.argv[1:]:
print "Syntax: python SpiderImagePlugin.py Spiderimage [outfile]" print("Syntax: python SpiderImagePlugin.py Spiderimage [outfile]")
sys.exit() sys.exit()
filename = sys.argv[1] filename = sys.argv[1]
if not isSpiderImage(filename): if not isSpiderImage(filename):
print "input image must be in Spider format" print("input image must be in Spider format")
sys.exit() sys.exit()
outfile = "" outfile = ""
@ -280,15 +282,15 @@ if __name__ == "__main__":
outfile = sys.argv[2] outfile = sys.argv[2]
im = Image.open(filename) im = Image.open(filename)
print "image: " + str(im) print("image: " + str(im))
print "format: " + str(im.format) print("format: " + str(im.format))
print "size: " + str(im.size) print("size: " + str(im.size))
print "mode: " + str(im.mode) print("mode: " + str(im.mode))
print "max, min: ", print("max, min: ", end=' ')
print im.getextrema() print(im.getextrema())
if outfile != "": if outfile != "":
# perform some image operation # perform some image operation
im = im.transpose(Image.FLIP_LEFT_RIGHT) im = im.transpose(Image.FLIP_LEFT_RIGHT)
print "saving a flipped version of %s as %s " % (os.path.basename(filename), outfile) print("saving a flipped version of %s as %s " % (os.path.basename(filename), outfile))
im.save(outfile, "SPIDER") im.save(outfile, "SPIDER")

View File

@ -20,14 +20,10 @@
__version__ = "0.3" __version__ = "0.3"
import Image, ImageFile, ImagePalette from . import Image, ImageFile, ImagePalette, _binary
i16 = _binary.i16be
def i16(c): i32 = _binary.i32be
return ord(c[1]) + (ord(c[0])<<8)
def i32(c):
return ord(c[3]) + (ord(c[2])<<8) + (ord(c[1])<<16) + (ord(c[0])<<24)
def _accept(prefix): def _accept(prefix):
@ -46,7 +42,7 @@ class SunImageFile(ImageFile.ImageFile):
# HEAD # HEAD
s = self.fp.read(32) s = self.fp.read(32)
if i32(s) != 0x59a66a95: if i32(s) != 0x59a66a95:
raise SyntaxError, "not an SUN raster file" raise SyntaxError("not an SUN raster file")
offset = 32 offset = 32
@ -60,7 +56,7 @@ class SunImageFile(ImageFile.ImageFile):
elif depth == 24: elif depth == 24:
self.mode, rawmode = "RGB", "BGR" self.mode, rawmode = "RGB", "BGR"
else: else:
raise SyntaxError, "unsupported mode" raise SyntaxError("unsupported mode")
compression = i32(s[20:24]) compression = i32(s[20:24])
@ -71,7 +67,7 @@ class SunImageFile(ImageFile.ImageFile):
if self.mode == "L": if self.mode == "L":
self.mode = rawmode = "P" self.mode = rawmode = "P"
stride = (((self.size[0] * depth + 7) / 8) + 3) & (~3) stride = (((self.size[0] * depth + 7) // 8) + 3) & (~3)
if compression == 1: if compression == 1:
self.tile = [("raw", (0,0)+self.size, offset, (rawmode, stride))] self.tile = [("raw", (0,0)+self.size, offset, (rawmode, stride))]

View File

@ -14,8 +14,7 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
import ContainerIO from . import ContainerIO
import string
## ##
# A file object that provides read access to a given member of a TAR # A file object that provides read access to a given member of a TAR
@ -33,20 +32,20 @@ class TarIO(ContainerIO.ContainerIO):
fh = open(tarfile, "rb") fh = open(tarfile, "rb")
while 1: while True:
s = fh.read(512) s = fh.read(512)
if len(s) != 512: if len(s) != 512:
raise IOError, "unexpected end of tar file" raise IOError("unexpected end of tar file")
name = s[:100] name = s[:100].decode('utf-8')
i = string.find(name, chr(0)) i = name.find('\0')
if i == 0: if i == 0:
raise IOError, "cannot find subfile" raise IOError("cannot find subfile")
if i > 0: if i > 0:
name = name[:i] name = name[:i]
size = string.atoi(s[124:136], 8) size = int(s[124:135], 8)
if file == name: if file == name:
break break

View File

@ -19,18 +19,16 @@
__version__ = "0.3" __version__ = "0.3"
import Image, ImageFile, ImagePalette from . import Image, ImageFile, ImagePalette, _binary
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Read RGA file # Read RGA file
def i16(c): i8 = _binary.i8
return ord(c[0]) + (ord(c[1])<<8) i16 = _binary.i16le
i32 = _binary.i32le
def i32(c):
return ord(c[0]) + (ord(c[1])<<8) + (ord(c[2])<<16) + (ord(c[3])<<24)
MODES = { MODES = {
@ -45,7 +43,7 @@ MODES = {
def _accept(prefix): def _accept(prefix):
return prefix[0] == "\0" return prefix[0:1] == b"\0"
## ##
# Image plugin for Targa files. # Image plugin for Targa files.
@ -60,14 +58,14 @@ class TgaImageFile(ImageFile.ImageFile):
# process header # process header
s = self.fp.read(18) s = self.fp.read(18)
id = ord(s[0]) id = i8(s[0])
colormaptype = ord(s[1]) colormaptype = i8(s[1])
imagetype = ord(s[2]) imagetype = i8(s[2])
depth = ord(s[16]) depth = i8(s[16])
flags = ord(s[17]) flags = i8(s[17])
self.size = i16(s[12:]), i16(s[14:]) self.size = i16(s[12:]), i16(s[14:])
@ -75,7 +73,7 @@ class TgaImageFile(ImageFile.ImageFile):
if id != 0 or colormaptype not in (0, 1) or\ if id != 0 or colormaptype not in (0, 1) or\
self.size[0] <= 0 or self.size[1] <= 0 or\ self.size[0] <= 0 or self.size[1] <= 0 or\
depth not in (1, 8, 16, 24, 32): depth not in (1, 8, 16, 24, 32):
raise SyntaxError, "not a TGA file" raise SyntaxError("not a TGA file")
# image mode # image mode
if imagetype in (3, 11): if imagetype in (3, 11):
@ -89,7 +87,7 @@ class TgaImageFile(ImageFile.ImageFile):
if depth == 32: if depth == 32:
self.mode = "RGBA" self.mode = "RGBA"
else: else:
raise SyntaxError, "unknown TGA mode" raise SyntaxError("unknown TGA mode")
# orientation # orientation
orientation = flags & 0x30 orientation = flags & 0x30
@ -98,7 +96,7 @@ class TgaImageFile(ImageFile.ImageFile):
elif not orientation: elif not orientation:
orientation = -1 orientation = -1
else: else:
raise SyntaxError, "unknown TGA orientation" raise SyntaxError("unknown TGA orientation")
self.info["orientation"] = orientation self.info["orientation"] = orientation
@ -110,13 +108,13 @@ class TgaImageFile(ImageFile.ImageFile):
start, size, mapdepth = i16(s[3:]), i16(s[5:]), i16(s[7:]) start, size, mapdepth = i16(s[3:]), i16(s[5:]), i16(s[7:])
if mapdepth == 16: if mapdepth == 16:
self.palette = ImagePalette.raw("BGR;16", self.palette = ImagePalette.raw("BGR;16",
"\0"*2*start + self.fp.read(2*size)) b"\0"*2*start + self.fp.read(2*size))
elif mapdepth == 24: elif mapdepth == 24:
self.palette = ImagePalette.raw("BGR", self.palette = ImagePalette.raw("BGR",
"\0"*3*start + self.fp.read(3*size)) b"\0"*3*start + self.fp.read(3*size))
elif mapdepth == 32: elif mapdepth == 32:
self.palette = ImagePalette.raw("BGRA", self.palette = ImagePalette.raw("BGRA",
"\0"*4*start + self.fp.read(4*size)) b"\0"*4*start + self.fp.read(4*size))
# setup tile descriptor # setup tile descriptor
try: try:
@ -135,11 +133,9 @@ class TgaImageFile(ImageFile.ImageFile):
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Write TGA file # Write TGA file
def o16(i): o8 = _binary.o8
return chr(i&255) + chr(i>>8&255) o16 = _binary.o16le
o32 = _binary.o32le
def o32(i):
return chr(i&255) + chr(i>>8&255) + chr(i>>16&255) + chr(i>>24&255)
SAVE = { SAVE = {
"1": ("1", 1, 0, 3), "1": ("1", 1, 0, 3),
@ -173,18 +169,18 @@ def _save(im, fp, filename, check=0):
if orientation > 0: if orientation > 0:
flags = flags | 0x20 flags = flags | 0x20
fp.write("\000" + fp.write(b"\000" +
chr(colormaptype) + o8(colormaptype) +
chr(imagetype) + o8(imagetype) +
o16(colormapfirst) + o16(colormapfirst) +
o16(colormaplength) + o16(colormaplength) +
chr(colormapentry) + o8(colormapentry) +
o16(0) + o16(0) +
o16(0) + o16(0) +
o16(im.size[0]) + o16(im.size[0]) +
o16(im.size[1]) + o16(im.size[1]) +
chr(bits) + o8(bits) +
chr(flags)) o8(flags))
if colormaptype: if colormaptype:
fp.write(im.im.getpalette("RGB", "BGR")) fp.write(im.im.getpalette("RGB", "BGR"))

View File

@ -39,48 +39,42 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
from __future__ import print_function
__version__ = "1.3.5" __version__ = "1.3.5"
import Image, ImageFile from . import Image, ImageFile
import ImagePalette from . import ImagePalette
from . import _binary
import array, string, sys import array, sys
import collections
import itertools
II = "II" # little-endian (intel-style) II = b"II" # little-endian (intel-style)
MM = "MM" # big-endian (motorola-style) MM = b"MM" # big-endian (motorola-style)
try: i8 = _binary.i8
if sys.byteorder == "little": o8 = _binary.o8
if sys.byteorder == "little":
native_prefix = II native_prefix = II
else: else:
native_prefix = MM
except AttributeError:
if ord(array.array("i",[1]).tostring()[0]):
native_prefix = II
else:
native_prefix = MM native_prefix = MM
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Read TIFF files # Read TIFF files
def il16(c,o=0): il16 = _binary.i16le
return ord(c[o]) + (ord(c[o+1])<<8) il32 = _binary.i32le
def il32(c,o=0): ol16 = _binary.o16le
return ord(c[o]) + (ord(c[o+1])<<8) + (ord(c[o+2])<<16) + (ord(c[o+3])<<24) ol32 = _binary.o32le
def ol16(i):
return chr(i&255) + chr(i>>8&255)
def ol32(i):
return chr(i&255) + chr(i>>8&255) + chr(i>>16&255) + chr(i>>24&255)
def ib16(c,o=0): ib16 = _binary.i16be
return ord(c[o+1]) + (ord(c[o])<<8) ib32 = _binary.i32be
def ib32(c,o=0): ob16 = _binary.o16be
return ord(c[o+3]) + (ord(c[o+2])<<8) + (ord(c[o+1])<<16) + (ord(c[o])<<24) ob32 = _binary.o32be
def ob16(i):
return chr(i>>8&255) + chr(i&255)
def ob32(i):
return chr(i>>24&255) + chr(i>>16&255) + chr(i>>8&255) + chr(i&255)
# a few tag names, just to make the code below a bit more readable # a few tag names, just to make the code below a bit more readable
IMAGEWIDTH = 256 IMAGEWIDTH = 256
@ -196,7 +190,7 @@ OPEN_INFO = {
} }
PREFIXES = ["MM\000\052", "II\052\000", "II\xBC\000"] PREFIXES = [b"MM\000\052", b"II\052\000", b"II\xBC\000"]
def _accept(prefix): def _accept(prefix):
return prefix[:4] in PREFIXES return prefix[:4] in PREFIXES
@ -204,7 +198,7 @@ def _accept(prefix):
## ##
# Wrapper for TIFF IFDs. # Wrapper for TIFF IFDs.
class ImageFileDirectory: class ImageFileDirectory(collections.MutableMapping):
# represents a TIFF tag directory. to speed things up, # represents a TIFF tag directory. to speed things up,
# we don't decode tags unless they're asked for. # we don't decode tags unless they're asked for.
@ -227,16 +221,7 @@ class ImageFileDirectory:
self.tagtype = {} # added 2008-06-05 by Florian Hoech self.tagtype = {} # added 2008-06-05 by Florian Hoech
self.next = None self.next = None
# dictionary API (sort of) # dictionary API
def keys(self):
return self.tagdata.keys() + self.tags.keys()
def items(self):
items = self.tags.items()
for tag in self.tagdata.keys():
items.append((tag, self[tag]))
return items
def __len__(self): def __len__(self):
return len(self.tagdata) + len(self.tags) return len(self.tagdata) + len(self.tags)
@ -251,12 +236,6 @@ class ImageFileDirectory:
del self.tagdata[tag] del self.tagdata[tag]
return data return data
def get(self, tag, default=None):
try:
return self[tag]
except KeyError:
return default
def getscalar(self, tag, default=None): def getscalar(self, tag, default=None):
try: try:
value = self[tag] value = self[tag]
@ -265,36 +244,43 @@ class ImageFileDirectory:
# work around broken (?) matrox library # work around broken (?) matrox library
# (from Ted Wright, via Bob Klimek) # (from Ted Wright, via Bob Klimek)
raise KeyError # use default raise KeyError # use default
raise ValueError, "not a scalar" raise ValueError("not a scalar")
return value[0] return value[0]
except KeyError: except KeyError:
if default is None: if default is None:
raise raise
return default return default
def __contains__(self, tag):
return tag in self.tags or tag in self.tagdata
if bytes is str:
def has_key(self, tag): def has_key(self, tag):
return self.tags.has_key(tag) or self.tagdata.has_key(tag) return tag in self
def __setitem__(self, tag, value): def __setitem__(self, tag, value):
if type(value) is not type(()): if not isinstance(value, tuple):
value = (value,) value = (value,)
self.tags[tag] = value self.tags[tag] = value
def __delitem__(self, tag):
self.tags.pop(tag, self.tagdata.pop(tag, None))
def __iter__(self):
return itertools.chain(self.tags.__iter__(), self.tagdata.__iter__())
# load primitives # load primitives
load_dispatch = {} load_dispatch = {}
def load_byte(self, data): def load_byte(self, data):
l = [] return data
for i in range(len(data)):
l.append(ord(data[i]))
return tuple(l)
load_dispatch[1] = (1, load_byte) load_dispatch[1] = (1, load_byte)
def load_string(self, data): def load_string(self, data):
if data[-1:] == '\0': if data[-1:] == b'\0':
data = data[:-1] data = data[:-1]
return data return data.decode('latin-1', 'replace')
load_dispatch[2] = (1, load_string) load_dispatch[2] = (1, load_string)
def load_short(self, data): def load_short(self, data):
@ -352,17 +338,17 @@ class ImageFileDirectory:
tag, typ = i16(ifd), i16(ifd, 2) tag, typ = i16(ifd), i16(ifd, 2)
if Image.DEBUG: if Image.DEBUG:
import TiffTags from . import TiffTags
tagname = TiffTags.TAGS.get(tag, "unknown") tagname = TiffTags.TAGS.get(tag, "unknown")
typname = TiffTags.TYPES.get(typ, "unknown") typname = TiffTags.TYPES.get(typ, "unknown")
print "tag: %s (%d)" % (tagname, tag), print("tag: %s (%d)" % (tagname, tag), end=' ')
print "- type: %s (%d)" % (typname, typ), print("- type: %s (%d)" % (typname, typ), end=' ')
try: try:
dispatch = self.load_dispatch[typ] dispatch = self.load_dispatch[typ]
except KeyError: except KeyError:
if Image.DEBUG: if Image.DEBUG:
print "- unsupported type", typ print("- unsupported type", typ)
continue # ignore unsupported type continue # ignore unsupported type
size, handler = dispatch size, handler = dispatch
@ -379,16 +365,16 @@ class ImageFileDirectory:
data = ifd[8:8+size] data = ifd[8:8+size]
if len(data) != size: if len(data) != size:
raise IOError, "not enough data" raise IOError("not enough data")
self.tagdata[tag] = typ, data self.tagdata[tag] = typ, data
self.tagtype[tag] = typ self.tagtype[tag] = typ
if Image.DEBUG: if Image.DEBUG:
if tag in (COLORMAP, IPTC_NAA_CHUNK, PHOTOSHOP_CHUNK, ICCPROFILE, XMP): if tag in (COLORMAP, IPTC_NAA_CHUNK, PHOTOSHOP_CHUNK, ICCPROFILE, XMP):
print "- value: <table: %d bytes>" % size print("- value: <table: %d bytes>" % size)
else: else:
print "- value:", self[tag] print("- value:", self[tag])
self.next = i32(fp.read(4)) self.next = i32(fp.read(4))
@ -402,8 +388,7 @@ class ImageFileDirectory:
fp.write(o16(len(self.tags))) fp.write(o16(len(self.tags)))
# always write in ascending tag order # always write in ascending tag order
tags = self.tags.items() tags = sorted(self.tags.items())
tags.sort()
directory = [] directory = []
append = directory.append append = directory.append
@ -417,19 +402,19 @@ class ImageFileDirectory:
typ = None typ = None
if self.tagtype.has_key(tag): if tag in self.tagtype:
typ = self.tagtype[tag] typ = self.tagtype[tag]
if typ == 1: if typ == 1:
# byte data # byte data
data = value = string.join(map(chr, value), "") data = value
elif typ == 7: elif typ == 7:
# untyped data # untyped data
data = value = string.join(value, "") data = value = b"".join(value)
elif type(value[0]) is type(""): elif isinstance(value[0], str):
# string data # string data
typ = 2 typ = 2
data = value = string.join(value, "\0") + "\0" data = value = b"\0".join(value.encode('ascii', 'replace')) + b"\0"
else: else:
# integer data # integer data
if tag == STRIPOFFSETS: if tag == STRIPOFFSETS:
@ -444,31 +429,31 @@ class ImageFileDirectory:
if v >= 65536: if v >= 65536:
typ = 4 typ = 4
if typ == 3: if typ == 3:
data = string.join(map(o16, value), "") data = b"".join(map(o16, value))
else: else:
data = string.join(map(o32, value), "") data = b"".join(map(o32, value))
if Image.DEBUG: if Image.DEBUG:
import TiffTags from . import TiffTags
tagname = TiffTags.TAGS.get(tag, "unknown") tagname = TiffTags.TAGS.get(tag, "unknown")
typname = TiffTags.TYPES.get(typ, "unknown") typname = TiffTags.TYPES.get(typ, "unknown")
print "save: %s (%d)" % (tagname, tag), print("save: %s (%d)" % (tagname, tag), end=' ')
print "- type: %s (%d)" % (typname, typ), print("- type: %s (%d)" % (typname, typ), end=' ')
if tag in (COLORMAP, IPTC_NAA_CHUNK, PHOTOSHOP_CHUNK, ICCPROFILE, XMP): if tag in (COLORMAP, IPTC_NAA_CHUNK, PHOTOSHOP_CHUNK, ICCPROFILE, XMP):
size = len(data) size = len(data)
print "- value: <table: %d bytes>" % size print("- value: <table: %d bytes>" % size)
else: else:
print "- value:", value print("- value:", value)
# figure out if data fits into the directory # figure out if data fits into the directory
if len(data) == 4: if len(data) == 4:
append((tag, typ, len(value), data, "")) append((tag, typ, len(value), data, b""))
elif len(data) < 4: elif len(data) < 4:
append((tag, typ, len(value), data + (4-len(data))*"\0", "")) append((tag, typ, len(value), data + (4-len(data))*b"\0", b""))
else: else:
count = len(value) count = len(value)
if typ == 5: if typ == 5:
count = count / 2 # adjust for rational data field count = count // 2 # adjust for rational data field
append((tag, typ, count, o32(offset), data)) append((tag, typ, count, o32(offset), data))
offset = offset + len(data) offset = offset + len(data)
if offset & 1: if offset & 1:
@ -484,17 +469,17 @@ class ImageFileDirectory:
# pass 2: write directory to file # pass 2: write directory to file
for tag, typ, count, value, data in directory: for tag, typ, count, value, data in directory:
if Image.DEBUG > 1: if Image.DEBUG > 1:
print tag, typ, count, repr(value), repr(data) print(tag, typ, count, repr(value), repr(data))
fp.write(o16(tag) + o16(typ) + o32(count) + value) fp.write(o16(tag) + o16(typ) + o32(count) + value)
# -- overwrite here for multi-page -- # -- overwrite here for multi-page --
fp.write("\0\0\0\0") # end of directory fp.write(b"\0\0\0\0") # end of directory
# pass 3: write auxiliary data to file # pass 3: write auxiliary data to file
for tag, typ, count, value, data in directory: for tag, typ, count, value, data in directory:
fp.write(data) fp.write(data)
if len(data) & 1: if len(data) & 1:
fp.write("\0") fp.write(b"\0")
return offset return offset
@ -513,7 +498,7 @@ class TiffImageFile(ImageFile.ImageFile):
ifh = self.fp.read(8) ifh = self.fp.read(8)
if ifh[:4] not in PREFIXES: if ifh[:4] not in PREFIXES:
raise SyntaxError, "not a TIFF file" raise SyntaxError("not a TIFF file")
# image file directory (tag dictionary) # image file directory (tag dictionary)
self.tag = self.ifd = ImageFileDirectory(ifh[:2]) self.tag = self.ifd = ImageFileDirectory(ifh[:2])
@ -547,7 +532,7 @@ class TiffImageFile(ImageFile.ImageFile):
self.__next = self.__first self.__next = self.__first
while self.__frame < frame: while self.__frame < frame:
if not self.__next: if not self.__next:
raise EOFError, "no more images in TIFF file" raise EOFError("no more images in TIFF file")
self.fp.seek(self.__next) self.fp.seek(self.__next)
self.tag.load(self.fp) self.tag.load(self.fp)
self.__next = self.tag.next self.__next = self.tag.next
@ -569,18 +554,18 @@ class TiffImageFile(ImageFile.ImageFile):
args = (rawmode, 0, 1) args = (rawmode, 0, 1)
elif compression == "jpeg": elif compression == "jpeg":
args = rawmode, "" args = rawmode, ""
if self.tag.has_key(JPEGTABLES): if JPEGTABLES in self.tag:
# Hack to handle abbreviated JPEG headers # Hack to handle abbreviated JPEG headers
self.tile_prefix = self.tag[JPEGTABLES] self.tile_prefix = self.tag[JPEGTABLES]
elif compression == "packbits": elif compression == "packbits":
args = rawmode args = rawmode
elif compression == "tiff_lzw": elif compression == "tiff_lzw":
args = rawmode args = rawmode
if self.tag.has_key(317): if 317 in self.tag:
# Section 14: Differencing Predictor # Section 14: Differencing Predictor
self.decoderconfig = (self.tag[PREDICTOR][0],) self.decoderconfig = (self.tag[PREDICTOR][0],)
if self.tag.has_key(ICCPROFILE): if ICCPROFILE in self.tag:
self.info['icc_profile'] = self.tag[ICCPROFILE] self.info['icc_profile'] = self.tag[ICCPROFILE]
return args return args
@ -588,8 +573,8 @@ class TiffImageFile(ImageFile.ImageFile):
def _setup(self): def _setup(self):
"Setup this image object based on current tags" "Setup this image object based on current tags"
if self.tag.has_key(0xBC01): if 0xBC01 in self.tag:
raise IOError, "Windows Media Photo files not yet supported" raise IOError("Windows Media Photo files not yet supported")
getscalar = self.tag.getscalar getscalar = self.tag.getscalar
@ -604,11 +589,11 @@ class TiffImageFile(ImageFile.ImageFile):
fillorder = getscalar(FILLORDER, 1) fillorder = getscalar(FILLORDER, 1)
if Image.DEBUG: if Image.DEBUG:
print "*** Summary ***" print("*** Summary ***")
print "- compression:", self._compression print("- compression:", self._compression)
print "- photometric_interpretation:", photo print("- photometric_interpretation:", photo)
print "- planar_configuration:", self._planar_configuration print("- planar_configuration:", self._planar_configuration)
print "- fill_order:", fillorder print("- fill_order:", fillorder)
# size # size
xsize = getscalar(IMAGEWIDTH) xsize = getscalar(IMAGEWIDTH)
@ -616,7 +601,7 @@ class TiffImageFile(ImageFile.ImageFile):
self.size = xsize, ysize self.size = xsize, ysize
if Image.DEBUG: if Image.DEBUG:
print "- size:", self.size print("- size:", self.size)
format = getscalar(SAMPLEFORMAT, 1) format = getscalar(SAMPLEFORMAT, 1)
@ -627,17 +612,17 @@ class TiffImageFile(ImageFile.ImageFile):
self.tag.get(EXTRASAMPLES, ()) self.tag.get(EXTRASAMPLES, ())
) )
if Image.DEBUG: if Image.DEBUG:
print "format key:", key print("format key:", key)
try: try:
self.mode, rawmode = OPEN_INFO[key] self.mode, rawmode = OPEN_INFO[key]
except KeyError: except KeyError:
if Image.DEBUG: if Image.DEBUG:
print "- unsupported format" print("- unsupported format")
raise SyntaxError, "unknown pixel mode" raise SyntaxError("unknown pixel mode")
if Image.DEBUG: if Image.DEBUG:
print "- raw mode:", rawmode print("- raw mode:", rawmode)
print "- pil mode:", self.mode print("- pil mode:", self.mode)
self.info["compression"] = self._compression self.info["compression"] = self._compression
@ -658,7 +643,7 @@ class TiffImageFile(ImageFile.ImageFile):
# build tile descriptors # build tile descriptors
x = y = l = 0 x = y = l = 0
self.tile = [] self.tile = []
if self.tag.has_key(STRIPOFFSETS): if STRIPOFFSETS in self.tag:
# striped image # striped image
h = getscalar(ROWSPERSTRIP, ysize) h = getscalar(ROWSPERSTRIP, ysize)
w = self.size[0] w = self.size[0]
@ -675,7 +660,7 @@ class TiffImageFile(ImageFile.ImageFile):
x = y = 0 x = y = 0
l = l + 1 l = l + 1
a = None a = None
elif self.tag.has_key(TILEOFFSETS): elif TILEOFFSETS in self.tag:
# tiled image # tiled image
w = getscalar(322) w = getscalar(322)
h = getscalar(323) h = getscalar(323)
@ -698,14 +683,14 @@ class TiffImageFile(ImageFile.ImageFile):
a = None a = None
else: else:
if Image.DEBUG: if Image.DEBUG:
print "- unsupported data organization" print("- unsupported data organization")
raise SyntaxError("unknown data organization") raise SyntaxError("unknown data organization")
# fixup palette descriptor # fixup palette descriptor
if self.mode == "P": if self.mode == "P":
palette = map(lambda a: chr(a / 256), self.tag[COLORMAP]) palette = [o8(a // 256) for a in self.tag[COLORMAP]]
self.palette = ImagePalette.raw("RGB;L", string.join(palette, "")) self.palette = ImagePalette.raw("RGB;L", b"".join(palette))
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Write TIFF files # Write TIFF files
@ -738,10 +723,10 @@ SAVE_INFO = {
def _cvt_res(value): def _cvt_res(value):
# convert value to TIFF rational number -- (numerator, denominator) # convert value to TIFF rational number -- (numerator, denominator)
if type(value) in (type([]), type(())): if isinstance(value, collections.Sequence):
assert(len(value) % 2 == 0) assert(len(value) % 2 == 0)
return value return value
if type(value) == type(1): if isinstance(value, int):
return (value, 1) return (value, 1)
value = float(value) value = float(value)
return (int(value * 65536), 65536) return (int(value * 65536), 65536)
@ -751,7 +736,7 @@ def _save(im, fp, filename):
try: try:
rawmode, prefix, photo, format, bits, extra = SAVE_INFO[im.mode] rawmode, prefix, photo, format, bits, extra = SAVE_INFO[im.mode]
except KeyError: except KeyError:
raise IOError, "cannot write mode %s as TIFF" % im.mode raise IOError("cannot write mode %s as TIFF" % im.mode)
ifd = ImageFileDirectory(prefix) ifd = ImageFileDirectory(prefix)
@ -769,28 +754,28 @@ def _save(im, fp, filename):
if hasattr(im, 'tag'): if hasattr(im, 'tag'):
# preserve tags from original TIFF image file # preserve tags from original TIFF image file
for key in (RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION): for key in (RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION):
if im.tag.tagdata.has_key(key): if key in im.tag.tagdata:
ifd[key] = im.tag.tagdata.get(key) ifd[key] = im.tag.tagdata.get(key)
# preserve some more tags from original TIFF image file # preserve some more tags from original TIFF image file
# -- 2008-06-06 Florian Hoech # -- 2008-06-06 Florian Hoech
ifd.tagtype = im.tag.tagtype ifd.tagtype = im.tag.tagtype
for key in (IPTC_NAA_CHUNK, PHOTOSHOP_CHUNK, XMP): for key in (IPTC_NAA_CHUNK, PHOTOSHOP_CHUNK, XMP):
if im.tag.has_key(key): if key in im.tag:
ifd[key] = im.tag[key] ifd[key] = im.tag[key]
# preserve ICC profile (should also work when saving other formats # preserve ICC profile (should also work when saving other formats
# which support profiles as TIFF) -- 2008-06-06 Florian Hoech # which support profiles as TIFF) -- 2008-06-06 Florian Hoech
if im.info.has_key("icc_profile"): if "icc_profile" in im.info:
ifd[ICCPROFILE] = im.info["icc_profile"] ifd[ICCPROFILE] = im.info["icc_profile"]
if im.encoderinfo.has_key("description"): if "description" in im.encoderinfo:
ifd[IMAGEDESCRIPTION] = im.encoderinfo["description"] ifd[IMAGEDESCRIPTION] = im.encoderinfo["description"]
if im.encoderinfo.has_key("resolution"): if "resolution" in im.encoderinfo:
ifd[X_RESOLUTION] = ifd[Y_RESOLUTION] \ ifd[X_RESOLUTION] = ifd[Y_RESOLUTION] \
= _cvt_res(im.encoderinfo["resolution"]) = _cvt_res(im.encoderinfo["resolution"])
if im.encoderinfo.has_key("x resolution"): if "x resolution" in im.encoderinfo:
ifd[X_RESOLUTION] = _cvt_res(im.encoderinfo["x resolution"]) ifd[X_RESOLUTION] = _cvt_res(im.encoderinfo["x resolution"])
if im.encoderinfo.has_key("y resolution"): if "y resolution" in im.encoderinfo:
ifd[Y_RESOLUTION] = _cvt_res(im.encoderinfo["y resolution"]) ifd[Y_RESOLUTION] = _cvt_res(im.encoderinfo["y resolution"])
if im.encoderinfo.has_key("resolution unit"): if "resolution unit" in im.encoderinfo:
unit = im.encoderinfo["resolution unit"] unit = im.encoderinfo["resolution unit"]
if unit == "inch": if unit == "inch":
ifd[RESOLUTION_UNIT] = 2 ifd[RESOLUTION_UNIT] = 2
@ -798,13 +783,13 @@ def _save(im, fp, filename):
ifd[RESOLUTION_UNIT] = 3 ifd[RESOLUTION_UNIT] = 3
else: else:
ifd[RESOLUTION_UNIT] = 1 ifd[RESOLUTION_UNIT] = 1
if im.encoderinfo.has_key("software"): if "software" in im.encoderinfo:
ifd[SOFTWARE] = im.encoderinfo["software"] ifd[SOFTWARE] = im.encoderinfo["software"]
if im.encoderinfo.has_key("date time"): if "date time" in im.encoderinfo:
ifd[DATE_TIME] = im.encoderinfo["date time"] ifd[DATE_TIME] = im.encoderinfo["date time"]
if im.encoderinfo.has_key("artist"): if "artist" in im.encoderinfo:
ifd[ARTIST] = im.encoderinfo["artist"] ifd[ARTIST] = im.encoderinfo["artist"]
if im.encoderinfo.has_key("copyright"): if "copyright" in im.encoderinfo:
ifd[COPYRIGHT] = im.encoderinfo["copyright"] ifd[COPYRIGHT] = im.encoderinfo["copyright"]
dpi = im.encoderinfo.get("dpi") dpi = im.encoderinfo.get("dpi")
@ -826,10 +811,10 @@ def _save(im, fp, filename):
if im.mode == "P": if im.mode == "P":
lut = im.im.getpalette("RGB", "RGB;L") lut = im.im.getpalette("RGB", "RGB;L")
ifd[COLORMAP] = tuple(map(lambda v: ord(v) * 256, lut)) ifd[COLORMAP] = tuple(i8(v) * 256 for v in lut)
# data orientation # data orientation
stride = len(bits) * ((im.size[0]*bits[0]+7)/8) stride = len(bits) * ((im.size[0]*bits[0]+7)//8)
ifd[ROWSPERSTRIP] = im.size[1] ifd[ROWSPERSTRIP] = im.size[1]
ifd[STRIPBYTECOUNTS] = stride * im.size[1] ifd[STRIPBYTECOUNTS] = stride * im.size[1]
ifd[STRIPOFFSETS] = 0 # this is adjusted by IFD writer ifd[STRIPOFFSETS] = 0 # this is adjusted by IFD writer
@ -843,7 +828,7 @@ def _save(im, fp, filename):
# -- helper for multi-page save -- # -- helper for multi-page save --
if im.encoderinfo.has_key("_debug_multipage"): if "_debug_multipage" in im.encoderinfo:
#just to access o32 and o16 (using correct byte order) #just to access o32 and o16 (using correct byte order)
im._debug_multipage = ifd im._debug_multipage = ifd

View File

@ -21,10 +21,17 @@
# http://www.flipcode.com/tutorials/tut_q2levels.shtml # http://www.flipcode.com/tutorials/tut_q2levels.shtml
# and has been tested with a few sample files found using google. # and has been tested with a few sample files found using google.
import Image from __future__ import print_function
def i32(c, o=0): from . import Image, _binary
return ord(c[o])+(ord(c[o+1])<<8)+(ord(c[o+2])<<16)+(ord(c[o+3])<<24)
try:
import builtins
except ImportError:
import __builtin__
builtins = __builtin__
i32 = _binary.i32le
## ##
# Load texture from a Quake2 WAL texture file. # Load texture from a Quake2 WAL texture file.
@ -42,8 +49,7 @@ def open(filename):
if hasattr(filename, "read"): if hasattr(filename, "read"):
fp = filename fp = filename
else: else:
import __builtin__ fp = builtins.open(filename, "rb")
fp = __builtin__.open(filename, "rb")
# read header fields # read header fields
header = fp.read(32+24+32+12) header = fp.read(32+24+32+12)
@ -53,15 +59,15 @@ def open(filename):
# load pixel data # load pixel data
fp.seek(offset) fp.seek(offset)
im = Image.fromstring("P", size, fp.read(size[0] * size[1])) im = Image.frombytes("P", size, fp.read(size[0] * size[1]))
im.putpalette(quake2palette) im.putpalette(quake2palette)
im.format = "WAL" im.format = "WAL"
im.format_description = "Quake2 Texture" im.format_description = "Quake2 Texture"
# strings are null-terminated # strings are null-terminated
im.info["name"] = header[:32].split("\0", 1)[0] im.info["name"] = header[:32].split(b"\0", 1)[0]
next_name = header[56:56+32].split("\0", 1)[0] next_name = header[56:56+32].split(b"\0", 1)[0]
if next_name: if next_name:
im.info["next_name"] = next_name im.info["next_name"] = next_name
@ -70,57 +76,57 @@ def open(filename):
quake2palette = ( quake2palette = (
# default palette taken from piffo 0.93 by Hans Häggström # default palette taken from piffo 0.93 by Hans Häggström
"\x01\x01\x01\x0b\x0b\x0b\x12\x12\x12\x17\x17\x17\x1b\x1b\x1b\x1e" b"\x01\x01\x01\x0b\x0b\x0b\x12\x12\x12\x17\x17\x17\x1b\x1b\x1b\x1e"
"\x1e\x1e\x22\x22\x22\x26\x26\x26\x29\x29\x29\x2c\x2c\x2c\x2f\x2f" b"\x1e\x1e\x22\x22\x22\x26\x26\x26\x29\x29\x29\x2c\x2c\x2c\x2f\x2f"
"\x2f\x32\x32\x32\x35\x35\x35\x37\x37\x37\x3a\x3a\x3a\x3c\x3c\x3c" b"\x2f\x32\x32\x32\x35\x35\x35\x37\x37\x37\x3a\x3a\x3a\x3c\x3c\x3c"
"\x24\x1e\x13\x22\x1c\x12\x20\x1b\x12\x1f\x1a\x10\x1d\x19\x10\x1b" b"\x24\x1e\x13\x22\x1c\x12\x20\x1b\x12\x1f\x1a\x10\x1d\x19\x10\x1b"
"\x17\x0f\x1a\x16\x0f\x18\x14\x0d\x17\x13\x0d\x16\x12\x0d\x14\x10" b"\x17\x0f\x1a\x16\x0f\x18\x14\x0d\x17\x13\x0d\x16\x12\x0d\x14\x10"
"\x0b\x13\x0f\x0b\x10\x0d\x0a\x0f\x0b\x0a\x0d\x0b\x07\x0b\x0a\x07" b"\x0b\x13\x0f\x0b\x10\x0d\x0a\x0f\x0b\x0a\x0d\x0b\x07\x0b\x0a\x07"
"\x23\x23\x26\x22\x22\x25\x22\x20\x23\x21\x1f\x22\x20\x1e\x20\x1f" b"\x23\x23\x26\x22\x22\x25\x22\x20\x23\x21\x1f\x22\x20\x1e\x20\x1f"
"\x1d\x1e\x1d\x1b\x1c\x1b\x1a\x1a\x1a\x19\x19\x18\x17\x17\x17\x16" b"\x1d\x1e\x1d\x1b\x1c\x1b\x1a\x1a\x1a\x19\x19\x18\x17\x17\x17\x16"
"\x16\x14\x14\x14\x13\x13\x13\x10\x10\x10\x0f\x0f\x0f\x0d\x0d\x0d" b"\x16\x14\x14\x14\x13\x13\x13\x10\x10\x10\x0f\x0f\x0f\x0d\x0d\x0d"
"\x2d\x28\x20\x29\x24\x1c\x27\x22\x1a\x25\x1f\x17\x38\x2e\x1e\x31" b"\x2d\x28\x20\x29\x24\x1c\x27\x22\x1a\x25\x1f\x17\x38\x2e\x1e\x31"
"\x29\x1a\x2c\x25\x17\x26\x20\x14\x3c\x30\x14\x37\x2c\x13\x33\x28" b"\x29\x1a\x2c\x25\x17\x26\x20\x14\x3c\x30\x14\x37\x2c\x13\x33\x28"
"\x12\x2d\x24\x10\x28\x1f\x0f\x22\x1a\x0b\x1b\x14\x0a\x13\x0f\x07" b"\x12\x2d\x24\x10\x28\x1f\x0f\x22\x1a\x0b\x1b\x14\x0a\x13\x0f\x07"
"\x31\x1a\x16\x30\x17\x13\x2e\x16\x10\x2c\x14\x0d\x2a\x12\x0b\x27" b"\x31\x1a\x16\x30\x17\x13\x2e\x16\x10\x2c\x14\x0d\x2a\x12\x0b\x27"
"\x0f\x0a\x25\x0f\x07\x21\x0d\x01\x1e\x0b\x01\x1c\x0b\x01\x1a\x0b" b"\x0f\x0a\x25\x0f\x07\x21\x0d\x01\x1e\x0b\x01\x1c\x0b\x01\x1a\x0b"
"\x01\x18\x0a\x01\x16\x0a\x01\x13\x0a\x01\x10\x07\x01\x0d\x07\x01" b"\x01\x18\x0a\x01\x16\x0a\x01\x13\x0a\x01\x10\x07\x01\x0d\x07\x01"
"\x29\x23\x1e\x27\x21\x1c\x26\x20\x1b\x25\x1f\x1a\x23\x1d\x19\x21" b"\x29\x23\x1e\x27\x21\x1c\x26\x20\x1b\x25\x1f\x1a\x23\x1d\x19\x21"
"\x1c\x18\x20\x1b\x17\x1e\x19\x16\x1c\x18\x14\x1b\x17\x13\x19\x14" b"\x1c\x18\x20\x1b\x17\x1e\x19\x16\x1c\x18\x14\x1b\x17\x13\x19\x14"
"\x10\x17\x13\x0f\x14\x10\x0d\x12\x0f\x0b\x0f\x0b\x0a\x0b\x0a\x07" b"\x10\x17\x13\x0f\x14\x10\x0d\x12\x0f\x0b\x0f\x0b\x0a\x0b\x0a\x07"
"\x26\x1a\x0f\x23\x19\x0f\x20\x17\x0f\x1c\x16\x0f\x19\x13\x0d\x14" b"\x26\x1a\x0f\x23\x19\x0f\x20\x17\x0f\x1c\x16\x0f\x19\x13\x0d\x14"
"\x10\x0b\x10\x0d\x0a\x0b\x0a\x07\x33\x22\x1f\x35\x29\x26\x37\x2f" b"\x10\x0b\x10\x0d\x0a\x0b\x0a\x07\x33\x22\x1f\x35\x29\x26\x37\x2f"
"\x2d\x39\x35\x34\x37\x39\x3a\x33\x37\x39\x30\x34\x36\x2b\x31\x34" b"\x2d\x39\x35\x34\x37\x39\x3a\x33\x37\x39\x30\x34\x36\x2b\x31\x34"
"\x27\x2e\x31\x22\x2b\x2f\x1d\x28\x2c\x17\x25\x2a\x0f\x20\x26\x0d" b"\x27\x2e\x31\x22\x2b\x2f\x1d\x28\x2c\x17\x25\x2a\x0f\x20\x26\x0d"
"\x1e\x25\x0b\x1c\x22\x0a\x1b\x20\x07\x19\x1e\x07\x17\x1b\x07\x14" b"\x1e\x25\x0b\x1c\x22\x0a\x1b\x20\x07\x19\x1e\x07\x17\x1b\x07\x14"
"\x18\x01\x12\x16\x01\x0f\x12\x01\x0b\x0d\x01\x07\x0a\x01\x01\x01" b"\x18\x01\x12\x16\x01\x0f\x12\x01\x0b\x0d\x01\x07\x0a\x01\x01\x01"
"\x2c\x21\x21\x2a\x1f\x1f\x29\x1d\x1d\x27\x1c\x1c\x26\x1a\x1a\x24" b"\x2c\x21\x21\x2a\x1f\x1f\x29\x1d\x1d\x27\x1c\x1c\x26\x1a\x1a\x24"
"\x18\x18\x22\x17\x17\x21\x16\x16\x1e\x13\x13\x1b\x12\x12\x18\x10" b"\x18\x18\x22\x17\x17\x21\x16\x16\x1e\x13\x13\x1b\x12\x12\x18\x10"
"\x10\x16\x0d\x0d\x12\x0b\x0b\x0d\x0a\x0a\x0a\x07\x07\x01\x01\x01" b"\x10\x16\x0d\x0d\x12\x0b\x0b\x0d\x0a\x0a\x0a\x07\x07\x01\x01\x01"
"\x2e\x30\x29\x2d\x2e\x27\x2b\x2c\x26\x2a\x2a\x24\x28\x29\x23\x27" b"\x2e\x30\x29\x2d\x2e\x27\x2b\x2c\x26\x2a\x2a\x24\x28\x29\x23\x27"
"\x27\x21\x26\x26\x1f\x24\x24\x1d\x22\x22\x1c\x1f\x1f\x1a\x1c\x1c" b"\x27\x21\x26\x26\x1f\x24\x24\x1d\x22\x22\x1c\x1f\x1f\x1a\x1c\x1c"
"\x18\x19\x19\x16\x17\x17\x13\x13\x13\x10\x0f\x0f\x0d\x0b\x0b\x0a" b"\x18\x19\x19\x16\x17\x17\x13\x13\x13\x10\x0f\x0f\x0d\x0b\x0b\x0a"
"\x30\x1e\x1b\x2d\x1c\x19\x2c\x1a\x17\x2a\x19\x14\x28\x17\x13\x26" b"\x30\x1e\x1b\x2d\x1c\x19\x2c\x1a\x17\x2a\x19\x14\x28\x17\x13\x26"
"\x16\x10\x24\x13\x0f\x21\x12\x0d\x1f\x10\x0b\x1c\x0f\x0a\x19\x0d" b"\x16\x10\x24\x13\x0f\x21\x12\x0d\x1f\x10\x0b\x1c\x0f\x0a\x19\x0d"
"\x0a\x16\x0b\x07\x12\x0a\x07\x0f\x07\x01\x0a\x01\x01\x01\x01\x01" b"\x0a\x16\x0b\x07\x12\x0a\x07\x0f\x07\x01\x0a\x01\x01\x01\x01\x01"
"\x28\x29\x38\x26\x27\x36\x25\x26\x34\x24\x24\x31\x22\x22\x2f\x20" b"\x28\x29\x38\x26\x27\x36\x25\x26\x34\x24\x24\x31\x22\x22\x2f\x20"
"\x21\x2d\x1e\x1f\x2a\x1d\x1d\x27\x1b\x1b\x25\x19\x19\x21\x17\x17" b"\x21\x2d\x1e\x1f\x2a\x1d\x1d\x27\x1b\x1b\x25\x19\x19\x21\x17\x17"
"\x1e\x14\x14\x1b\x13\x12\x17\x10\x0f\x13\x0d\x0b\x0f\x0a\x07\x07" b"\x1e\x14\x14\x1b\x13\x12\x17\x10\x0f\x13\x0d\x0b\x0f\x0a\x07\x07"
"\x2f\x32\x29\x2d\x30\x26\x2b\x2e\x24\x29\x2c\x21\x27\x2a\x1e\x25" b"\x2f\x32\x29\x2d\x30\x26\x2b\x2e\x24\x29\x2c\x21\x27\x2a\x1e\x25"
"\x28\x1c\x23\x26\x1a\x21\x25\x18\x1e\x22\x14\x1b\x1f\x10\x19\x1c" b"\x28\x1c\x23\x26\x1a\x21\x25\x18\x1e\x22\x14\x1b\x1f\x10\x19\x1c"
"\x0d\x17\x1a\x0a\x13\x17\x07\x10\x13\x01\x0d\x0f\x01\x0a\x0b\x01" b"\x0d\x17\x1a\x0a\x13\x17\x07\x10\x13\x01\x0d\x0f\x01\x0a\x0b\x01"
"\x01\x3f\x01\x13\x3c\x0b\x1b\x39\x10\x20\x35\x14\x23\x31\x17\x23" b"\x01\x3f\x01\x13\x3c\x0b\x1b\x39\x10\x20\x35\x14\x23\x31\x17\x23"
"\x2d\x18\x23\x29\x18\x3f\x3f\x3f\x3f\x3f\x39\x3f\x3f\x31\x3f\x3f" b"\x2d\x18\x23\x29\x18\x3f\x3f\x3f\x3f\x3f\x39\x3f\x3f\x31\x3f\x3f"
"\x2a\x3f\x3f\x20\x3f\x3f\x14\x3f\x3c\x12\x3f\x39\x0f\x3f\x35\x0b" b"\x2a\x3f\x3f\x20\x3f\x3f\x14\x3f\x3c\x12\x3f\x39\x0f\x3f\x35\x0b"
"\x3f\x32\x07\x3f\x2d\x01\x3d\x2a\x01\x3b\x26\x01\x39\x21\x01\x37" b"\x3f\x32\x07\x3f\x2d\x01\x3d\x2a\x01\x3b\x26\x01\x39\x21\x01\x37"
"\x1d\x01\x34\x1a\x01\x32\x16\x01\x2f\x12\x01\x2d\x0f\x01\x2a\x0b" b"\x1d\x01\x34\x1a\x01\x32\x16\x01\x2f\x12\x01\x2d\x0f\x01\x2a\x0b"
"\x01\x27\x07\x01\x23\x01\x01\x1d\x01\x01\x17\x01\x01\x10\x01\x01" b"\x01\x27\x07\x01\x23\x01\x01\x1d\x01\x01\x17\x01\x01\x10\x01\x01"
"\x3d\x01\x01\x19\x19\x3f\x3f\x01\x01\x01\x01\x3f\x16\x16\x13\x10" b"\x3d\x01\x01\x19\x19\x3f\x3f\x01\x01\x01\x01\x3f\x16\x16\x13\x10"
"\x10\x0f\x0d\x0d\x0b\x3c\x2e\x2a\x36\x27\x20\x30\x21\x18\x29\x1b" b"\x10\x0f\x0d\x0d\x0b\x3c\x2e\x2a\x36\x27\x20\x30\x21\x18\x29\x1b"
"\x10\x3c\x39\x37\x37\x32\x2f\x31\x2c\x28\x2b\x26\x21\x30\x22\x20" b"\x10\x3c\x39\x37\x37\x32\x2f\x31\x2c\x28\x2b\x26\x21\x30\x22\x20"
) )
if __name__ == "__main__": if __name__ == "__main__":
im = open("../hacks/sample.wal") im = open("../hacks/sample.wal")
print im.info, im.mode, im.size print(im.info, im.mode, im.size)
im.save("../out.png") im.save("../out.png")

View File

@ -17,10 +17,13 @@
__version__ = "0.2" __version__ = "0.2"
import Image, ImageFile from . import Image, ImageFile, _binary
_handler = None _handler = None
if str != bytes:
long = int
## ##
# Install application-specific WMF image handler. # Install application-specific WMF image handler.
# #
@ -41,7 +44,7 @@ if hasattr(Image.core, "drawwmf"):
def load(self, im): def load(self, im):
im.fp.seek(0) # rewind im.fp.seek(0) # rewind
return Image.fromstring( return Image.frombytes(
"RGB", im.size, "RGB", im.size,
Image.core.drawwmf(im.fp.read(), im.size, self.bbox), Image.core.drawwmf(im.fp.read(), im.size, self.bbox),
"raw", "BGR", (im.size[0]*3 + 3) & -4, -1 "raw", "BGR", (im.size[0]*3 + 3) & -4, -1
@ -51,20 +54,15 @@ if hasattr(Image.core, "drawwmf"):
# -------------------------------------------------------------------- # --------------------------------------------------------------------
def word(c, o=0): word = _binary.i16le
return ord(c[o]) + (ord(c[o+1])<<8)
def short(c, o=0): def short(c, o=0):
v = ord(c[o]) + (ord(c[o+1])<<8) v = word(c, o)
if v >= 32768: if v >= 32768:
v = v - 65536 v = v - 65536
return v return v
def dword(c, o=0): dword = _binary.i32le
return ord(c[o]) + (ord(c[o+1])<<8) + (ord(c[o+2])<<16) + (ord(c[o+3])<<24)
def long(c, o=0):
return dword(c, o)
# #
# -------------------------------------------------------------------- # --------------------------------------------------------------------
@ -72,8 +70,8 @@ def long(c, o=0):
def _accept(prefix): def _accept(prefix):
return ( return (
prefix[:6] == "\xd7\xcd\xc6\x9a\x00\x00" or prefix[:6] == b"\xd7\xcd\xc6\x9a\x00\x00" or
prefix[:4] == "\x01\x00\x00\x00" prefix[:4] == b"\x01\x00\x00\x00"
) )
## ##
@ -89,7 +87,7 @@ class WmfStubImageFile(ImageFile.StubImageFile):
# check placable header # check placable header
s = self.fp.read(80) s = self.fp.read(80)
if s[:6] == "\xd7\xcd\xc6\x9a\x00\x00": if s[:6] == b"\xd7\xcd\xc6\x9a\x00\x00":
# placeable windows metafile # placeable windows metafile
@ -101,7 +99,7 @@ class WmfStubImageFile(ImageFile.StubImageFile):
x1 = short(s, 10); y1 = short(s, 12) x1 = short(s, 10); y1 = short(s, 12)
# normalize size to 72 dots per inch # normalize size to 72 dots per inch
size = (x1 - x0) * 72 / inch, (y1 - y0) * 72 / inch size = (x1 - x0) * 72 // inch, (y1 - y0) * 72 // inch
self.info["wmf_bbox"] = x0, y0, x1, y1 self.info["wmf_bbox"] = x0, y0, x1, y1
@ -110,25 +108,25 @@ class WmfStubImageFile(ImageFile.StubImageFile):
# print self.mode, self.size, self.info # print self.mode, self.size, self.info
# sanity check (standard metafile header) # sanity check (standard metafile header)
if s[22:26] != "\x01\x00\t\x00": if s[22:26] != b"\x01\x00\t\x00":
raise SyntaxError("Unsupported WMF file format") raise SyntaxError("Unsupported WMF file format")
elif long(s) == 1 and s[40:44] == " EMF": elif dword(s) == 1 and s[40:44] == b" EMF":
# enhanced metafile # enhanced metafile
# get bounding box # get bounding box
x0 = long(s, 8); y0 = long(s, 12) x0 = dword(s, 8); y0 = dword(s, 12)
x1 = long(s, 16); y1 = long(s, 20) x1 = dword(s, 16); y1 = dword(s, 20)
# get frame (in 0.01 millimeter units) # get frame (in 0.01 millimeter units)
frame = long(s, 24), long(s, 28), long(s, 32), long(s, 36) frame = dword(s, 24), dword(s, 28), dword(s, 32), dword(s, 36)
# normalize size to 72 dots per inch # normalize size to 72 dots per inch
size = x1 - x0, y1 - y0 size = x1 - x0, y1 - y0
# calculate dots per inch from bbox and frame # calculate dots per inch from bbox and frame
xdpi = 2540 * (x1 - y0) / (frame[2] - frame[0]) xdpi = 2540 * (x1 - y0) // (frame[2] - frame[0])
ydpi = 2540 * (y1 - y0) / (frame[3] - frame[1]) ydpi = 2540 * (y1 - y0) // (frame[3] - frame[1])
self.info["wmf_bbox"] = x0, y0, x1, y1 self.info["wmf_bbox"] = x0, y0, x1, y1

View File

@ -19,15 +19,16 @@
__version__ = "0.1" __version__ = "0.1"
import string from . import Image, ImageFile, ImagePalette, _binary
import Image, ImageFile, ImagePalette
o8 = _binary.o8
# standard color palette for thumbnails (RGB332) # standard color palette for thumbnails (RGB332)
PALETTE = "" PALETTE = b""
for r in range(8): for r in range(8):
for g in range(8): for g in range(8):
for b in range(4): for b in range(4):
PALETTE = PALETTE + (chr((r*255)/7)+chr((g*255)/7)+chr((b*255)/3)) PALETTE = PALETTE + (o8((r*255)//7)+o8((g*255)//7)+o8((b*255)//3))
## ##
# Image plugin for XV thumbnail images. # Image plugin for XV thumbnail images.
@ -41,25 +42,25 @@ class XVThumbImageFile(ImageFile.ImageFile):
# check magic # check magic
s = self.fp.read(6) s = self.fp.read(6)
if s != "P7 332": if s != b"P7 332":
raise SyntaxError, "not an XV thumbnail file" raise SyntaxError("not an XV thumbnail file")
# Skip to beginning of next line # Skip to beginning of next line
self.fp.readline() self.fp.readline()
# skip info comments # skip info comments
while 1: while True:
s = self.fp.readline() s = self.fp.readline()
if not s: if not s:
raise SyntaxError, "Unexpected EOF reading XV thumbnail file" raise SyntaxError("Unexpected EOF reading XV thumbnail file")
if s[0] != '#': if s[0] != b'#':
break break
# parse header line (already read) # parse header line (already read)
s = string.split(s.strip()) s = s.strip().split()
self.mode = "P" self.mode = "P"
self.size = int(s[0]), int(s[1]) self.size = int(s[0:1]), int(s[1:2])
self.palette = ImagePalette.raw("RGB", PALETTE) self.palette = ImagePalette.raw("RGB", PALETTE)

View File

@ -21,22 +21,22 @@
__version__ = "0.6" __version__ = "0.6"
import re, string import re
import Image, ImageFile from . import Image, ImageFile
# XBM header # XBM header
xbm_head = re.compile( xbm_head = re.compile(
"\s*#define[ \t]+[^_]*_width[ \t]+(?P<width>[0-9]+)[\r\n]+" b"\s*#define[ \t]+[^_]*_width[ \t]+(?P<width>[0-9]+)[\r\n]+"
"#define[ \t]+[^_]*_height[ \t]+(?P<height>[0-9]+)[\r\n]+" b"#define[ \t]+[^_]*_height[ \t]+(?P<height>[0-9]+)[\r\n]+"
"(?P<hotspot>" b"(?P<hotspot>"
"#define[ \t]+[^_]*_x_hot[ \t]+(?P<xhot>[0-9]+)[\r\n]+" b"#define[ \t]+[^_]*_x_hot[ \t]+(?P<xhot>[0-9]+)[\r\n]+"
"#define[ \t]+[^_]*_y_hot[ \t]+(?P<yhot>[0-9]+)[\r\n]+" b"#define[ \t]+[^_]*_y_hot[ \t]+(?P<yhot>[0-9]+)[\r\n]+"
")?" b")?"
"[\\000-\\377]*_bits\\[\\]" b"[\\000-\\377]*_bits\\[\\]"
) )
def _accept(prefix): def _accept(prefix):
return string.lstrip(prefix)[:7] == "#define" return prefix.lstrip()[:7] == b"#define"
## ##
# Image plugin for X11 bitmaps. # Image plugin for X11 bitmaps.
@ -69,21 +69,21 @@ class XbmImageFile(ImageFile.ImageFile):
def _save(im, fp, filename): def _save(im, fp, filename):
if im.mode != "1": if im.mode != "1":
raise IOError, "cannot write mode %s as XBM" % im.mode raise IOError("cannot write mode %s as XBM" % im.mode)
fp.write("#define im_width %d\n" % im.size[0]) fp.write(("#define im_width %d\n" % im.size[0]).encode('ascii'))
fp.write("#define im_height %d\n" % im.size[1]) fp.write(("#define im_height %d\n" % im.size[1]).encode('ascii'))
hotspot = im.encoderinfo.get("hotspot") hotspot = im.encoderinfo.get("hotspot")
if hotspot: if hotspot:
fp.write("#define im_x_hot %d\n" % hotspot[0]) fp.write(("#define im_x_hot %d\n" % hotspot[0]).encode('ascii'))
fp.write("#define im_y_hot %d\n" % hotspot[1]) fp.write(("#define im_y_hot %d\n" % hotspot[1]).encode('ascii'))
fp.write("static char im_bits[] = {\n") fp.write(b"static char im_bits[] = {\n")
ImageFile._save(im, fp, [("xbm", (0,0)+im.size, 0, None)]) ImageFile._save(im, fp, [("xbm", (0,0)+im.size, 0, None)])
fp.write("};\n") fp.write(b"};\n")
Image.register_open("XBM", XbmImageFile, _accept) Image.register_open("XBM", XbmImageFile, _accept)

View File

@ -18,15 +18,16 @@
__version__ = "0.2" __version__ = "0.2"
import re, string import re
import Image, ImageFile, ImagePalette from . import Image, ImageFile, ImagePalette
from ._binary import i8, o8
# XPM header # XPM header
xpm_head = re.compile("\"([0-9]*) ([0-9]*) ([0-9]*) ([0-9]*)") xpm_head = re.compile(b"\"([0-9]*) ([0-9]*) ([0-9]*) ([0-9]*)")
def _accept(prefix): def _accept(prefix):
return prefix[:9] == "/* XPM */" return prefix[:9] == b"/* XPM */"
## ##
# Image plugin for X11 pixel maps. # Image plugin for X11 pixel maps.
@ -39,13 +40,13 @@ class XpmImageFile(ImageFile.ImageFile):
def _open(self): def _open(self):
if not _accept(self.fp.read(9)): if not _accept(self.fp.read(9)):
raise SyntaxError, "not an XPM file" raise SyntaxError("not an XPM file")
# skip forward to next string # skip forward to next string
while 1: while True:
s = self.fp.readline() s = self.fp.readline()
if not s: if not s:
raise SyntaxError, "broken XPM file" raise SyntaxError("broken XPM file")
m = xpm_head.match(s) m = xpm_head.match(s)
if m: if m:
break break
@ -56,50 +57,50 @@ class XpmImageFile(ImageFile.ImageFile):
bpp = int(m.group(4)) bpp = int(m.group(4))
if pal > 256 or bpp != 1: if pal > 256 or bpp != 1:
raise ValueError, "cannot read this XPM file" raise ValueError("cannot read this XPM file")
# #
# load palette description # load palette description
palette = ["\0\0\0"] * 256 palette = [b"\0\0\0"] * 256
for i in range(pal): for i in range(pal):
s = self.fp.readline() s = self.fp.readline()
if s[-2:] == '\r\n': if s[-2:] == b'\r\n':
s = s[:-2] s = s[:-2]
elif s[-1:] in '\r\n': elif s[-1:] in b'\r\n':
s = s[:-1] s = s[:-1]
c = ord(s[1]) c = i8(s[1])
s = string.split(s[2:-2]) s = s[2:-2].split()
for i in range(0, len(s), 2): for i in range(0, len(s), 2):
if s[i] == "c": if s[i] == b"c":
# process colour key # process colour key
rgb = s[i+1] rgb = s[i+1]
if rgb == "None": if rgb == b"None":
self.info["transparency"] = c self.info["transparency"] = c
elif rgb[0] == "#": elif rgb[0:1] == b"#":
# FIXME: handle colour names (see ImagePalette.py) # FIXME: handle colour names (see ImagePalette.py)
rgb = string.atoi(rgb[1:], 16) rgb = int(rgb[1:], 16)
palette[c] = chr((rgb >> 16) & 255) +\ palette[c] = o8((rgb >> 16) & 255) +\
chr((rgb >> 8) & 255) +\ o8((rgb >> 8) & 255) +\
chr(rgb & 255) o8(rgb & 255)
else: else:
# unknown colour # unknown colour
raise ValueError, "cannot read this XPM file" raise ValueError("cannot read this XPM file")
break break
else: else:
# missing colour key # missing colour key
raise ValueError, "cannot read this XPM file" raise ValueError("cannot read this XPM file")
self.mode = "P" self.mode = "P"
self.palette = ImagePalette.raw("RGB", string.join(palette, "")) self.palette = ImagePalette.raw("RGB", b"".join(palette))
self.tile = [("raw", (0, 0)+self.size, self.fp.tell(), ("P", 0, 1))] self.tile = [("raw", (0, 0)+self.size, self.fp.tell(), ("P", 0, 1))]
@ -113,11 +114,11 @@ class XpmImageFile(ImageFile.ImageFile):
s = [None] * ysize s = [None] * ysize
for i in range(ysize): for i in range(ysize):
s[i] = string.ljust(self.fp.readline()[1:xsize+1], xsize) s[i] = self.fp.readline()[1:xsize+1].ljust(xsize)
self.fp = None self.fp = None
return string.join(s, "") return b"".join(s)
# #
# Registry # Registry

52
PIL/_binary.py Normal file
View File

@ -0,0 +1,52 @@
#
# The Python Imaging Library.
# $Id$
#
# Binary input/output support routines.
#
# Copyright (c) 1997-2003 by Secret Labs AB
# Copyright (c) 1995-2003 by Fredrik Lundh
# Copyright (c) 2012 by Brian Crowell
#
# See the README file for information on usage and redistribution.
#
if bytes is str:
def i8(c):
return ord(c)
def o8(i):
return chr(i&255)
else:
def i8(c):
return c if c.__class__ is int else c[0]
def o8(i):
return bytes((i&255,))
# Input, le = little endian, be = big endian
def i16le(c, o=0):
return i8(c[o]) | (i8(c[o+1])<<8)
def i32le(c, o=0):
return i8(c[o]) | (i8(c[o+1])<<8) | (i8(c[o+2])<<16) | (i8(c[o+3])<<24)
def i16be(c, o=0):
return (i8(c[o])<<8) | i8(c[o+1])
def i32be(c, o=0):
return (i8(c[o])<<24) | (i8(c[o+1])<<16) | (i8(c[o+2])<<8) | i8(c[o+3])
# Output, le = little endian, be = big endian
def o16le(i):
return o8(i) + o8(i>>8)
def o32le(i):
return o8(i) + o8(i>>8) + o8(i>>16) + o8(i>>24)
def o16be(i):
return o8(i>>8) + o8(i)
def o32be(i):
return o8(i>>24) + o8(i>>16) + o8(i>>8) + o8(i)

View File

@ -28,6 +28,12 @@ PERFORMANCE OF THIS SOFTWARE.
#include <sys/time.h> #include <sys/time.h>
#if PY_MAJOR_VERSION >= 3
#define PyInt_AsLong PyLong_AsLong
#define PyInt_FromLong PyLong_FromLong
#define PyInt_Check PyLong_Check
#endif
static PyObject *ErrorObject; static PyObject *ErrorObject;
typedef struct { typedef struct {
@ -51,14 +57,18 @@ PySane_Error(SANE_Status st)
return NULL; return NULL;
} }
staticforward PyTypeObject SaneDev_Type; static PyTypeObject SaneDev_Type;
#define SaneDevObject_Check(v) ((v)->ob_type == &SaneDev_Type) #define SaneDevObject_Check(v) (Py_TYPE(v) == &SaneDev_Type)
static SaneDevObject * static SaneDevObject *
newSaneDevObject(void) newSaneDevObject(void)
{ {
SaneDevObject *self; SaneDevObject *self;
if (PyType_Ready(&SaneDev_Type) < 0)
return NULL;
self = PyObject_NEW(SaneDevObject, &SaneDev_Type); self = PyObject_NEW(SaneDevObject, &SaneDev_Type);
if (self == NULL) if (self == NULL)
return NULL; return NULL;
@ -233,7 +243,11 @@ SaneDev_get_options(SaneDevObject *self, PyObject *args)
constraint=PyList_New(0); constraint=PyList_New(0);
for(j=0; d->constraint.string_list[j]!=NULL; j++) for(j=0; d->constraint.string_list[j]!=NULL; j++)
PyList_Append(constraint, PyList_Append(constraint,
#if PY_MAJOR_VERSION >= 3
PyUnicode_DecodeLatin1(d->constraint.string_list[j], strlen(d->constraint.string_list[j]), NULL));
#else
PyString_FromString(d->constraint.string_list[j])); PyString_FromString(d->constraint.string_list[j]));
#endif
break; break;
} }
value=Py_BuildValue("isssiiiiO", i, d->name, d->title, d->desc, value=Py_BuildValue("isssiiiiO", i, d->name, d->title, d->desc,
@ -284,7 +298,11 @@ SaneDev_get_option(SaneDevObject *self, PyObject *args)
value=Py_BuildValue("d", SANE_UNFIX((*((SANE_Fixed*)v))) ); value=Py_BuildValue("d", SANE_UNFIX((*((SANE_Fixed*)v))) );
break; break;
case(SANE_TYPE_STRING): case(SANE_TYPE_STRING):
#if PY_MAJOR_VERSION >= 3
value=PyUnicode_DecodeLatin1((const char *) v, strlen((const char *) v), NULL);
#else
value=Py_BuildValue("s", v); value=Py_BuildValue("s", v);
#endif
break; break;
case(SANE_TYPE_BUTTON): case(SANE_TYPE_BUTTON):
case(SANE_TYPE_GROUP): case(SANE_TYPE_GROUP):
@ -345,6 +363,24 @@ SaneDev_set_option(SaneDevObject *self, PyObject *args)
*( (SANE_Fixed*)v) = SANE_FIX(PyFloat_AsDouble(value)); *( (SANE_Fixed*)v) = SANE_FIX(PyFloat_AsDouble(value));
break; break;
case(SANE_TYPE_STRING): case(SANE_TYPE_STRING):
#if PY_MAJOR_VERSION >= 3
if (!PyUnicode_Check(value))
{
PyErr_SetString(PyExc_TypeError, "SANE_STRING requires a string");
free(v);
return NULL;
}
{
PyObject *encoded = PyUnicode_AsLatin1String(value);
if (!encoded)
return NULL;
strncpy(v, PyBytes_AsString(encoded), d->size-1);
((char*)v)[d->size-1] = 0;
Py_DECREF(encoded);
}
#else
if (!PyString_Check(value)) if (!PyString_Check(value))
{ {
PyErr_SetString(PyExc_TypeError, "SANE_STRING requires a string"); PyErr_SetString(PyExc_TypeError, "SANE_STRING requires a string");
@ -353,6 +389,7 @@ SaneDev_set_option(SaneDevObject *self, PyObject *args)
} }
strncpy(v, PyString_AsString(value), d->size-1); strncpy(v, PyString_AsString(value), d->size-1);
((char*)v)[d->size-1] = 0; ((char*)v)[d->size-1] = 0;
#endif
break; break;
case(SANE_TYPE_BUTTON): case(SANE_TYPE_BUTTON):
case(SANE_TYPE_GROUP): case(SANE_TYPE_GROUP):
@ -1095,29 +1132,38 @@ static PyMethodDef SaneDev_methods[] = {
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };
static PyObject * static PyTypeObject SaneDev_Type = {
SaneDev_getattr(SaneDevObject *self, char *name) PyVarObject_HEAD_INIT(NULL, 0)
{
return Py_FindMethod(SaneDev_methods, (PyObject *)self, name);
}
staticforward PyTypeObject SaneDev_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0, /*ob_size*/
"SaneDev", /*tp_name*/ "SaneDev", /*tp_name*/
sizeof(SaneDevObject), /*tp_basicsize*/ sizeof(SaneDevObject), /*tp_basicsize*/
0, /*tp_itemsize*/ 0, /*tp_itemsize*/
/* methods */ /* methods */
(destructor)SaneDev_dealloc, /*tp_dealloc*/ (destructor)SaneDev_dealloc, /*tp_dealloc*/
0, /*tp_print*/ 0, /*tp_print*/
(getattrfunc)SaneDev_getattr, /*tp_getattr*/ 0, /*tp_getattr*/
0, /*tp_setattr*/ 0, /*tp_setattr*/
0, /*tp_compare*/ 0, /*tp_compare*/
0, /*tp_repr*/ 0, /*tp_repr*/
0, /*tp_as_number*/ 0, /*tp_as_number */
0, /*tp_as_sequence*/ 0, /*tp_as_sequence */
0, /*tp_as_mapping*/ 0, /*tp_as_mapping */
0, /*tp_hash*/ 0, /*tp_hash*/
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
0, /*tp_doc*/
0, /*tp_traverse*/
0, /*tp_clear*/
0, /*tp_richcompare*/
0, /*tp_weaklistoffset*/
0, /*tp_iter*/
0, /*tp_iternext*/
SaneDev_methods, /*tp_methods*/
0, /*tp_members*/
0, /*tp_getset*/
}; };
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
@ -1152,8 +1198,8 @@ PySane_exit(PyObject *self, PyObject *args)
static PyObject * static PyObject *
PySane_get_devices(PyObject *self, PyObject *args) PySane_get_devices(PyObject *self, PyObject *args)
{ {
SANE_Device **devlist; const SANE_Device **devlist;
SANE_Device *dev; const SANE_Device *dev;
SANE_Status st; SANE_Status st;
PyObject *list; PyObject *list;
int local_only, i; int local_only, i;
@ -1163,7 +1209,9 @@ PySane_get_devices(PyObject *self, PyObject *args)
return NULL; return NULL;
} }
Py_BEGIN_ALLOW_THREADS
st=sane_get_devices(&devlist, local_only); st=sane_get_devices(&devlist, local_only);
Py_END_ALLOW_THREADS
if (st) return PySane_Error(st); if (st) return PySane_Error(st);
if (!(list = PyList_New(0))) if (!(list = PyList_New(0)))
return NULL; return NULL;
@ -1191,7 +1239,9 @@ PySane_open(PyObject *self, PyObject *args)
rv = newSaneDevObject(); rv = newSaneDevObject();
if ( rv == NULL ) if ( rv == NULL )
return NULL; return NULL;
Py_BEGIN_ALLOW_THREADS
st = sane_open(name, &(rv->h)); st = sane_open(name, &(rv->h));
Py_END_ALLOW_THREADS
if (st) if (st)
{ {
Py_DECREF(rv); Py_DECREF(rv);
@ -1248,17 +1298,40 @@ insint(PyObject *d, char *name, int value)
Py_DECREF(v); Py_DECREF(v);
} }
void #if PY_MAJOR_VERSION >= 3
static struct PyModuleDef PySane_moduledef = {
PyModuleDef_HEAD_INIT,
"_sane",
NULL,
0,
PySane_methods,
NULL,
NULL,
NULL,
NULL
};
PyMODINIT_FUNC
PyInit__sane(void)
{
/* Create the module and add the functions */
PyObject *m = PyModule_Create(&PySane_moduledef);
if(!m)
return NULL;
#else /* if PY_MAJOR_VERSION < 3 */
PyMODINIT_FUNC
init_sane(void) init_sane(void)
{ {
PyObject *m, *d;
/* Create the module and add the functions */ /* Create the module and add the functions */
m = Py_InitModule("_sane", PySane_methods); PyObject *m = Py_InitModule("_sane", PySane_methods);
if(!m)
return;
#endif
/* Add some symbolic constants to the module */ /* Add some symbolic constants to the module */
d = PyModule_GetDict(m); PyObject *d = PyModule_GetDict(m);
ErrorObject = PyString_FromString("_sane.error"); ErrorObject = PyErr_NewException("_sane.error", NULL, NULL);
PyDict_SetItemString(d, "error", ErrorObject); PyDict_SetItemString(d, "error", ErrorObject);
insint(d, "INFO_INEXACT", SANE_INFO_INEXACT); insint(d, "INFO_INEXACT", SANE_INFO_INEXACT);
@ -1322,4 +1395,7 @@ init_sane(void)
NUMARRAY_IMPORTED = 1; NUMARRAY_IMPORTED = 1;
#endif /* WITH_NUMARRAY */ #endif /* WITH_NUMARRAY */
#if PY_MAJOR_VERSION >= 3
return m;
#endif
} }

View File

@ -4,6 +4,8 @@
# Shows how to scan a 16 bit grayscale image into a numarray object # Shows how to scan a 16 bit grayscale image into a numarray object
# #
from __future__ import print_function
# Get the path set up to find PIL modules if not installed yet: # Get the path set up to find PIL modules if not installed yet:
import sys ; sys.path.append('../PIL') import sys ; sys.path.append('../PIL')
@ -14,17 +16,17 @@ import Image
def toImage(arr): def toImage(arr):
if arr.type().bytes == 1: if arr.type().bytes == 1:
# need to swap coordinates btw array and image (with [::-1]) # need to swap coordinates btw array and image (with [::-1])
im = Image.fromstring('L', arr.shape[::-1], arr.tostring()) im = Image.frombytes('L', arr.shape[::-1], arr.tostring())
else: else:
arr_c = arr - arr.min() arr_c = arr - arr.min()
arr_c *= (255./arr_c.max()) arr_c *= (255./arr_c.max())
arr = arr_c.astype(UInt8) arr = arr_c.astype(UInt8)
# need to swap coordinates btw array and image (with [::-1]) # need to swap coordinates btw array and image (with [::-1])
im = Image.fromstring('L', arr.shape[::-1], arr.tostring()) im = Image.frombytes('L', arr.shape[::-1], arr.tostring())
return im return im
print 'SANE version:', sane.init() print('SANE version:', sane.init())
print 'Available devices=', sane.get_devices() print('Available devices=', sane.get_devices())
s = sane.open(sane.get_devices()[0][0]) s = sane.open(sane.get_devices()[0][0])
@ -32,7 +34,7 @@ s = sane.open(sane.get_devices()[0][0])
s.mode = 'gray' s.mode = 'gray'
s.br_x=320. ; s.br_y=240. s.br_x=320. ; s.br_y=240.
print 'Device parameters:', s.get_parameters() print('Device parameters:', s.get_parameters())
s.depth=16 s.depth=16
arr16 = s.arr_scan() arr16 = s.arr_scan()

View File

@ -4,19 +4,21 @@
# Shows how to scan a color image into a PIL rgb-image # Shows how to scan a color image into a PIL rgb-image
# #
from __future__ import print_function
# Get the path set up to find PIL modules if not installed yet: # Get the path set up to find PIL modules if not installed yet:
import sys ; sys.path.append('../PIL') import sys ; sys.path.append('../PIL')
import sane import sane
print 'SANE version:', sane.init() print('SANE version:', sane.init())
print 'Available devices=', sane.get_devices() print('Available devices=', sane.get_devices())
s = sane.open(sane.get_devices()[0][0]) s = sane.open(sane.get_devices()[0][0])
s.mode = 'color' s.mode = 'color'
s.br_x=320. ; s.br_y=240. s.br_x=320. ; s.br_y=240.
print 'Device parameters:', s.get_parameters() print('Device parameters:', s.get_parameters())
# Initiate the scan # Initiate the scan
s.start() s.start()

View File

@ -46,7 +46,6 @@ class Option:
""" """
def __init__(self, args, scanDev): def __init__(self, args, scanDev):
import string
self.scanDev = scanDev # needed to get current value of this option self.scanDev = scanDev # needed to get current value of this option
self.index, self.name = args[0], args[1] self.index, self.name = args[0], args[1]
self.title, self.desc = args[2], args[3] self.title, self.desc = args[2], args[3]
@ -56,8 +55,8 @@ class Option:
def f(x): def f(x):
if x=='-': return '_' if x=='-': return '_'
else: return x else: return x
if type(self.name)!=type(''): self.py_name=str(self.name) if not isinstance(self.name, str): self.py_name=str(self.name)
else: self.py_name=string.join(map(f, self.name), '') else: self.py_name=''.join(map(f, self.name))
def is_active(self): def is_active(self):
return _sane.OPTION_IS_ACTIVE(self.cap) return _sane.OPTION_IS_ACTIVE(self.cap)
@ -86,7 +85,7 @@ active: %s
settable: %s\n""" % (self.py_name, curValue, settable: %s\n""" % (self.py_name, curValue,
self.index, self.title, self.desc, self.index, self.title, self.desc,
TYPE_STR[self.type], UNIT_STR[self.unit], TYPE_STR[self.type], UNIT_STR[self.unit],
`self.constraint`, active, settable) repr(self.constraint), active, settable)
return s return s
@ -106,7 +105,7 @@ class _SaneIterator:
def next(self): def next(self):
try: try:
self.device.start() self.device.start()
except error, v: except error as v:
if v == 'Document feeder out of documents': if v == 'Document feeder out of documents':
raise StopIteration raise StopIteration
else: else:
@ -166,16 +165,16 @@ class SaneDev:
def __setattr__(self, key, value): def __setattr__(self, key, value):
dev=self.__dict__['dev'] dev=self.__dict__['dev']
optdict=self.__dict__['opt'] optdict=self.__dict__['opt']
if not optdict.has_key(key): if key not in optdict:
self.__dict__[key]=value ; return self.__dict__[key]=value ; return
opt=optdict[key] opt=optdict[key]
if opt.type==TYPE_GROUP: if opt.type==TYPE_GROUP:
raise AttributeError, "Groups can't be set: "+key raise AttributeError("Groups can't be set: "+key)
if not _sane.OPTION_IS_ACTIVE(opt.cap): if not _sane.OPTION_IS_ACTIVE(opt.cap):
raise AttributeError, 'Inactive option: '+key raise AttributeError('Inactive option: '+key)
if not _sane.OPTION_IS_SETTABLE(opt.cap): if not _sane.OPTION_IS_SETTABLE(opt.cap):
raise AttributeError, "Option can't be set by software: "+key raise AttributeError("Option can't be set by software: "+key)
if type(value) == int and opt.type == TYPE_FIXED: if isinstance(value, int) and opt.type == TYPE_FIXED:
# avoid annoying errors of backend if int is given instead float: # avoid annoying errors of backend if int is given instead float:
value = float(value) value = float(value)
self.last_opt = dev.set_option(opt.index, value) self.last_opt = dev.set_option(opt.index, value)
@ -187,18 +186,18 @@ class SaneDev:
dev=self.__dict__['dev'] dev=self.__dict__['dev']
optdict=self.__dict__['opt'] optdict=self.__dict__['opt']
if key=='optlist': if key=='optlist':
return self.opt.keys() return list(self.opt.keys())
if key=='area': if key=='area':
return (self.tl_x, self.tl_y),(self.br_x, self.br_y) return (self.tl_x, self.tl_y),(self.br_x, self.br_y)
if not optdict.has_key(key): if key not in optdict:
raise AttributeError, 'No such attribute: '+key raise AttributeError('No such attribute: '+key)
opt=optdict[key] opt=optdict[key]
if opt.type==TYPE_BUTTON: if opt.type==TYPE_BUTTON:
raise AttributeError, "Buttons don't have values: "+key raise AttributeError("Buttons don't have values: "+key)
if opt.type==TYPE_GROUP: if opt.type==TYPE_GROUP:
raise AttributeError, "Groups don't have values: "+key raise AttributeError("Groups don't have values: "+key)
if not _sane.OPTION_IS_ACTIVE(opt.cap): if not _sane.OPTION_IS_ACTIVE(opt.cap):
raise AttributeError, 'Inactive option: '+key raise AttributeError('Inactive option: '+key)
value = dev.get_option(opt.index) value = dev.get_option(opt.index)
return value return value

View File

@ -6,7 +6,11 @@
# drag the slider to modify the image. # drag the slider to modify the image.
# #
from Tkinter import * try:
from tkinter import *
except ImportError:
from Tkinter import *
from PIL import Image, ImageTk, ImageEnhance from PIL import Image, ImageTk, ImageEnhance
import sys import sys

View File

@ -5,8 +5,10 @@
# split an animation into a number of frame files # split an animation into a number of frame files
# #
from __future__ import print_function
from PIL import Image from PIL import Image
import os, string, sys import os, sys
class Interval: class Interval:
@ -18,23 +20,23 @@ class Interval:
self.hilo = [] self.hilo = []
for s in string.split(interval, ","): for s in interval.split(","):
if not string.strip(s): if not s.strip():
continue continue
try: try:
v = string.atoi(s) v = int(s)
if v < 0: if v < 0:
lo, hi = 0, -v lo, hi = 0, -v
else: else:
lo = hi = v lo = hi = v
except ValueError: except ValueError:
i = string.find(s, "-") i = s.find("-")
lo, hi = string.atoi(s[:i]), string.atoi(s[i+1:]) lo, hi = int(s[:i]), int(s[i+1:])
self.hilo.append((hi, lo)) self.hilo.append((hi, lo))
if not self.hilo: if not self.hilo:
self.hilo = [(sys.maxint, 0)] self.hilo = [(sys.maxsize, 0)]
def __getitem__(self, index): def __getitem__(self, index):
@ -53,23 +55,23 @@ if sys.argv[1:2] == ["-h"]:
del sys.argv[1] del sys.argv[1]
if not sys.argv[2:]: if not sys.argv[2:]:
print print()
print "Syntax: python explode.py infile template [range]" print("Syntax: python explode.py infile template [range]")
print print()
print "The template argument is used to construct the names of the" print("The template argument is used to construct the names of the")
print "individual frame files. The frames are numbered file001.ext," print("individual frame files. The frames are numbered file001.ext,")
print "file002.ext, etc. You can insert %d to control the placement" print("file002.ext, etc. You can insert %d to control the placement")
print "and syntax of the frame number." print("and syntax of the frame number.")
print print()
print "The optional range argument specifies which frames to extract." print("The optional range argument specifies which frames to extract.")
print "You can give one or more ranges like 1-10, 5, -15 etc. If" print("You can give one or more ranges like 1-10, 5, -15 etc. If")
print "omitted, all frames are extracted." print("omitted, all frames are extracted.")
sys.exit(1) sys.exit(1)
infile = sys.argv[1] infile = sys.argv[1]
outfile = sys.argv[2] outfile = sys.argv[2]
frames = Interval(string.join(sys.argv[3:], ",")) frames = Interval(",".join(sys.argv[3:]))
try: try:
# check if outfile contains a placeholder # check if outfile contains a placeholder
@ -87,11 +89,11 @@ if html:
html = open(file+".html", "w") html = open(file+".html", "w")
html.write("<html>\n<body>\n") html.write("<html>\n<body>\n")
while 1: while True:
if frames[ix]: if frames[ix]:
im.save(outfile % ix) im.save(outfile % ix)
print outfile % ix print(outfile % ix)
if html: if html:
html.write("<img src='%s'><br>\n" % outfile % ix) html.write("<img src='%s'><br>\n" % outfile % ix)

View File

@ -39,8 +39,9 @@
# write data directly to a socket. Or something... # write data directly to a socket. Or something...
# #
from __future__ import print_function
from PIL import Image, ImageChops from PIL import Image, ImageChops
import string
from PIL.GifImagePlugin import getheader, getdata from PIL.GifImagePlugin import getheader, getdata
@ -128,8 +129,8 @@ if __name__ == "__main__":
import sys import sys
if len(sys.argv) < 3: if len(sys.argv) < 3:
print "GIFMAKER -- create GIF animations" print("GIFMAKER -- create GIF animations")
print "Usage: gifmaker infile outfile" print("Usage: gifmaker infile outfile")
sys.exit(1) sys.exit(1)
compress(sys.argv[1], sys.argv[2]) compress(sys.argv[1], sys.argv[2])

View File

@ -8,7 +8,11 @@
# the image into a set of tiles. # the image into a set of tiles.
# #
from Tkinter import * try:
from tkinter import *
except ImportError:
from Tkinter import *
from PIL import Image, ImageTk from PIL import Image, ImageTk
import sys import sys

View File

@ -13,27 +13,29 @@
# 0.5 98-12-30 fl Fixed -f option (from Anthony Baxter) # 0.5 98-12-30 fl Fixed -f option (from Anthony Baxter)
# #
from __future__ import print_function
import site import site
import getopt, string, sys import getopt, string, sys
from PIL import Image from PIL import Image
def usage(): def usage():
print "PIL Convert 0.5/1998-12-30 -- convert image files" print("PIL Convert 0.5/1998-12-30 -- convert image files")
print "Usage: pilconvert [option] infile outfile" print("Usage: pilconvert [option] infile outfile")
print print()
print "Options:" print("Options:")
print print()
print " -c <format> convert to format (default is given by extension)" print(" -c <format> convert to format (default is given by extension)")
print print()
print " -g convert to greyscale" print(" -g convert to greyscale")
print " -p convert to palette image (using standard palette)" print(" -p convert to palette image (using standard palette)")
print " -r convert to rgb" print(" -r convert to rgb")
print print()
print " -o optimize output (trade speed for size)" print(" -o optimize output (trade speed for size)")
print " -q <value> set compression quality (0-100, JPEG only)" print(" -q <value> set compression quality (0-100, JPEG only)")
print print()
print " -f list supported file formats" print(" -f list supported file formats")
sys.exit(1) sys.exit(1)
if len(sys.argv) == 1: if len(sys.argv) == 1:
@ -41,8 +43,8 @@ if len(sys.argv) == 1:
try: try:
opt, argv = getopt.getopt(sys.argv[1:], "c:dfgopq:r") opt, argv = getopt.getopt(sys.argv[1:], "c:dfgopq:r")
except getopt.error, v: except getopt.error as v:
print v print(v)
sys.exit(1) sys.exit(1)
format = None format = None
@ -54,14 +56,13 @@ for o, a in opt:
if o == "-f": if o == "-f":
Image.init() Image.init()
id = Image.ID[:] id = sorted(Image.ID)
id.sort() print("Supported formats (* indicates output format):")
print "Supported formats (* indicates output format):"
for i in id: for i in id:
if Image.SAVE.has_key(i): if i in Image.SAVE:
print i+"*", print(i+"*", end=' ')
else: else:
print i, print(i, end=' ')
sys.exit(1) sys.exit(1)
elif o == "-c": elif o == "-c":
@ -88,9 +89,9 @@ try:
im.draft(convert, im.size) im.draft(convert, im.size)
im = im.convert(convert) im = im.convert(convert)
if format: if format:
apply(im.save, (argv[1], format), options) im.save(argv[1], format, **options)
else: else:
apply(im.save, (argv[1],), options) im.save(argv[1], **options)
except: except:
print "cannot convert image", print("cannot convert image", end=' ')
print "(%s:%s)" % (sys.exc_type, sys.exc_value) print("(%s:%s)" % (sys.exc_info()[0], sys.exc_info()[1]))

View File

@ -48,8 +48,9 @@ of its upper-left-hand corner and displays the cropped portion.
# 3. Add support for composing and decomposing multiple-image files. # 3. Add support for composing and decomposing multiple-image files.
# #
from __future__ import print_function
from PIL import Image from PIL import Image
import string
class PILDriver: class PILDriver:
@ -206,7 +207,7 @@ class PILDriver:
Process the top image with the given filter. Process the top image with the given filter.
""" """
import ImageFilter import ImageFilter
filter = eval("ImageFilter." + string.upper(self.do_pop())) filter = eval("ImageFilter." + self.do_pop().upper())
image = self.do_pop() image = self.do_pop()
self.push(image.filter(filter)) self.push(image.filter(filter))
@ -314,7 +315,7 @@ class PILDriver:
Transpose the top image. Transpose the top image.
""" """
transpose = string.upper(self.do_pop()) transpose = self.do_pop().upper()
image = self.do_pop() image = self.do_pop()
self.push(image.transpose(transpose)) self.push(image.transpose(transpose))
@ -482,9 +483,9 @@ class PILDriver:
self.push(list[0]) self.push(list[0])
list = list[1:] list = list[1:]
if self.verbose: if self.verbose:
print "Stack: " + `self.stack` print("Stack: " + repr(self.stack))
top = self.top() top = self.top()
if type(top) != type(""): if not isinstance(top, str):
continue; continue;
funcname = "do_" + top funcname = "do_" + top
if not hasattr(self, funcname): if not hasattr(self, funcname):
@ -508,15 +509,15 @@ if __name__ == '__main__':
if len(sys.argv[1:]) > 0: if len(sys.argv[1:]) > 0:
driver.execute(sys.argv[1:]) driver.execute(sys.argv[1:])
else: else:
print "PILDriver says hello." print("PILDriver says hello.")
while 1: while True:
try: try:
line = raw_input('pildriver> '); line = raw_input('pildriver> ');
except EOFError: except EOFError:
print "\nPILDriver says goodbye." print("\nPILDriver says goodbye.")
break break
driver.execute(string.split(line)) driver.execute(line.split())
print driver.stack print(driver.stack)
# The following sets edit modes for GNU EMACS # The following sets edit modes for GNU EMACS
# Local Variables: # Local Variables:

View File

@ -17,25 +17,27 @@
# 0.4 2003-09-30 fl Expand wildcards on Windows; robustness tweaks # 0.4 2003-09-30 fl Expand wildcards on Windows; robustness tweaks
# #
from __future__ import print_function
import site import site
import getopt, glob, sys import getopt, glob, sys
from PIL import Image from PIL import Image
if len(sys.argv) == 1: if len(sys.argv) == 1:
print "PIL File 0.4/2003-09-30 -- identify image files" print("PIL File 0.4/2003-09-30 -- identify image files")
print "Usage: pilfile [option] files..." print("Usage: pilfile [option] files...")
print "Options:" print("Options:")
print " -f list supported file formats" print(" -f list supported file formats")
print " -i show associated info and tile data" print(" -i show associated info and tile data")
print " -v verify file headers" print(" -v verify file headers")
print " -q quiet, don't warn for unidentified/missing/broken files" print(" -q quiet, don't warn for unidentified/missing/broken files")
sys.exit(1) sys.exit(1)
try: try:
opt, args = getopt.getopt(sys.argv[1:], "fqivD") opt, args = getopt.getopt(sys.argv[1:], "fqivD")
except getopt.error, v: except getopt.error as v:
print v print(v)
sys.exit(1) sys.exit(1)
verbose = quiet = verify = 0 verbose = quiet = verify = 0
@ -43,11 +45,10 @@ verbose = quiet = verify = 0
for o, a in opt: for o, a in opt:
if o == "-f": if o == "-f":
Image.init() Image.init()
id = Image.ID[:] id = sorted(Image.ID)
id.sort() print("Supported formats:")
print "Supported formats:"
for i in id: for i in id:
print i, print(i, end=' ')
sys.exit(1) sys.exit(1)
elif o == "-i": elif o == "-i":
verbose = 1 verbose = 1
@ -73,22 +74,22 @@ def globfix(files):
for file in globfix(args): for file in globfix(args):
try: try:
im = Image.open(file) im = Image.open(file)
print "%s:" % file, im.format, "%dx%d" % im.size, im.mode, print("%s:" % file, im.format, "%dx%d" % im.size, im.mode, end=' ')
if verbose: if verbose:
print im.info, im.tile, print(im.info, im.tile, end=' ')
print print()
if verify: if verify:
try: try:
im.verify() im.verify()
except: except:
if not quiet: if not quiet:
print "failed to verify image", print("failed to verify image", end=' ')
print "(%s:%s)" % (sys.exc_type, sys.exc_value) print("(%s:%s)" % (sys.exc_info()[0], sys.exc_info()[1]))
except IOError, v: except IOError as v:
if not quiet: if not quiet:
print file, "failed:", v print(file, "failed:", v)
except: except:
import traceback import traceback
if not quiet: if not quiet:
print file, "failed:", "unexpected error" print(file, "failed:", "unexpected error")
traceback.print_exc(file=sys.stdout) traceback.print_exc(file=sys.stdout)

View File

@ -9,6 +9,8 @@
# 2002-03-10 fl use "from PIL import" # 2002-03-10 fl use "from PIL import"
# #
from __future__ import print_function
VERSION = "0.4" VERSION = "0.4"
import site import site
@ -19,12 +21,12 @@ from PIL import BdfFontFile
from PIL import PcfFontFile from PIL import PcfFontFile
if len(sys.argv) <= 1: if len(sys.argv) <= 1:
print "PILFONT", VERSION, "-- PIL font compiler." print("PILFONT", VERSION, "-- PIL font compiler.")
print print()
print "Usage: pilfont fontfiles..." print("Usage: pilfont fontfiles...")
print print()
print "Convert given font files to the PIL raster font format." print("Convert given font files to the PIL raster font format.")
print "This version of pilfont supports X BDF and PCF fonts." print("This version of pilfont supports X BDF and PCF fonts.")
sys.exit(1) sys.exit(1)
files = [] files = []
@ -33,7 +35,7 @@ for f in sys.argv[1:]:
for f in files: for f in files:
print f + "...", print(f + "...", end=' ')
try: try:
@ -48,7 +50,7 @@ for f in files:
p.save(f) p.save(f)
except (SyntaxError, IOError): except (SyntaxError, IOError):
print "failed" print("failed")
else: else:
print "OK" print("OK")

View File

@ -11,6 +11,8 @@
# 0.3 2003-05-06 fl Fixed a typo or two. # 0.3 2003-05-06 fl Fixed a typo or two.
# #
from __future__ import print_function
VERSION = "pilprint 0.3/2003-05-05" VERSION = "pilprint 0.3/2003-05-05"
from PIL import Image from PIL import Image
@ -29,18 +31,18 @@ def description(file, image):
import getopt, os, sys import getopt, os, sys
if len(sys.argv) == 1: if len(sys.argv) == 1:
print "PIL Print 0.2a1/96-10-04 -- print image files" print("PIL Print 0.2a1/96-10-04 -- print image files")
print "Usage: pilprint files..." print("Usage: pilprint files...")
print "Options:" print("Options:")
print " -c colour printer (default is monochrome)" print(" -c colour printer (default is monochrome)")
print " -p print via lpr (default is stdout)" print(" -p print via lpr (default is stdout)")
print " -P <printer> same as -p but use given printer" print(" -P <printer> same as -p but use given printer")
sys.exit(1) sys.exit(1)
try: try:
opt, argv = getopt.getopt(sys.argv[1:], "cdpP:") opt, argv = getopt.getopt(sys.argv[1:], "cdpP:")
except getopt.error, v: except getopt.error as v:
print v print(v)
sys.exit(1) sys.exit(1)
printer = None # print to stdout printer = None # print to stdout
@ -50,7 +52,7 @@ for o, a in opt:
if o == "-d": if o == "-d":
# debug: show available drivers # debug: show available drivers
Image.init() Image.init()
print Image.ID print(Image.ID)
sys.exit(1) sys.exit(1)
elif o == "-c": elif o == "-c":
# colour printer # colour printer
@ -89,5 +91,5 @@ for file in argv:
ps.end_document() ps.end_document()
except: except:
print "cannot print image", print("cannot print image", end=' ')
print "(%s:%s)" % (sys.exc_type, sys.exc_value) print("(%s:%s)" % (sys.exc_info()[0], sys.exc_info()[1]))

View File

@ -3,7 +3,13 @@
# $Id$ # $Id$
# #
from Tkinter import * from __future__ import print_function
try:
from tkinter import *
except ImportError:
from Tkinter import *
from PIL import Image, ImageTk from PIL import Image, ImageTk
import sys import sys
@ -36,7 +42,7 @@ class AppletDisplay:
class UI(Label): class UI(Label):
def __init__(self, master, im): def __init__(self, master, im):
if type(im) == type([]): if isinstance(im, list):
# list of images # list of images
self.im = im[1:] self.im = im[1:]
im = self.im[0] im = self.im[0]
@ -65,7 +71,7 @@ class UI(Label):
def next(self): def next(self):
if type(self.im) == type([]): if isinstance(self.im, list):
try: try:
im = self.im[0] im = self.im[0]
@ -98,7 +104,7 @@ class UI(Label):
if __name__ == "__main__": if __name__ == "__main__":
if not sys.argv[1:]: if not sys.argv[1:]:
print "Syntax: python player.py imagefile(s)" print("Syntax: python player.py imagefile(s)")
sys.exit(1) sys.exit(1)
filename = sys.argv[1] filename = sys.argv[1]
@ -108,7 +114,7 @@ if __name__ == "__main__":
if len(sys.argv) > 2: if len(sys.argv) > 2:
# list of images # list of images
print "loading..." print("loading...")
im = [] im = []
for filename in sys.argv[1:]: for filename in sys.argv[1:]:
im.append(Image.open(filename)) im.append(Image.open(filename))

View File

@ -6,7 +6,11 @@
# as a dynamically updated overlay # as a dynamically updated overlay
# #
from Tkinter import * try:
from tkinter import *
except ImportError:
from Tkinter import *
from PIL import Image, ImageTk from PIL import Image, ImageTk
import sys import sys

View File

@ -3,7 +3,13 @@
# $Id$ # $Id$
# #
from Tkinter import * from __future__ import print_function
try:
from tkinter import *
except ImportError:
from Tkinter import *
from PIL import Image, ImageTk from PIL import Image, ImageTk
# #
@ -31,7 +37,7 @@ if __name__ == "__main__":
import sys import sys
if not sys.argv[1:]: if not sys.argv[1:]:
print "Syntax: python viewer.py imagefile" print("Syntax: python viewer.py imagefile")
sys.exit(1) sys.exit(1)
filename = sys.argv[1] filename = sys.argv[1]

4
Tests/README.txt Normal file
View File

@ -0,0 +1,4 @@
Minimalistic PIL test framework.
Test scripts are named "test_xxx" and are supposed to output "ok".
That's it.

20
Tests/bench_get.py Normal file
View File

@ -0,0 +1,20 @@
import sys
sys.path.insert(0, ".")
import tester
import timeit
def bench(mode):
im = tester.lena(mode)
get = im.im.getpixel
xy = 50, 50 # position shouldn't really matter
t0 = timeit.default_timer()
for i in range(1000000):
get(xy)
print(mode, timeit.default_timer() - t0, "us")
bench("L")
bench("I")
bench("I;16")
bench("F")
bench("RGB")

Some files were not shown because too many files have changed in this diff Show More