Framework for image filters, alongwith an auto-trim filter

This commit is contained in:
Kovid Goyal 2013-12-05 17:45:53 +05:30
parent e80ce3f6d6
commit a7b7577fd1
5 changed files with 817 additions and 12 deletions

702
imgsrc/filter.svg Normal file
View File

@ -0,0 +1,702 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://web.resource.org/cc/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="128"
height="128"
id="svg1307"
sodipodi:version="0.32"
inkscape:version="0.45"
version="1.0"
sodipodi:docbase="/home/david/Progetti/sandbox"
sodipodi:docname="filter.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
sodipodi:modified="true">
<defs
id="defs1309">
<linearGradient
inkscape:collect="always"
id="linearGradient2897">
<stop
style="stop-color:black;stop-opacity:1;"
offset="0"
id="stop2899" />
<stop
style="stop-color:black;stop-opacity:0;"
offset="1"
id="stop2901" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient2884">
<stop
style="stop-color:black;stop-opacity:1;"
offset="0"
id="stop2886" />
<stop
style="stop-color:black;stop-opacity:0;"
offset="1"
id="stop2888" />
</linearGradient>
<linearGradient
id="linearGradient3054">
<stop
style="stop-color:black;stop-opacity:1;"
offset="0"
id="stop3056" />
<stop
id="stop3062"
offset="0.5714286"
style="stop-color:black;stop-opacity:1;" />
<stop
style="stop-color:black;stop-opacity:0;"
offset="1"
id="stop3058" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient3040">
<stop
style="stop-color:white;stop-opacity:1;"
offset="0"
id="stop3042" />
<stop
style="stop-color:white;stop-opacity:0;"
offset="1"
id="stop3044" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient3027">
<stop
style="stop-color:white;stop-opacity:1;"
offset="0"
id="stop3029" />
<stop
style="stop-color:white;stop-opacity:0;"
offset="1"
id="stop3031" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient3012">
<stop
style="stop-color:white;stop-opacity:1;"
offset="0"
id="stop3014" />
<stop
style="stop-color:white;stop-opacity:0;"
offset="1"
id="stop3016" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient2999">
<stop
style="stop-color:black;stop-opacity:1;"
offset="0"
id="stop3001" />
<stop
style="stop-color:black;stop-opacity:0;"
offset="1"
id="stop3003" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient2981">
<stop
style="stop-color:black;stop-opacity:1;"
offset="0"
id="stop2983" />
<stop
style="stop-color:black;stop-opacity:0;"
offset="1"
id="stop2985" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient2947">
<stop
style="stop-color:black;stop-opacity:1;"
offset="0"
id="stop2949" />
<stop
style="stop-color:black;stop-opacity:0;"
offset="1"
id="stop2951" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient2929">
<stop
style="stop-color:#bdbdbd;stop-opacity:1;"
offset="0"
id="stop2931" />
<stop
style="stop-color:#bdbdbd;stop-opacity:0;"
offset="1"
id="stop2933" />
</linearGradient>
<linearGradient
id="linearGradient2903">
<stop
style="stop-color:white;stop-opacity:0.53790611;"
offset="0"
id="stop2905" />
<stop
id="stop2911"
offset="0.21464799"
style="stop-color:white;stop-opacity:1;" />
<stop
style="stop-color:white;stop-opacity:0.41516244;"
offset="0.66342056"
id="stop2913" />
<stop
style="stop-color:white;stop-opacity:0;"
offset="1"
id="stop2907" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient3291">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop3293" />
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop3295" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3291"
id="radialGradient3297"
cx="63.912209"
cy="115.70919"
fx="63.912209"
fy="115.7093"
r="63.912209"
gradientTransform="matrix(1,0,0,0.197802,0,92.82166)"
gradientUnits="userSpaceOnUse" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3054"
id="radialGradient3060"
cx="63.816387"
cy="120.57538"
fx="63.816387"
fy="120.57538"
r="14.672465"
gradientTransform="matrix(1,0,0,0.289157,0,85.71021)"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2897"
id="linearGradient2904"
x1="67.25"
y1="72.375"
x2="65.25"
y2="17.625"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2981"
id="linearGradient2256"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.7646663,0,0,0.9871806,19.248865,2.1082198)"
x1="94.42218"
y1="30.355696"
x2="100.78125"
y2="35.359375" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2929"
id="linearGradient2258"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.7646663,0,0,0.9871796,19.248866,2.1082206)"
spreadMethod="reflect"
x1="55.826965"
y1="61.3554"
x2="121.36113"
y2="52.6054" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2903"
id="linearGradient2260"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.7646663,0,0,0.9871806,19.248865,2.1082198)"
x1="55.875"
y1="91.296875"
x2="70.71875"
y2="91.296875" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2947"
id="radialGradient2262"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8268423,0,0,0.1392194,15.358897,56.83334)"
cx="63.462833"
cy="66.417244"
fx="63.462833"
fy="66.417244"
r="13.788582" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2903"
id="radialGradient2264"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.5047306,-0.9375819,1.2433202,3.3256839,-79.061389,-69.19504)"
cx="51.78791"
cy="41.299831"
fx="51.78791"
fy="41.299831"
r="15.995545" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2947"
id="radialGradient2266"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8268423,0,0,0.1392194,15.358897,56.83334)"
cx="63.462833"
cy="66.417244"
fx="63.462833"
fy="66.417244"
r="13.788582" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2903"
id="radialGradient2268"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.5047306,-0.9375819,1.2433202,3.3256839,-79.061389,-69.19504)"
cx="52.715279"
cy="41.561275"
fx="52.715279"
fy="41.561275"
r="15.995545" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3012"
id="radialGradient2270"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.556928,-2.91845e-8,0,0.138799,37.13478,97.17706)"
cx="57.214077"
cy="124.00706"
fx="49.233025"
fy="124.00705"
r="11.383312" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2947"
id="radialGradient2272"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8268423,0,0,0.2437132,15.358897,49.893028)"
cx="63.462833"
cy="66.417244"
fx="63.462833"
fy="66.417244"
r="13.788582" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3012"
id="radialGradient2274"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-0.396982,-6.091903e-3,2.173148e-3,-0.138782,90.77277,126.4457)"
cx="76.055191"
cy="102.52346"
fx="70.111389"
fy="106.1347"
r="11.383312" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2903"
id="linearGradient2276"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.7646663,0,0,0.9871806,19.248865,2.1082198)"
x1="55.875"
y1="91.296875"
x2="70.71875"
y2="91.296875" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2999"
id="linearGradient2278"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.7646663,0,0,0.9871806,19.248865,2.1082198)"
x1="48.326965"
y1="241.35539"
x2="60.750298"
y2="67.1054" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3027"
id="linearGradient2280"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.7646663,0,0,0.9871806,19.248865,2.1082198)"
x1="26.516504"
y1="6.2892453"
x2="67.55307"
y2="6.2892451" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3040"
id="linearGradient2282"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.7646663,0,0,0.9871806,19.248865,2.1082198)"
x1="27.080584"
y1="-14.285192"
x2="59.768688"
y2="17.40625" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2884"
id="linearGradient2284"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8601654,0,0,0.9472313,14.250514,3.8818714)"
x1="48.648247"
y1="123.09119"
x2="63.212357"
y2="60.341194" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2884"
id="linearGradient2287"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.9384891,0,0,0.9797769,5.3602634,-0.1102297)"
x1="48.648247"
y1="123.09119"
x2="63.212357"
y2="60.341194" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3040"
id="linearGradient2290"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8342942,0,0,0.6237166,10.813747,4.9721139)"
x1="27.080584"
y1="-14.285192"
x2="59.768688"
y2="17.40625" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3027"
id="linearGradient2293"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8332988,-4.0741942e-2,4.3563196e-2,0.8910022,10.908193,1.2960712)"
x1="26.516504"
y1="6.2892453"
x2="67.55307"
y2="6.2892451" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2999"
id="linearGradient2297"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8342942,0,0,1.0210988,10.813747,-1.9448217)"
x1="48.326965"
y1="241.35539"
x2="60.750298"
y2="67.1054" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2903"
id="linearGradient2300"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8342942,0,0,1.0210988,10.813747,-1.9448217)"
x1="55.875"
y1="91.296875"
x2="70.71875"
y2="91.296875" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2947"
id="radialGradient2304"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.9021317,0,0,0.2520869,6.5695719,47.48181)"
cx="63.462833"
cy="66.417244"
fx="63.462833"
fy="66.417244"
r="13.788582" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2903"
id="radialGradient2308"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.6417463,-0.8079979,1.3565327,2.8660381,-96.448304,-52.309632)"
cx="52.715279"
cy="41.561275"
fx="52.715279"
fy="41.561275"
r="15.995545" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2947"
id="radialGradient2312"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.9021317,0,0,0.1440028,6.5695719,54.660582)"
cx="63.462833"
cy="66.417244"
fx="63.462833"
fy="66.417244"
r="13.788582" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2903"
id="radialGradient2315"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.6417463,-0.8125119,1.3565327,2.88205,-96.448304,-52.949828)"
cx="51.78791"
cy="41.299831"
fx="51.78791"
fy="41.299831"
r="15.995545" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2947"
id="radialGradient2318"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.9021317,0,0,0.1440028,6.5695719,54.660582)"
cx="63.462833"
cy="66.417244"
fx="63.462833"
fy="66.417244"
r="13.788582" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2903"
id="linearGradient2321"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8342942,0,0,1.0210988,10.813747,-1.9448217)"
x1="55.875"
y1="91.296875"
x2="70.71875"
y2="91.296875" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2929"
id="linearGradient2325"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8342942,0,0,1.0210978,10.813748,-1.9448209)"
spreadMethod="reflect"
x1="55.826965"
y1="61.3554"
x2="121.36113"
y2="52.6054" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2981"
id="linearGradient2328"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8342942,0,0,0.8975001,10.813747,5.9409483)"
x1="94.42218"
y1="30.355696"
x2="100.78125"
y2="35.359375" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3012"
id="radialGradient2330"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-0.396982,-6.091903e-3,2.173148e-3,-0.138782,90.77277,126.4457)"
cx="76.055191"
cy="102.52346"
fx="70.111389"
fy="106.1347"
r="11.383312" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3012"
id="radialGradient2332"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.556928,-2.91845e-8,0,0.138799,37.13478,97.17706)"
cx="57.214077"
cy="124.00706"
fx="49.233025"
fy="124.00705"
r="11.383312" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="90.481778"
inkscape:cy="106.17217"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
guidetolerance="0.1px"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1018"
inkscape:window-height="694"
inkscape:window-x="0"
inkscape:window-y="0"
gridspacingx="8px"
gridspacingy="8px"
gridempspacing="0" />
<metadata
id="metadata1312">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<cc:license
rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
<dc:contributor>
<cc:Agent>
<dc:title>Oxygen team</dc:title>
</cc:Agent>
</dc:contributor>
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/LGPL/2.1/">
<cc:permits
rdf:resource="http://web.resource.org/cc/Reproduction" />
<cc:permits
rdf:resource="http://web.resource.org/cc/Distribution" />
<cc:requires
rdf:resource="http://web.resource.org/cc/Notice" />
<cc:permits
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
<cc:requires
rdf:resource="http://web.resource.org/cc/ShareAlike" />
<cc:requires
rdf:resource="http://web.resource.org/cc/SourceCode" />
</cc:License>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<path
sodipodi:type="arc"
style="opacity:0.38139535;fill:url(#radialGradient3297);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1"
id="path3289"
sodipodi:cx="63.912209"
sodipodi:cy="115.70919"
sodipodi:rx="63.912209"
sodipodi:ry="12.641975"
d="M 127.82442 115.70919 A 63.912209 12.641975 0 1 1 0,115.70919 A 63.912209 12.641975 0 1 1 127.82442 115.70919 z"
transform="matrix(0.6102121,0,0,0.416667,24.999997,74.520305)" />
<path
sodipodi:type="arc"
style="opacity:0.41393445;fill:url(#radialGradient3060);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.69499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1"
id="path3052"
sodipodi:cx="63.816387"
sodipodi:cy="120.57538"
sodipodi:rx="14.672465"
sodipodi:ry="4.2426405"
d="M 78.488853 120.57538 A 14.672465 4.2426405 0 1 1 49.143922,120.57538 A 14.672465 4.2426405 0 1 1 78.488853 120.57538 z"
transform="matrix(0.9702784,0,0,0.9820563,2.080338,1.4216782)" />
<path
sodipodi:nodetypes="ccc"
id="path2276"
d="M 53.349575,3.2933654 L 53.349575,0.49920781 L 53.349575,3.2933654 z "
style="fill:#ffffff;fill-opacity:0.75688076;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1" />
<path
style="opacity:0.41999996;fill:url(#linearGradient2328);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999995;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:0.31707315"
d="M 102.76856,18.730326 C 92.024693,33.884991 79.448035,48.048049 72.117251,63.202716 L 73.288437,63.163051 L 108.97363,16.991419 C 106.68706,17.962299 104.63818,18.507029 102.76856,18.730326 z "
id="path2978"
sodipodi:nodetypes="ccccc" />
<path
style="fill:url(#linearGradient2325);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.18459648;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1"
d="M 64.07844,0.4721712 C 37.58961,0.4721712 16.092299,5.7132236 16.092299,11.718435 C 16.092299,24.096447 53.39715,62.252891 53.39715,62.252891 C 53.55139,62.473797 53.73502,62.839504 53.72186,63.265829 L 53.72186,117.72963 C 53.72186,119.07259 55.58016,119.9077 62.88947,119.9077 C 70.04254,119.9077 74.43501,119.26405 74.43501,117.72963 C 74.43501,117.72109 74.43573,117.70417 74.43501,117.69564 L 74.3799,63.265838 C 74.3799,63.015828 74.41383,62.731875 74.53013,62.518927 C 74.53013,62.518927 111.90814,23.750824 111.90814,11.251924 C 111.90814,6.9947672 90.56726,0.4721713 64.07844,0.4721712 z "
id="path1969"
sodipodi:nodetypes="cccccsscccsc" />
<path
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999995;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:0.31707315"
d="M 64.077815,9.398298 C 44.544101,9.398298 28.36902,13.356343 25.791837,18.484968 C 34.209824,21.787518 48.209741,24 64.077815,24 C 79.928558,24 93.917453,21.833952 102.33849,18.537495 C 99.811032,13.39477 83.64834,9.398298 64.077815,9.398298 z "
id="path2880" />
<path
style="opacity:0.61475375;fill:url(#linearGradient2321);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999995;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:0.31707315"
d="M 57.429913,63.660786 L 57.429913,119.26952 C 59.214996,119.64495 61.433104,119.9077 64.07819,119.9077 C 66.27883,119.9077 68.183409,119.72504 69.813958,119.46096 L 69.813958,63.660786 C 65.685944,64.582695 61.557928,65.119361 57.429913,63.660786 z "
id="path2900"
sodipodi:nodetypes="ccsccc" />
<path
style="opacity:0.11000001;fill:url(#radialGradient2318);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1"
d="M 54.05364,62.480138 C 54.050373,62.503 54.030261,62.520928 54.030261,62.543957 C 54.030261,63.764542 58.646106,65.770396 64.340254,65.770396 C 70.034397,65.770396 74.673621,63.764543 74.673625,62.543957 C 74.673625,62.521598 74.653326,62.50234 74.650245,62.480138 C 72.379359,62.994783 68.608504,63.309781 64.340254,63.309781 C 60.073012,63.30978 56.3247,62.994578 54.05364,62.480138 z "
id="path2945"
sodipodi:nodetypes="cssscsc" />
<path
sodipodi:nodetypes="ccccc"
id="path2915"
d="M 57.429913,63.807359 L 44.598832,24 C 53.424982,25.007037 62.430518,24.599508 71.288795,24.160406 L 69.813958,63.807359 C 65.685944,64.57975 61.557928,65.029378 57.429913,63.807359 z "
style="opacity:0.75819672;fill:url(#radialGradient2315);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999995;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:0.31707315" />
<path
sodipodi:nodetypes="cssscsc"
id="path2962"
d="M 54.05364,62.480138 C 54.050373,62.503 54.030261,62.520928 54.030261,62.543957 C 54.030261,63.764542 58.646106,64.958119 64.340254,64.958119 C 70.034397,64.958119 74.673621,63.764543 74.673625,62.543957 C 74.673625,62.521598 74.653326,62.50234 74.650245,62.480138 C 72.379359,62.994783 68.54238,63.8513 64.274128,63.8513 C 60.006886,63.851299 56.3247,62.994578 54.05364,62.480138 z "
style="opacity:0.11000001;fill:url(#radialGradient2312);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1" />
<path
sodipodi:type="arc"
style="fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#5b5b5b;stroke-width:0.19620273;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1"
id="path2871"
sodipodi:cx="68.053238"
sodipodi:cy="112.83906"
sodipodi:rx="11.285211"
sodipodi:ry="1.4818963"
d="M 79.338449 112.83906 A 11.285211 1.4818963 0 1 1 56.768027,112.83906 A 11.285211 1.4818963 0 1 1 79.338449 112.83906 z"
transform="matrix(4.2019807,0,0,7.7206883,-221.93924,-859.19522)" />
<path
style="opacity:0.75819672;fill:url(#radialGradient2308);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999995;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:0.31707315"
d="M 56.729366,63.68609 L 41.887377,24 C 50.713529,25.001442 64.724826,24.808862 73.583104,24.3722 L 70.367024,63.798885 C 66.239006,64.566985 60.857381,64.90132 56.729366,63.68609 z "
id="path2939"
sodipodi:nodetypes="ccccc" />
<path
transform="matrix(4.2043803,0,0,7.832456,-222.10254,-871.80695)"
d="M 79.338449 112.83906 A 11.285211 1.4818963 0 1 1 56.768027,112.83906 A 11.285211 1.4818963 0 1 1 79.338449 112.83906 z"
sodipodi:ry="1.4818963"
sodipodi:rx="11.285211"
sodipodi:cy="112.83906"
sodipodi:cx="68.053238"
id="path3010"
style="fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#radialGradient2332);stroke-width:0.13700832;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1"
sodipodi:type="arc" />
<path
style="opacity:0.11000001;fill:url(#radialGradient2304);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1"
d="M 54.05364,62.480138 C 54.050373,62.503 54.030261,62.520928 54.030261,62.543957 C 54.030261,63.764542 58.679169,66.672928 64.373314,66.672928 C 70.067458,66.672928 74.673621,63.764543 74.673625,62.543957 C 74.673625,62.521598 74.653326,62.50234 74.650245,62.480138 C 72.379359,62.994783 68.344005,64.076933 64.075754,64.076933 C 59.80851,64.076932 56.3247,62.994578 54.05364,62.480138 z "
id="path2964"
sodipodi:nodetypes="cssscsc" />
<path
sodipodi:nodetypes="ccsccc"
id="path2943"
d="M 56.752048,63.49897 L 57.429913,119.26952 C 59.214996,119.64495 61.433104,119.9077 64.07819,119.9077 C 66.27883,119.9077 68.183409,119.72504 69.813958,119.46096 L 70.283249,63.660786 C 66.155234,64.582695 60.880065,64.957546 56.752048,63.49897 z "
style="opacity:0.61475375;fill:url(#linearGradient2300);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999995;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:0.31707315" />
<path
style="opacity:0.21311478;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:4;stroke-opacity:1"
d="M 72.189405,63.195363 L 73.23227,63.195363 L 73.23227,118.84109 L 72.15253,119.23497 L 72.189405,63.195363 z "
id="rect3007"
sodipodi:nodetypes="ccccc" />
<path
style="opacity:0.83606561;fill:url(#linearGradient2293);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.69499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:4;stroke-opacity:1"
d="M 33.561894,4.0688722 C 38.714737,3.0721977 43.838836,2.2854781 48.91922,1.8181091 L 49.037348,8.8932006 C 44.819109,9.1859388 41.106601,10.362191 37.109709,11.168653 L 33.561894,4.0688722 z "
id="rect3024"
sodipodi:nodetypes="ccccc" />
<path
style="opacity:0.83606561;fill:url(#linearGradient2290);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.69499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1"
d="M 45.279272,11.288602 C 40.829452,11.474899 40.007663,11.54473 36.59864,11.871979 C 39.812937,13.236 43.503323,14.352439 46.584092,15.536315 C 50.68162,15.702374 55.063348,15.785167 59.646005,15.828683 C 56.702723,14.361914 53.045552,10.674121 48.669828,10.129129 C 45.59708,9.7464214 45.346835,11.317702 45.279272,11.288602 z "
id="path3035"
sodipodi:nodetypes="ccccsc" />
<path
sodipodi:nodetypes="ccccc"
id="path2882"
d="M 53.730639,62.885731 L 53.714243,62.870422 L 53.875545,118.19758 C 54.023651,118.79808 54.525843,118.88716 54.955285,119.08134 C 55.694913,96.275115 54.450528,80.511284 53.730639,62.885731 z "
style="opacity:0.53278689;fill:url(#linearGradient2287);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:4;stroke-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 29 KiB

BIN
resources/images/filter.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@ -11,10 +11,12 @@ from functools import wraps
from PyQt4.Qt import (
QWidget, QPainter, QColor, QApplication, Qt, QPixmap, QRectF, QMatrix,
QPointF, QPen, pyqtSignal, QUndoCommand, QUndoStack, QIcon, QImage)
QPointF, QPen, pyqtSignal, QUndoCommand, QUndoStack, QIcon, QImage, QByteArray)
from calibre import fit_image
from calibre.gui2 import error_dialog, pixmap_to_data
from calibre.utils.config_base import tweaks
from calibre.utils.magick import Image
from calibre.utils.magick.draw import identify_data
def painter(func):
@ -50,8 +52,10 @@ class SelectionState(object):
class Command(QUndoCommand):
def __init__(self, text, canvas):
QUndoCommand.__init__(self, text)
TEXT = ''
def __init__(self, canvas):
QUndoCommand.__init__(self, self.TEXT)
self.canvas_ref = weakref.ref(canvas)
self.before_image = i = canvas.current_image
if i is None:
@ -76,12 +80,55 @@ def get_selection_rect(img, sr, target):
bottom_border = (abs(target.bottom() - sr.bottom())/target.height()) * img.height()
return left_border, top_border, img.width() - left_border - right_border, img.height() - top_border - bottom_border
_qimage_pixel_map = None
def get_pixel_map():
' Get the order of pixels in QImage (RGBA or BGRA usually) '
global _qimage_pixel_map
if _qimage_pixel_map is None:
i = QImage(1, 1, QImage.Format_ARGB32)
i.fill(QColor(0, 1, 2, 3))
raw = bytearray(i.constBits().asstring(4))
_qimage_pixel_map = {c:raw.index(x) for c, x in zip('RGBA', b'\x00\x01\x02\x03')}
_qimage_pixel_map = ''.join(sorted(_qimage_pixel_map, key=_qimage_pixel_map.get))
return _qimage_pixel_map
def qimage_to_magick(img):
fmt = get_pixel_map()
if not img.hasAlphaChannel():
if img.format() != img.Format_RGB32:
img = QImage(img)
img.setFormat(QImage.Format_RGB32)
fmt = fmt.replace('A', 'P')
else:
if img.format() != img.Format_ARGB32:
img = QImage(img)
img.setFormat(img.Format_ARGB32)
raw = img.constBits().ascapsule()
ans = Image()
ans.constitute(img.width(), img.height(), fmt, raw)
return ans
def magick_to_qimage(img):
fmt = get_pixel_map()
# ImageMagick can output only output raw data in some formats that can be
# read into QImage directly, if the QImage format is not one of those, use
# PNG
if fmt in {'RGBA', 'BGRA'}:
w, h = img.size
img.depth = 8 # QImage expects 8bpp
raw = img.export(fmt)
i = QImage(raw, w, h, QImage.Format_ARGB32)
del raw # According to the documentation, raw is supposed to not be deleted, but it works, so make it explicit
return i
else:
raw = img.export('PNG')
return QImage.fromData(QByteArray(raw), 'PNG')
class Trim(Command):
''' Remove the areas of the image outside the current selection. '''
def __init__(self, canvas):
Command.__init__(self, _('Trim image'), canvas)
TEXT = _('Trim image')
def __call__(self, canvas):
img = canvas.current_image
@ -89,10 +136,20 @@ class Trim(Command):
sr = canvas.selection_state.rect
return img.copy(*get_selection_rect(img, sr, target))
class AutoTrim(Trim):
''' Auto trim borders from the image '''
TEXT = _('Auto-trim image')
def __call__(self, canvas):
img = canvas.current_image
i = qimage_to_magick(img)
i.trim(tweaks['cover_trim_fuzz_value'])
return magick_to_qimage(i)
class Rotate(Command):
def __init__(self, canvas):
Command.__init__(self, _('Rotate image'), canvas)
TEXT = _('Rotate image')
def __call__(self, canvas):
img = canvas.current_image
@ -102,9 +159,11 @@ class Rotate(Command):
class Scale(Command):
TEXT = _('Resize image')
def __init__(self, width, height, canvas):
self.width, self.height = width, height
Command.__init__(self, _('Resize image'), canvas)
Command.__init__(self, canvas)
def __call__(self, canvas):
img = canvas.current_image
@ -247,6 +306,11 @@ class Canvas(QWidget):
self.undo_stack.push(Trim(self))
return True
@imageop
def autotrim_image(self):
self.undo_stack.push(AutoTrim(self))
return True
@imageop
def rotate_image(self):
self.undo_stack.push(Rotate(self))

View File

@ -11,7 +11,7 @@ from functools import partial
from PyQt4.Qt import (
QMainWindow, Qt, QApplication, pyqtSignal, QLabel, QIcon, QFormLayout,
QDialog, QSpinBox, QCheckBox, QDialogButtonBox)
QDialog, QSpinBox, QCheckBox, QDialogButtonBox, QToolButton, QMenu)
from calibre.gui2 import error_dialog
from calibre.gui2.tweak_book import actions
@ -200,7 +200,7 @@ class Editor(QMainWindow):
self.copy_available_state_changed.emit(self.copy_available)
self.data_changed.emit(self)
self.modification_state_changed.emit(True)
self.fmt_label.setText((self.canvas.original_image_format or '').upper())
self.fmt_label.setText(' ' + (self.canvas.original_image_format or '').upper())
im = self.canvas.current_image
self.size_label.setText('{0} x {1}{2}'.format(im.width(), im.height(), ' px'))
@ -229,7 +229,7 @@ class Editor(QMainWindow):
try:
ac = actions['editor-%s' % x]
except KeyError:
b.addAction(x, getattr(self.canvas, x))
setattr(self, 'action_' + x, b.addAction(x, getattr(self.canvas, x)))
else:
setattr(self, 'action_' + x, b.addAction(ac.icon(), x, getattr(self, x)))
self.update_clipboard_actions()
@ -238,6 +238,12 @@ class Editor(QMainWindow):
self.action_trim = ac = b.addAction(QIcon(I('trim.png')), _('Trim image'), self.canvas.trim_image)
self.action_rotate = ac = b.addAction(QIcon(I('rotate-right.png')), _('Rotate image'), self.canvas.rotate_image)
self.action_resize = ac = b.addAction(QIcon(I('resize.png')), _('Resize image'), self.resize_image)
b.addSeparator()
self.action_filters = ac = b.addAction(QIcon(I('filter.png')), _('Image filters'))
b.widgetForAction(ac).setPopupMode(QToolButton.InstantPopup)
self.filters_menu = m = QMenu()
ac.setMenu(m)
m.addAction(_('Auto-trim image'), self.canvas.autotrim_image)
self.info_bar = b = self.addToolBar(_('Image information bar'))
self.fmt_label = QLabel('')

View File

@ -537,6 +537,35 @@ magick_Image_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return (PyObject *)self;
}
// Image.constitute {{{
static PyObject *
magick_Image_constitute(magick_Image *self, PyObject *args) {
const char *map;
Py_ssize_t width, height;
PyObject *capsule;
MagickBooleanType res;
void *data;
NULL_CHECK(NULL)
if (!PyArg_ParseTuple(args, "iisO", &width, &height, &map, &capsule)) return NULL;
if (!PyCapsule_CheckExact(capsule)) {
PyErr_SetString(PyExc_TypeError, "data is not a capsule object");
return NULL;
}
data = PyCapsule_GetPointer(capsule, PyCapsule_GetName(capsule));
if (data == NULL) return NULL;
res = MagickConstituteImage(self->wand, width, height, map, CharPixel, data);
if (!res)
return magick_set_exception(self->wand);
Py_RETURN_NONE;
}
// }}}
// Image.load {{{
static PyObject *
@ -1296,6 +1325,10 @@ static PyMethodDef magick_Image_methods[] = {
"Identify an image from a byte buffer (string)"
},
{"constitute", (PyCFunction)magick_Image_constitute, METH_VARARGS,
"constitute(width, height, map, data) -> Create an image from raw (A)RGB data. map should be 'ARGB' or 'PRGB' or whatever is needed for data. data must be a PyCapsule object."
},
{"load", (PyCFunction)magick_Image_load, METH_VARARGS,
"Load an image from a byte buffer (string)"
},